From efaf9311b332e49dc643de5237b73b1613e627cc Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 30 Apr 2025 17:38:16 +0100
Subject: [PATCH 001/140] Extract population business logic from PopulationTask
---
src/world/generator/PopulationTask.php | 40 +++----------
src/world/generator/PopulationUtils.php | 74 +++++++++++++++++++++++++
2 files changed, 83 insertions(+), 31 deletions(-)
create mode 100644 src/world/generator/PopulationUtils.php
diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php
index bad134324..a8366a306 100644
--- a/src/world/generator/PopulationTask.php
+++ b/src/world/generator/PopulationTask.php
@@ -27,8 +27,6 @@ use pocketmine\scheduler\AsyncTask;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\FastChunkSerializer;
-use pocketmine\world\SimpleChunkManager;
-use pocketmine\world\World;
use function array_map;
use function igbinary_serialize;
use function igbinary_unserialize;
@@ -71,8 +69,6 @@ class PopulationTask extends AsyncTask{
if($context === null){
throw new AssumptionFailedError("Generator context should have been initialized before any PopulationTask execution");
}
- $generator = $context->getGenerator();
- $manager = new SimpleChunkManager($context->getWorldMinY(), $context->getWorldMaxY());
$chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null;
@@ -93,21 +89,15 @@ class PopulationTask extends AsyncTask{
$serialChunks
);
- self::setOrGenerateChunk($manager, $generator, $this->chunkX, $this->chunkZ, $chunk);
-
- $resultChunks = []; //this is just to keep phpstan's type inference happy
- foreach($chunks as $relativeChunkHash => $c){
- World::getXZ($relativeChunkHash, $relativeX, $relativeZ);
- $resultChunks[$relativeChunkHash] = self::setOrGenerateChunk($manager, $generator, $this->chunkX + $relativeX, $this->chunkZ + $relativeZ, $c);
- }
- $chunks = $resultChunks;
-
- $generator->populateChunk($manager, $this->chunkX, $this->chunkZ);
- $chunk = $manager->getChunk($this->chunkX, $this->chunkZ);
- if($chunk === null){
- throw new AssumptionFailedError("We just generated this chunk, so it must exist");
- }
- $chunk->setPopulated();
+ [$chunk, $chunks] = PopulationUtils::populateChunkWithAdjacents(
+ $context->getWorldMinY(),
+ $context->getWorldMaxY(),
+ $context->getGenerator(),
+ $this->chunkX,
+ $this->chunkZ,
+ $chunk,
+ $chunks
+ );
$this->chunk = FastChunkSerializer::serializeTerrain($chunk);
@@ -118,18 +108,6 @@ class PopulationTask extends AsyncTask{
$this->adjacentChunks = igbinary_serialize($serialChunks) ?? throw new AssumptionFailedError("igbinary_serialize() returned null");
}
- private static function setOrGenerateChunk(SimpleChunkManager $manager, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $chunk) : Chunk{
- $manager->setChunk($chunkX, $chunkZ, $chunk ?? new Chunk([], false));
- if($chunk === null){
- $generator->generateChunk($manager, $chunkX, $chunkZ);
- $chunk = $manager->getChunk($chunkX, $chunkZ);
- if($chunk === null){
- throw new AssumptionFailedError("We just set this chunk, so it must exist");
- }
- }
- return $chunk;
- }
-
public function onCompletion() : void{
/**
* @var \Closure $onCompletion
diff --git a/src/world/generator/PopulationUtils.php b/src/world/generator/PopulationUtils.php
new file mode 100644
index 000000000..84840ee3e
--- /dev/null
+++ b/src/world/generator/PopulationUtils.php
@@ -0,0 +1,74 @@
+setChunk($chunkX, $chunkZ, $chunk ?? new Chunk([], false));
+ if($chunk === null){
+ $generator->generateChunk($manager, $chunkX, $chunkZ);
+ $chunk = $manager->getChunk($chunkX, $chunkZ);
+ if($chunk === null){
+ throw new AssumptionFailedError("We just set this chunk, so it must exist");
+ }
+ }
+ return $chunk;
+ }
+
+ /**
+ * @param Chunk[]|null[] $adjacentChunks
+ * @phpstan-param array $adjacentChunks
+ *
+ * @return Chunk[]|Chunk[][]
+ * @phpstan-return array{Chunk, array}
+ */
+ public static function populateChunkWithAdjacents(int $minY, int $maxY, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks) : array{
+ $manager = new SimpleChunkManager($minY, $maxY);
+ self::setOrGenerateChunk($manager, $generator, $chunkX, $chunkZ, $centerChunk);
+
+ $resultChunks = []; //this is just to keep phpstan's type inference happy
+ foreach($adjacentChunks as $relativeChunkHash => $c){
+ World::getXZ($relativeChunkHash, $relativeX, $relativeZ);
+ $resultChunks[$relativeChunkHash] = self::setOrGenerateChunk($manager, $generator, $chunkX + $relativeX, $chunkZ + $relativeZ, $c);
+ }
+ $adjacentChunks = $resultChunks;
+
+ $generator->populateChunk($manager, $chunkX, $chunkZ);
+ $centerChunk = $manager->getChunk($chunkX, $chunkZ);
+ if($centerChunk === null){
+ throw new AssumptionFailedError("We just generated this chunk, so it must exist");
+ }
+ $centerChunk->setPopulated();
+ return [$centerChunk, $adjacentChunks];
+ }
+}
From 6f3506360e8777dbe7b0e0eb05f717678e755658 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 1 May 2025 08:30:26 +0000
Subject: [PATCH 002/140] Bump the github-actions group with 3 updates (#6683)
---
.github/workflows/build-docker-image.yml | 8 ++++----
.github/workflows/discord-release-notify.yml | 2 +-
.github/workflows/draft-release-pr-check.yml | 2 +-
.github/workflows/draft-release.yml | 4 ++--
.github/workflows/main.yml | 2 +-
.github/workflows/team-pr-auto-approve.yml | 2 +-
6 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
index 83d568878..dc282ab71 100644
--- a/.github/workflows/build-docker-image.yml
+++ b/.github/workflows/build-docker-image.yml
@@ -53,7 +53,7 @@ jobs:
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag
- uses: docker/build-push-action@v6.15.0
+ uses: docker/build-push-action@v6.16.0
with:
push: true
context: ./pocketmine-mp
@@ -66,7 +66,7 @@ jobs:
- name: Build image for major tag
if: steps.channel.outputs.CHANNEL == 'stable'
- uses: docker/build-push-action@v6.15.0
+ uses: docker/build-push-action@v6.16.0
with:
push: true
context: ./pocketmine-mp
@@ -79,7 +79,7 @@ jobs:
- name: Build image for minor tag
if: steps.channel.outputs.CHANNEL == 'stable'
- uses: docker/build-push-action@v6.15.0
+ uses: docker/build-push-action@v6.16.0
with:
push: true
context: ./pocketmine-mp
@@ -92,7 +92,7 @@ jobs:
- name: Build image for latest tag
if: steps.channel.outputs.CHANNEL == 'stable'
- uses: docker/build-push-action@v6.15.0
+ uses: docker/build-push-action@v6.16.0
with:
push: true
context: ./pocketmine-mp
diff --git a/.github/workflows/discord-release-notify.yml b/.github/workflows/discord-release-notify.yml
index fde5e3099..93b2978aa 100644
--- a/.github/workflows/discord-release-notify.yml
+++ b/.github/workflows/discord-release-notify.yml
@@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP and tools
- uses: shivammathur/setup-php@2.32.0
+ uses: shivammathur/setup-php@2.33.0
with:
php-version: 8.2
diff --git a/.github/workflows/draft-release-pr-check.yml b/.github/workflows/draft-release-pr-check.yml
index 303f61ccf..20b2200e6 100644
--- a/.github/workflows/draft-release-pr-check.yml
+++ b/.github/workflows/draft-release-pr-check.yml
@@ -49,7 +49,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP
- uses: shivammathur/setup-php@2.32.0
+ uses: shivammathur/setup-php@2.33.0
with:
php-version: 8.2
diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml
index 02cdeec6f..fa20d1912 100644
--- a/.github/workflows/draft-release.yml
+++ b/.github/workflows/draft-release.yml
@@ -59,7 +59,7 @@ jobs:
steps:
- name: Generate access token
id: generate-token
- uses: actions/create-github-app-token@v1
+ uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
@@ -87,7 +87,7 @@ jobs:
submodules: true
- name: Setup PHP
- uses: shivammathur/setup-php@2.32.0
+ uses: shivammathur/setup-php@2.33.0
with:
php-version: ${{ env.PHP_VERSION }}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 051a3a790..cfe97aa7e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP and tools
- uses: shivammathur/setup-php@2.32.0
+ uses: shivammathur/setup-php@2.33.0
with:
php-version: 8.2
tools: php-cs-fixer:3.49
diff --git a/.github/workflows/team-pr-auto-approve.yml b/.github/workflows/team-pr-auto-approve.yml
index 0c2fdd81c..cc5c47139 100644
--- a/.github/workflows/team-pr-auto-approve.yml
+++ b/.github/workflows/team-pr-auto-approve.yml
@@ -22,7 +22,7 @@ jobs:
steps:
- name: Generate access token
id: generate-token
- uses: actions/create-github-app-token@v1
+ uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
From 6bf9a305de7d722d15736f379cac944a5310ebee Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 3 May 2025 19:23:50 +0100
Subject: [PATCH 003/140] Rename confusing PHPStan rule name it never occurred
to me that this was misleading until I read some Devin documentation, noticed
that Devin misunderstood was the class was for, and then realized actually
Devin understood correctly, and it was the name of the class that was wrong.
Funny how that happens...
---
phpstan.neon.dist | 2 +-
tests/phpstan/configs/phpstan-bugs.neon | 2 +-
...fStringRule.php => UnsafeForeachArrayWithStringKeysRule.php} | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
rename tests/phpstan/rules/{UnsafeForeachArrayOfStringRule.php => UnsafeForeachArrayWithStringKeysRule.php} (98%)
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index 13f35c121..391f0f54c 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -15,7 +15,7 @@ rules:
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
- pocketmine\phpstan\rules\ExplodeLimitRule
- - pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
+ - pocketmine\phpstan\rules\UnsafeForeachArrayWithStringKeysRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
parameters:
diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon
index aeb3fae29..cb92bf968 100644
--- a/tests/phpstan/configs/phpstan-bugs.neon
+++ b/tests/phpstan/configs/phpstan-bugs.neon
@@ -256,5 +256,5 @@ parameters:
message: '#^Strict comparison using \=\=\= between 0 and 0 will always evaluate to true\.$#'
identifier: identical.alwaysTrue
count: 1
- path: ../rules/UnsafeForeachArrayOfStringRule.php
+ path: ../rules/UnsafeForeachArrayWithStringKeysRule.php
diff --git a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php b/tests/phpstan/rules/UnsafeForeachArrayWithStringKeysRule.php
similarity index 98%
rename from tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php
rename to tests/phpstan/rules/UnsafeForeachArrayWithStringKeysRule.php
index 34056131b..83f47f092 100644
--- a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php
+++ b/tests/phpstan/rules/UnsafeForeachArrayWithStringKeysRule.php
@@ -41,7 +41,7 @@ use function sprintf;
/**
* @implements Rule
*/
-final class UnsafeForeachArrayOfStringRule implements Rule{
+final class UnsafeForeachArrayWithStringKeysRule implements Rule{
public function getNodeType() : string{
return Foreach_::class;
From 2a42e2c75d1c1b92d17559833899ce35940da269 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 4 May 2025 16:41:40 +0100
Subject: [PATCH 004/140] Drop PluginLoader from Plugin, expose path instead we
already had this anyway, and it's already being reflected into. Instead of
DevTools checking for FolderPluginLoader instances, it could just check if
the file is a directory instead.
---
src/crash/CrashDump.php | 4 +---
src/plugin/Plugin.php | 4 ++--
src/plugin/PluginBase.php | 7 +------
src/plugin/PluginManager.php | 2 +-
4 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php
index 49a587c34..df7c9199d 100644
--- a/src/crash/CrashDump.php
+++ b/src/crash/CrashDump.php
@@ -259,10 +259,8 @@ class CrashDump{
}
if(file_exists($filePath)){
- $reflection = new \ReflectionClass(PluginBase::class);
- $file = $reflection->getProperty("file");
foreach($this->server->getPluginManager()->getPlugins() as $plugin){
- $filePath = Filesystem::cleanPath($file->getValue($plugin));
+ $filePath = Filesystem::cleanPath($plugin->getFile());
if(str_starts_with($frameCleanPath, $filePath)){
$this->data->plugin = $plugin->getName();
break;
diff --git a/src/plugin/Plugin.php b/src/plugin/Plugin.php
index ae64d443b..b71e3f5fb 100644
--- a/src/plugin/Plugin.php
+++ b/src/plugin/Plugin.php
@@ -34,7 +34,7 @@ use pocketmine\Server;
*/
interface Plugin{
- public function __construct(PluginLoader $loader, Server $server, PluginDescription $description, string $dataFolder, string $file, string $resourceFolder);
+ public function __construct(Server $server, PluginDescription $description, string $dataFolder, string $file, string $resourceFolder);
public function isEnabled() : bool;
@@ -59,7 +59,7 @@ interface Plugin{
public function getLogger() : \AttachableLogger;
- public function getPluginLoader() : PluginLoader;
+ public function getFile() : string;
public function getScheduler() : TaskScheduler;
diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php
index a32339e84..727e93591 100644
--- a/src/plugin/PluginBase.php
+++ b/src/plugin/PluginBase.php
@@ -59,7 +59,6 @@ abstract class PluginBase implements Plugin, CommandExecutor{
private TaskScheduler $scheduler;
public function __construct(
- private PluginLoader $loader,
private Server $server,
private PluginDescription $description,
private string $dataFolder,
@@ -311,14 +310,10 @@ abstract class PluginBase implements Plugin, CommandExecutor{
return $this->description->getFullName();
}
- protected function getFile() : string{
+ public function getFile() : string{
return $this->file;
}
- public function getPluginLoader() : PluginLoader{
- return $this->loader;
- }
-
public function getScheduler() : TaskScheduler{
return $this->scheduler;
}
diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php
index 1a74b64e7..3750af3ef 100644
--- a/src/plugin/PluginManager.php
+++ b/src/plugin/PluginManager.php
@@ -220,7 +220,7 @@ class PluginManager{
* @var Plugin $plugin
* @see Plugin::__construct()
*/
- $plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $prefixed, $prefixed . "/resources/");
+ $plugin = new $mainClass($this->server, $description, $dataFolder, $prefixed, $prefixed . "/resources/");
$this->plugins[$plugin->getDescription()->getName()] = $plugin;
return $plugin;
From 912a5d6ad0cc8a0cbe407557bd483234b17af7a6 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 4 May 2025 16:45:25 +0100
Subject: [PATCH 005/140] Remove TODO
---
src/plugin/PluginBase.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php
index 727e93591..3b401d44a 100644
--- a/src/plugin/PluginBase.php
+++ b/src/plugin/PluginBase.php
@@ -66,7 +66,6 @@ abstract class PluginBase implements Plugin, CommandExecutor{
private string $resourceFolder,
){
$this->dataFolder = rtrim($dataFolder, "/" . DIRECTORY_SEPARATOR) . "/";
- //TODO: this is accessed externally via reflection, not unused
$this->file = rtrim($file, "/" . DIRECTORY_SEPARATOR) . "/";
$this->resourceFolder = rtrim(str_replace(DIRECTORY_SEPARATOR, "/", $resourceFolder), "/") . "/";
From eb3922fc7e9e847ef59427d3aa833ff15781d8a2 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 4 May 2025 17:10:01 +0100
Subject: [PATCH 006/140] shut
---
src/crash/CrashDump.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php
index df7c9199d..15c48c7a7 100644
--- a/src/crash/CrashDump.php
+++ b/src/crash/CrashDump.php
@@ -26,7 +26,6 @@ namespace pocketmine\crash;
use Composer\InstalledVersions;
use pocketmine\errorhandler\ErrorTypeToStringMap;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
-use pocketmine\plugin\PluginBase;
use pocketmine\plugin\PluginManager;
use pocketmine\Server;
use pocketmine\thread\ThreadCrashInfoFrame;
From f2e74736296eca93f3732cc64041535e824dab00 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 4 May 2025 17:18:58 +0100
Subject: [PATCH 007/140] Update PHP-CS-Fixer
---
.github/workflows/main.yml | 4 ++--
.php-cs-fixer.php | 6 ++++++
build/dump-version-info.php | 4 ++--
src/block/tile/Spawnable.php | 4 ++--
src/world/World.php | 2 +-
5 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index cfe97aa7e..cabda54be 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -30,8 +30,8 @@ jobs:
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.33.0
with:
- php-version: 8.2
- tools: php-cs-fixer:3.49
+ php-version: 8.3
+ tools: php-cs-fixer:3.75
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
index 32af1ef48..5a14b1d35 100644
--- a/.php-cs-fixer.php
+++ b/.php-cs-fixer.php
@@ -6,6 +6,12 @@ $finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/tests')
->in(__DIR__ . '/tools')
->notPath('plugins/DevTools')
+ //JsonMapper will break if the FQNs in the doc comments for these are shortened :(
+ ->notPath('crafting/json')
+ ->notPath('inventory/json')
+ ->notPath('data/bedrock/block/upgrade/model')
+ ->notPath('data/bedrock/item/upgrade/model')
+
->notName('PocketMine.php');
return (new PhpCsFixer\Config)
diff --git a/build/dump-version-info.php b/build/dump-version-info.php
index e13696f3d..3181acba6 100644
--- a/build/dump-version-info.php
+++ b/build/dump-version-info.php
@@ -31,8 +31,8 @@ require dirname(__DIR__) . '/vendor/autoload.php';
*/
/**
- * @var string[]|\Closure[] $options
- * @phpstan-var array $options
+ * @var string[]|Closure[] $options
+ * @phpstan-var array $options
*/
$options = [
"base_version" => VersionInfo::BASE_VERSION,
diff --git a/src/block/tile/Spawnable.php b/src/block/tile/Spawnable.php
index 67bc72fd9..0c41713f2 100644
--- a/src/block/tile/Spawnable.php
+++ b/src/block/tile/Spawnable.php
@@ -32,7 +32,7 @@ use pocketmine\network\mcpe\protocol\types\CacheableNbt;
use function get_class;
abstract class Spawnable extends Tile{
- /** @phpstan-var CacheableNbt<\pocketmine\nbt\tag\CompoundTag>|null */
+ /** @phpstan-var CacheableNbt|null */
private ?CacheableNbt $spawnCompoundCache = null;
/**
@@ -73,7 +73,7 @@ abstract class Spawnable extends Tile{
* Returns encoded NBT (varint, little-endian) used to spawn this tile to clients. Uses cache where possible,
* populates cache if it is null.
*
- * @phpstan-return CacheableNbt<\pocketmine\nbt\tag\CompoundTag>
+ * @phpstan-return CacheableNbt
*/
final public function getSerializedSpawnCompound() : CacheableNbt{
if($this->spawnCompoundCache === null){
diff --git a/src/world/World.php b/src/world/World.php
index 3a7d0c538..63a617126 100644
--- a/src/world/World.php
+++ b/src/world/World.php
@@ -360,7 +360,7 @@ class World implements ChunkManager{
private bool $doingTick = false;
- /** @phpstan-var class-string<\pocketmine\world\generator\Generator> */
+ /** @phpstan-var class-string */
private string $generator;
private bool $unloaded = false;
From d789c75c0084cacac09baa33d8ec5462d1f9c089 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Thu, 8 May 2025 02:21:39 +0100
Subject: [PATCH 008/140] Improve PHPStan error reporting for unsafe foreaches
these are actually two separate concerns: one for dodgy PHPStan type
suppression on implicit keys, and the other for arrays being casted to
strings by PHP.
---
phpstan.neon.dist | 2 +-
...OfStringRule.php => UnsafeForeachRule.php} | 43 +++++++++++--------
2 files changed, 26 insertions(+), 19 deletions(-)
rename tests/phpstan/rules/{UnsafeForeachArrayOfStringRule.php => UnsafeForeachRule.php} (69%)
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index 13f35c121..12c739f2f 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -15,7 +15,7 @@ rules:
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
- pocketmine\phpstan\rules\ExplodeLimitRule
- - pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
+ - pocketmine\phpstan\rules\UnsafeForeachRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
parameters:
diff --git a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php b/tests/phpstan/rules/UnsafeForeachRule.php
similarity index 69%
rename from tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php
rename to tests/phpstan/rules/UnsafeForeachRule.php
index 34056131b..cb463c61d 100644
--- a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php
+++ b/tests/phpstan/rules/UnsafeForeachRule.php
@@ -41,7 +41,7 @@ use function sprintf;
/**
* @implements Rule
*/
-final class UnsafeForeachArrayOfStringRule implements Rule{
+final class UnsafeForeachRule implements Rule{
public function getNodeType() : string{
return Foreach_::class;
@@ -73,7 +73,7 @@ final class UnsafeForeachArrayOfStringRule implements Rule{
$benevolentUnionDepth--;
return $result;
}
- if($type instanceof IntegerType && $benevolentUnionDepth === 0){
+ if($type instanceof IntegerType){
$expectsIntKeyTypes = true;
return $type;
}
@@ -87,24 +87,31 @@ final class UnsafeForeachArrayOfStringRule implements Rule{
$hasCastableKeyTypes = true;
return $type;
});
- if($hasCastableKeyTypes && !$expectsIntKeyTypes){
- $tip = $implicitType ?
- sprintf(
- "Declare a key type using @phpstan-var or @phpstan-param, or use %s() to promote the key type to get proper error reporting",
+ $errors = [];
+ if($implicitType){
+ $errors[] = RuleErrorBuilder::message("Possible unreported errors in foreach on array with unspecified key type.")
+ ->tip(sprintf(
+ <<getIterableKeyType()->describe(VerbosityLevel::value())
- ))->tip($tip)->identifier('pocketmine.foreach.stringKeys')->build()
- ];
+ ))->identifier('pocketmine.foreach.implicitKeys')->build();
}
- return [];
+ if($hasCastableKeyTypes && !$expectsIntKeyTypes){
+ $errors[] = RuleErrorBuilder::message(sprintf(
+ "Unsafe foreach on array with key type %s.",
+ $iterableType->getIterableKeyType()->describe(VerbosityLevel::value())
+ ))
+ ->tip(sprintf(
+ <<identifier('pocketmine.foreach.stringKeys')->build();
+ }
+ return $errors;
}
}
From 5e830c732075d067887eaac9fb605d6a347e8115 Mon Sep 17 00:00:00 2001
From: Dries C
Date: Fri, 9 May 2025 16:29:05 +0200
Subject: [PATCH 009/140] Protocol changes for 1.21.80 (#6687)
* Bedrock 1.21.80 support
* Update bedrock-data
* Add required tags to models
* Fixed biome data loading
* Support newest world format
apparently I messed up the blockstate data version last time around... it hasn't changed since 1.21.60
* always CS has to complain...
* Sync with release versions
* Ready 5.28.0 release
* this might help...
---------
Co-authored-by: Dylan T.
---
changelogs/5.28.md | 21 ++++++
composer.json | 4 +-
composer.lock | 30 ++++----
src/VersionInfo.php | 4 +-
src/data/bedrock/BedrockDataFiles.php | 3 +-
src/data/bedrock/block/BlockStateData.php | 4 +-
src/data/bedrock/block/BlockStateNames.php | 1 +
src/data/bedrock/block/BlockTypeNames.php | 1 +
src/data/bedrock/item/ItemTypeNames.php | 17 +++++
src/network/mcpe/cache/StaticPacketCache.php | 63 ++++++++++++++++-
.../mcpe/handler/InGamePacketHandler.php | 5 --
.../biome/model/BiomeDefinitionEntryData.php | 69 +++++++++++++++++++
src/world/biome/model/ColorData.php | 41 +++++++++++
src/world/format/io/data/BedrockWorldData.php | 4 +-
tools/generate-bedrock-data-from-packets.php | 54 ++++++++-------
15 files changed, 264 insertions(+), 57 deletions(-)
create mode 100644 changelogs/5.28.md
create mode 100644 src/world/biome/model/BiomeDefinitionEntryData.php
create mode 100644 src/world/biome/model/ColorData.php
diff --git a/changelogs/5.28.md b/changelogs/5.28.md
new file mode 100644
index 000000000..f368e819e
--- /dev/null
+++ b/changelogs/5.28.md
@@ -0,0 +1,21 @@
+# 5.28.0
+Released 9th May 2025.
+
+This is a support release for Minecraft: Bedrock Edition 1.21.80.
+
+**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
+- Aded support for Minecraft: Bedrock Edition 1.21.70.
+- Removed support for earlier versions.
+
+## Fixes
+- `AvailableEnchantmentRegistry` now requires provided tags to always be `string`. Previously, this wasn't enforced, leading to random crashes in core code related to enchanting.
+- `Entity->setFireTicks()` and `Entity->setOnFire()` now truncate the fire time to the max value instead of throwing exceptions.
+
+## Internals
+- Improved PHPStan error reporting for unsafe foreaches. Foreach on an array with implicit keys now generates different errors than foreach on an array with string keys.
diff --git a/composer.json b/composer.json
index 87086f456..7545806b4 100644
--- a/composer.json
+++ b/composer.json
@@ -34,9 +34,9 @@
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
- "pocketmine/bedrock-data": "~4.1.0+bedrock-1.21.70",
+ "pocketmine/bedrock-data": "5.0.0+bedrock-1.21.80",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
- "pocketmine/bedrock-protocol": "~37.0.0+bedrock-1.21.70",
+ "pocketmine/bedrock-protocol": "38.0.0+bedrock-1.21.80",
"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 23f312317..d45311018 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": "818c679a25da8e6b466bc454ad48dec3",
+ "content-hash": "4dfc7b8c912d8d5fa194ddc0e97903fb",
"packages": [
{
"name": "adhocore/json-comment",
@@ -204,16 +204,16 @@
},
{
"name": "pocketmine/bedrock-data",
- "version": "4.1.0+bedrock-1.21.70",
+ "version": "5.0.0+bedrock-1.21.80",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
- "reference": "d53fe98cb3b596ac016e275df5bd5e89b04a4817"
+ "reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d53fe98cb3b596ac016e275df5bd5e89b04a4817",
- "reference": "d53fe98cb3b596ac016e275df5bd5e89b04a4817",
+ "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/e38d5ea19f794ec5216e5f96742237e8c4e7f080",
+ "reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080",
"shasum": ""
},
"type": "library",
@@ -224,9 +224,9 @@
"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.21.70"
+ "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.80"
},
- "time": "2025-03-25T19:43:31+00:00"
+ "time": "2025-05-09T14:15:18+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
@@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "37.0.0+bedrock-1.21.70",
+ "version": "38.0.0+bedrock-1.21.80",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "7091dad2c12ed4a4106432df21fc698960c6be9e"
+ "reference": "a626561eaefeb6333c0d2726e2789ceb0aac0724"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/7091dad2c12ed4a4106432df21fc698960c6be9e",
- "reference": "7091dad2c12ed4a4106432df21fc698960c6be9e",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a626561eaefeb6333c0d2726e2789ceb0aac0724",
+ "reference": "a626561eaefeb6333c0d2726e2789ceb0aac0724",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/37.0.0+bedrock-1.21.70"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/38.0.0+bedrock-1.21.80"
},
- "time": "2025-03-27T15:19:36+00:00"
+ "time": "2025-05-09T14:17:07+00:00"
},
{
"name": "pocketmine/binaryutils",
@@ -2921,7 +2921,7 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@@ -2952,7 +2952,7 @@
"ext-zlib": ">=1.2.11",
"composer-runtime-api": "^2.0"
},
- "platform-dev": [],
+ "platform-dev": {},
"platform-overrides": {
"php": "8.1.0"
},
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 44238dba3..c5b38f072 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.27.2";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const BASE_VERSION = "5.28.0";
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
diff --git a/src/data/bedrock/BedrockDataFiles.php b/src/data/bedrock/BedrockDataFiles.php
index 1ecb707cc..53bd9b11e 100644
--- a/src/data/bedrock/BedrockDataFiles.php
+++ b/src/data/bedrock/BedrockDataFiles.php
@@ -31,8 +31,7 @@ final class BedrockDataFiles{
}
public const BANNER_PATTERNS_JSON = BEDROCK_DATA_PATH . '/banner_patterns.json';
- public const BIOME_DEFINITIONS_NBT = BEDROCK_DATA_PATH . '/biome_definitions.nbt';
- public const BIOME_DEFINITIONS_FULL_NBT = BEDROCK_DATA_PATH . '/biome_definitions_full.nbt';
+ public const BIOME_DEFINITIONS_JSON = BEDROCK_DATA_PATH . '/biome_definitions.json';
public const BIOME_ID_MAP_JSON = BEDROCK_DATA_PATH . '/biome_id_map.json';
public const BLOCK_ID_TO_ITEM_ID_MAP_JSON = BEDROCK_DATA_PATH . '/block_id_to_item_id_map.json';
public const BLOCK_PROPERTIES_TABLE_JSON = BEDROCK_DATA_PATH . '/block_properties_table.json';
diff --git a/src/data/bedrock/block/BlockStateData.php b/src/data/bedrock/block/BlockStateData.php
index 600eba938..e90410ac7 100644
--- a/src/data/bedrock/block/BlockStateData.php
+++ b/src/data/bedrock/block/BlockStateData.php
@@ -45,8 +45,8 @@ final class BlockStateData{
public const CURRENT_VERSION =
(1 << 24) | //major
(21 << 16) | //minor
- (70 << 8) | //patch
- (1); //revision
+ (60 << 8) | //patch
+ (33); //revision
public const TAG_NAME = "name";
public const TAG_STATES = "states";
diff --git a/src/data/bedrock/block/BlockStateNames.php b/src/data/bedrock/block/BlockStateNames.php
index 9fed77e4a..704798d1d 100644
--- a/src/data/bedrock/block/BlockStateNames.php
+++ b/src/data/bedrock/block/BlockStateNames.php
@@ -113,6 +113,7 @@ final class BlockStateNames{
public const RAIL_DATA_BIT = "rail_data_bit";
public const RAIL_DIRECTION = "rail_direction";
public const REDSTONE_SIGNAL = "redstone_signal";
+ public const REHYDRATION_LEVEL = "rehydration_level";
public const REPEATER_DELAY = "repeater_delay";
public const RESPAWN_ANCHOR_CHARGE = "respawn_anchor_charge";
public const ROTATION = "rotation";
diff --git a/src/data/bedrock/block/BlockTypeNames.php b/src/data/bedrock/block/BlockTypeNames.php
index bc30800fc..527a01345 100644
--- a/src/data/bedrock/block/BlockTypeNames.php
+++ b/src/data/bedrock/block/BlockTypeNames.php
@@ -392,6 +392,7 @@ final class BlockTypeNames{
public const DOUBLE_CUT_COPPER_SLAB = "minecraft:double_cut_copper_slab";
public const DRAGON_EGG = "minecraft:dragon_egg";
public const DRAGON_HEAD = "minecraft:dragon_head";
+ public const DRIED_GHAST = "minecraft:dried_ghast";
public const DRIED_KELP_BLOCK = "minecraft:dried_kelp_block";
public const DRIPSTONE_BLOCK = "minecraft:dripstone_block";
public const DROPPER = "minecraft:dropper";
diff --git a/src/data/bedrock/item/ItemTypeNames.php b/src/data/bedrock/item/ItemTypeNames.php
index ea95d57f0..5f86cde96 100644
--- a/src/data/bedrock/item/ItemTypeNames.php
+++ b/src/data/bedrock/item/ItemTypeNames.php
@@ -68,6 +68,7 @@ final class ItemTypeNames{
public const BIRCH_SIGN = "minecraft:birch_sign";
public const BLACK_BUNDLE = "minecraft:black_bundle";
public const BLACK_DYE = "minecraft:black_dye";
+ public const BLACK_HARNESS = "minecraft:black_harness";
public const BLADE_POTTERY_SHERD = "minecraft:blade_pottery_sherd";
public const BLAZE_POWDER = "minecraft:blaze_powder";
public const BLAZE_ROD = "minecraft:blaze_rod";
@@ -76,6 +77,7 @@ final class ItemTypeNames{
public const BLUE_BUNDLE = "minecraft:blue_bundle";
public const BLUE_DYE = "minecraft:blue_dye";
public const BLUE_EGG = "minecraft:blue_egg";
+ public const BLUE_HARNESS = "minecraft:blue_harness";
public const BOARD = "minecraft:board";
public const BOAT = "minecraft:boat";
public const BOGGED_SPAWN_EGG = "minecraft:bogged_spawn_egg";
@@ -95,6 +97,7 @@ final class ItemTypeNames{
public const BROWN_BUNDLE = "minecraft:brown_bundle";
public const BROWN_DYE = "minecraft:brown_dye";
public const BROWN_EGG = "minecraft:brown_egg";
+ public const BROWN_HARNESS = "minecraft:brown_harness";
public const BRUSH = "minecraft:brush";
public const BUCKET = "minecraft:bucket";
public const BUNDLE = "minecraft:bundle";
@@ -166,6 +169,7 @@ final class ItemTypeNames{
public const CROSSBOW = "minecraft:crossbow";
public const CYAN_BUNDLE = "minecraft:cyan_bundle";
public const CYAN_DYE = "minecraft:cyan_dye";
+ public const CYAN_HARNESS = "minecraft:cyan_harness";
public const DANGER_POTTERY_SHERD = "minecraft:danger_pottery_sherd";
public const DARK_OAK_BOAT = "minecraft:dark_oak_boat";
public const DARK_OAK_CHEST_BOAT = "minecraft:dark_oak_chest_boat";
@@ -265,12 +269,15 @@ final class ItemTypeNames{
public const GOLDEN_SWORD = "minecraft:golden_sword";
public const GRAY_BUNDLE = "minecraft:gray_bundle";
public const GRAY_DYE = "minecraft:gray_dye";
+ public const GRAY_HARNESS = "minecraft:gray_harness";
public const GREEN_BUNDLE = "minecraft:green_bundle";
public const GREEN_DYE = "minecraft:green_dye";
+ public const GREEN_HARNESS = "minecraft:green_harness";
public const GUARDIAN_SPAWN_EGG = "minecraft:guardian_spawn_egg";
public const GUNPOWDER = "minecraft:gunpowder";
public const GUSTER_BANNER_PATTERN = "minecraft:guster_banner_pattern";
public const GUSTER_POTTERY_SHERD = "minecraft:guster_pottery_sherd";
+ public const HAPPY_GHAST_SPAWN_EGG = "minecraft:happy_ghast_spawn_egg";
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";
@@ -321,10 +328,13 @@ final class ItemTypeNames{
public const LIGHT_BLOCK = "minecraft:light_block";
public const LIGHT_BLUE_BUNDLE = "minecraft:light_blue_bundle";
public const LIGHT_BLUE_DYE = "minecraft:light_blue_dye";
+ public const LIGHT_BLUE_HARNESS = "minecraft:light_blue_harness";
public const LIGHT_GRAY_BUNDLE = "minecraft:light_gray_bundle";
public const LIGHT_GRAY_DYE = "minecraft:light_gray_dye";
+ public const LIGHT_GRAY_HARNESS = "minecraft:light_gray_harness";
public const LIME_BUNDLE = "minecraft:lime_bundle";
public const LIME_DYE = "minecraft:lime_dye";
+ public const LIME_HARNESS = "minecraft:lime_harness";
public const LINGERING_POTION = "minecraft:lingering_potion";
public const LLAMA_SPAWN_EGG = "minecraft:llama_spawn_egg";
public const LODESTONE_COMPASS = "minecraft:lodestone_compass";
@@ -333,6 +343,7 @@ final class ItemTypeNames{
public const MACE = "minecraft:mace";
public const MAGENTA_BUNDLE = "minecraft:magenta_bundle";
public const MAGENTA_DYE = "minecraft:magenta_dye";
+ public const MAGENTA_HARNESS = "minecraft:magenta_harness";
public const MAGMA_CREAM = "minecraft:magma_cream";
public const MAGMA_CUBE_SPAWN_EGG = "minecraft:magma_cube_spawn_egg";
public const MANGROVE_BOAT = "minecraft:mangrove_boat";
@@ -400,6 +411,7 @@ final class ItemTypeNames{
public const OMINOUS_TRIAL_KEY = "minecraft:ominous_trial_key";
public const ORANGE_BUNDLE = "minecraft:orange_bundle";
public const ORANGE_DYE = "minecraft:orange_dye";
+ public const ORANGE_HARNESS = "minecraft:orange_harness";
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
public const PAINTING = "minecraft:painting";
public const PALE_OAK_BOAT = "minecraft:pale_oak_boat";
@@ -419,6 +431,7 @@ final class ItemTypeNames{
public const PILLAGER_SPAWN_EGG = "minecraft:pillager_spawn_egg";
public const PINK_BUNDLE = "minecraft:pink_bundle";
public const PINK_DYE = "minecraft:pink_dye";
+ public const PINK_HARNESS = "minecraft:pink_harness";
public const PITCHER_POD = "minecraft:pitcher_pod";
public const PLANKS = "minecraft:planks";
public const PLENTY_POTTERY_SHERD = "minecraft:plenty_pottery_sherd";
@@ -439,6 +452,7 @@ final class ItemTypeNames{
public const PUMPKIN_SEEDS = "minecraft:pumpkin_seeds";
public const PURPLE_BUNDLE = "minecraft:purple_bundle";
public const PURPLE_DYE = "minecraft:purple_dye";
+ public const PURPLE_HARNESS = "minecraft:purple_harness";
public const QUARTZ = "minecraft:quartz";
public const RABBIT = "minecraft:rabbit";
public const RABBIT_FOOT = "minecraft:rabbit_foot";
@@ -455,6 +469,7 @@ final class ItemTypeNames{
public const RED_BUNDLE = "minecraft:red_bundle";
public const RED_DYE = "minecraft:red_dye";
public const RED_FLOWER = "minecraft:red_flower";
+ public const RED_HARNESS = "minecraft:red_harness";
public const REDSTONE = "minecraft:redstone";
public const REPEATER = "minecraft:repeater";
public const RESIN_BRICK = "minecraft:resin_brick";
@@ -563,6 +578,7 @@ final class ItemTypeNames{
public const WHEAT_SEEDS = "minecraft:wheat_seeds";
public const WHITE_BUNDLE = "minecraft:white_bundle";
public const WHITE_DYE = "minecraft:white_dye";
+ public const WHITE_HARNESS = "minecraft:white_harness";
public const WILD_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wild_armor_trim_smithing_template";
public const WIND_CHARGE = "minecraft:wind_charge";
public const WITCH_SPAWN_EGG = "minecraft:witch_spawn_egg";
@@ -583,6 +599,7 @@ final class ItemTypeNames{
public const WRITTEN_BOOK = "minecraft:written_book";
public const YELLOW_BUNDLE = "minecraft:yellow_bundle";
public const YELLOW_DYE = "minecraft:yellow_dye";
+ public const YELLOW_HARNESS = "minecraft:yellow_harness";
public const ZOGLIN_SPAWN_EGG = "minecraft:zoglin_spawn_egg";
public const ZOMBIE_HORSE_SPAWN_EGG = "minecraft:zombie_horse_spawn_egg";
public const ZOMBIE_PIGMAN_SPAWN_EGG = "minecraft:zombie_pigman_spawn_egg";
diff --git a/src/network/mcpe/cache/StaticPacketCache.php b/src/network/mcpe/cache/StaticPacketCache.php
index 88a522600..861881437 100644
--- a/src/network/mcpe/cache/StaticPacketCache.php
+++ b/src/network/mcpe/cache/StaticPacketCache.php
@@ -23,13 +23,22 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\cache;
+use pocketmine\color\Color;
use pocketmine\data\bedrock\BedrockDataFiles;
+use pocketmine\data\SavedDataLoadingException;
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
+use pocketmine\network\mcpe\protocol\types\biome\BiomeDefinitionEntry;
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
use pocketmine\utils\Filesystem;
use pocketmine\utils\SingletonTrait;
+use pocketmine\utils\Utils;
+use pocketmine\world\biome\model\BiomeDefinitionEntryData;
+use function count;
+use function get_debug_type;
+use function is_array;
+use function json_decode;
class StaticPacketCache{
use SingletonTrait;
@@ -41,9 +50,61 @@ class StaticPacketCache{
return new CacheableNbt((new NetworkNbtSerializer())->read(Filesystem::fileGetContents($filePath))->mustGetCompoundTag());
}
+ /**
+ * @return list
+ */
+ private static function loadBiomeDefinitionModel(string $filePath) : array{
+ $biomeEntries = json_decode(Filesystem::fileGetContents($filePath), associative: true);
+ if(!is_array($biomeEntries)){
+ throw new SavedDataLoadingException("$filePath root should be an array, got " . get_debug_type($biomeEntries));
+ }
+
+ $jsonMapper = new \JsonMapper();
+ $jsonMapper->bExceptionOnMissingData = true;
+ $jsonMapper->bStrictObjectTypeChecking = true;
+ $jsonMapper->bEnforceMapType = false;
+
+ $entries = [];
+ foreach(Utils::promoteKeys($biomeEntries) as $biomeName => $entry){
+ if(!is_array($entry)){
+ throw new SavedDataLoadingException("$filePath should be an array of objects, got " . get_debug_type($entry));
+ }
+
+ try{
+ $biomeDefinition = $jsonMapper->map($entry, new BiomeDefinitionEntryData());
+
+ $mapWaterColour = $biomeDefinition->mapWaterColour;
+ $entries[] = new BiomeDefinitionEntry(
+ (string) $biomeName,
+ $biomeDefinition->id,
+ $biomeDefinition->temperature,
+ $biomeDefinition->downfall,
+ $biomeDefinition->redSporeDensity,
+ $biomeDefinition->blueSporeDensity,
+ $biomeDefinition->ashDensity,
+ $biomeDefinition->whiteAshDensity,
+ $biomeDefinition->depth,
+ $biomeDefinition->scale,
+ new Color(
+ $mapWaterColour->r,
+ $mapWaterColour->g,
+ $mapWaterColour->b,
+ $mapWaterColour->a
+ ),
+ $biomeDefinition->rain,
+ count($biomeDefinition->tags) > 0 ? $biomeDefinition->tags : null,
+ );
+ }catch(\JsonMapper_Exception $e){
+ throw new \RuntimeException($e->getMessage(), 0, $e);
+ }
+ }
+
+ return $entries;
+ }
+
private static function make() : self{
return new self(
- BiomeDefinitionListPacket::create(self::loadCompoundFromFile(BedrockDataFiles::BIOME_DEFINITIONS_NBT)),
+ BiomeDefinitionListPacket::fromDefinitions(self::loadBiomeDefinitionModel(BedrockDataFiles::BIOME_DEFINITIONS_JSON)),
AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(BedrockDataFiles::ENTITY_IDENTIFIERS_NBT))
);
}
diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php
index 93a01fdcc..eec200e4b 100644
--- a/src/network/mcpe/handler/InGamePacketHandler.php
+++ b/src/network/mcpe/handler/InGamePacketHandler.php
@@ -73,7 +73,6 @@ use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
-use pocketmine\network\mcpe\protocol\PlayerInputPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
use pocketmine\network\mcpe\protocol\serializer\BitSet;
@@ -781,10 +780,6 @@ class InGamePacketHandler extends PacketHandler{
return false;
}
- public function handlePlayerInput(PlayerInputPacket $packet) : bool{
- return false; //TODO
- }
-
public function handleSetPlayerGameType(SetPlayerGameTypePacket $packet) : bool{
$gameMode = $this->session->getTypeConverter()->protocolGameModeToCore($packet->gamemode);
if($gameMode !== $this->player->getGamemode()){
diff --git a/src/world/biome/model/BiomeDefinitionEntryData.php b/src/world/biome/model/BiomeDefinitionEntryData.php
new file mode 100644
index 000000000..8a5c3d354
--- /dev/null
+++ b/src/world/biome/model/BiomeDefinitionEntryData.php
@@ -0,0 +1,69 @@
+
+ */
+ public array $tags;
+}
diff --git a/src/world/biome/model/ColorData.php b/src/world/biome/model/ColorData.php
new file mode 100644
index 000000000..f70a77d15
--- /dev/null
+++ b/src/world/biome/model/ColorData.php
@@ -0,0 +1,41 @@
+bedrockDataPath . '/biome_definitions_full.nbt', $packet->definitions->getEncodedNbt());
+ $definitions = [];
+ foreach($packet->buildDefinitionsFromData() as $entry){
+ $mapWaterColor = new ColorData();
+ $mapWaterColor->r = $entry->getMapWaterColor()->getR();
+ $mapWaterColor->g = $entry->getMapWaterColor()->getG();
+ $mapWaterColor->b = $entry->getMapWaterColor()->getB();
+ $mapWaterColor->a = $entry->getMapWaterColor()->getA();
- $nbt = $packet->definitions->getRoot();
- if(!$nbt instanceof CompoundTag){
- throw new AssumptionFailedError();
- }
- $strippedNbt = clone $nbt;
- foreach($strippedNbt as $compound){
- if($compound instanceof CompoundTag){
- foreach([
- "minecraft:capped_surface",
- "minecraft:consolidated_features",
- "minecraft:frozen_ocean_surface",
- "minecraft:legacy_world_generation_rules",
- "minecraft:mesa_surface",
- "minecraft:mountain_parameters",
- "minecraft:multinoise_generation_rules",
- "minecraft:overworld_generation_rules",
- "minecraft:surface_material_adjustments",
- "minecraft:surface_parameters",
- "minecraft:swamp_surface",
- ] as $remove){
- $compound->removeTag($remove);
- }
- }
+ $data = new BiomeDefinitionEntryData();
+ $data->id = $entry->getId();
+ $data->temperature = round($entry->getTemperature(), 3);
+ $data->downfall = round($entry->getDownfall(), 3);
+ $data->redSporeDensity = round($entry->getRedSporeDensity(), 3);
+ $data->blueSporeDensity = round($entry->getBlueSporeDensity(), 3);
+ $data->ashDensity = round($entry->getAshDensity(), 3);
+ $data->whiteAshDensity = round($entry->getWhiteAshDensity(), 3);
+ $data->depth = round($entry->getDepth(), 3);
+ $data->scale = round($entry->getScale(), 3);
+ $data->mapWaterColour = $mapWaterColor;
+ $data->rain = $entry->hasRain();
+ $data->tags = $entry->getTags() ?? [];
+
+ $definitions[$entry->getBiomeName()] = self::objectToOrderedArray($data);
}
- file_put_contents($this->bedrockDataPath . '/biome_definitions.nbt', (new CacheableNbt($strippedNbt))->getEncodedNbt());
+ ksort($definitions, SORT_STRING);
+
+ file_put_contents($this->bedrockDataPath . '/biome_definitions.json', json_encode($definitions, JSON_PRETTY_PRINT) . "\n");
return true;
}
From 134c7309c5985cd6df0a323a8465f44e9099510a Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Fri, 9 May 2025 14:30:04 +0000
Subject: [PATCH 010/140] 5.28.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/14931216524
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index c5b38f072..acc7db91c 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.28.0";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.28.1";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From d90fc3415c611a976cdde80bbcd79574fadb38bf Mon Sep 17 00:00:00 2001
From: ItzxDwi <107537435+ItzxDwi@users.noreply.github.com>
Date: Fri, 9 May 2025 23:33:55 +0800
Subject: [PATCH 011/140] fixed wrong version info (#6689)
---
changelogs/5.28.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/changelogs/5.28.md b/changelogs/5.28.md
index f368e819e..8a69b97e0 100644
--- a/changelogs/5.28.md
+++ b/changelogs/5.28.md
@@ -10,7 +10,7 @@ Do not update plugin minimum API versions unless you need new features added in
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
-- Aded support for Minecraft: Bedrock Edition 1.21.70.
+- Aded support for Minecraft: Bedrock Edition 1.21.80.
- Removed support for earlier versions.
## Fixes
From 04de72e85ec8c8da36e1d527db3cbe4ee855a124 Mon Sep 17 00:00:00 2001
From: Sergi del Olmo
Date: Sat, 10 May 2025 15:34:37 +0200
Subject: [PATCH 012/140] Fix changelog typo (#6690)
---
changelogs/5.28.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/changelogs/5.28.md b/changelogs/5.28.md
index 8a69b97e0..a2ede942f 100644
--- a/changelogs/5.28.md
+++ b/changelogs/5.28.md
@@ -10,7 +10,7 @@ Do not update plugin minimum API versions unless you need new features added in
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
-- Aded support for Minecraft: Bedrock Edition 1.21.80.
+- Added support for Minecraft: Bedrock Edition 1.21.80.
- Removed support for earlier versions.
## Fixes
From bb7bfee0cd94bdae7026026e9eaf01d53157eb19 Mon Sep 17 00:00:00 2001
From: zSALLAZAR <59490940+zSALLAZAR@users.noreply.github.com>
Date: Wed, 14 May 2025 08:06:22 +0200
Subject: [PATCH 013/140] Remove `ServerEvent` class (#6695)
---
src/event/server/CommandEvent.php | 3 +-
src/event/server/DataPacketDecodeEvent.php | 3 +-
src/event/server/DataPacketReceiveEvent.php | 3 +-
src/event/server/DataPacketSendEvent.php | 3 +-
src/event/server/LowMemoryEvent.php | 3 +-
src/event/server/NetworkInterfaceEvent.php | 3 +-
src/event/server/QueryRegenerateEvent.php | 3 +-
src/event/server/ServerEvent.php | 33 ---------------------
src/event/server/UpdateNotifyEvent.php | 3 +-
9 files changed, 16 insertions(+), 41 deletions(-)
delete mode 100644 src/event/server/ServerEvent.php
diff --git a/src/event/server/CommandEvent.php b/src/event/server/CommandEvent.php
index 1881ad496..f8feb6808 100644
--- a/src/event/server/CommandEvent.php
+++ b/src/event/server/CommandEvent.php
@@ -26,6 +26,7 @@ namespace pocketmine\event\server;
use pocketmine\command\CommandSender;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
+use pocketmine\event\Event;
/**
* Called when any CommandSender runs a command, before it is parsed.
@@ -41,7 +42,7 @@ use pocketmine\event\CancellableTrait;
*
* The message DOES NOT begin with a slash.
*/
-class CommandEvent extends ServerEvent implements Cancellable{
+class CommandEvent extends Event implements Cancellable{
use CancellableTrait;
public function __construct(
diff --git a/src/event/server/DataPacketDecodeEvent.php b/src/event/server/DataPacketDecodeEvent.php
index 44aefbb91..9a3b9be21 100644
--- a/src/event/server/DataPacketDecodeEvent.php
+++ b/src/event/server/DataPacketDecodeEvent.php
@@ -25,13 +25,14 @@ namespace pocketmine\event\server;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
+use pocketmine\event\Event;
use pocketmine\network\mcpe\NetworkSession;
/**
* Called before a packet is decoded and handled by the network session.
* Cancelling this event will drop the packet without decoding it, minimizing wasted CPU time.
*/
-class DataPacketDecodeEvent extends ServerEvent implements Cancellable{
+class DataPacketDecodeEvent extends Event implements Cancellable{
use CancellableTrait;
public function __construct(
diff --git a/src/event/server/DataPacketReceiveEvent.php b/src/event/server/DataPacketReceiveEvent.php
index 17224003d..41d2a2445 100644
--- a/src/event/server/DataPacketReceiveEvent.php
+++ b/src/event/server/DataPacketReceiveEvent.php
@@ -25,10 +25,11 @@ namespace pocketmine\event\server;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
+use pocketmine\event\Event;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\ServerboundPacket;
-class DataPacketReceiveEvent extends ServerEvent implements Cancellable{
+class DataPacketReceiveEvent extends Event implements Cancellable{
use CancellableTrait;
public function __construct(
diff --git a/src/event/server/DataPacketSendEvent.php b/src/event/server/DataPacketSendEvent.php
index 147d99db3..d46990015 100644
--- a/src/event/server/DataPacketSendEvent.php
+++ b/src/event/server/DataPacketSendEvent.php
@@ -25,6 +25,7 @@ namespace pocketmine\event\server;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
+use pocketmine\event\Event;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\utils\Utils;
@@ -32,7 +33,7 @@ use pocketmine\utils\Utils;
/**
* Called when packets are sent to network sessions.
*/
-class DataPacketSendEvent extends ServerEvent implements Cancellable{
+class DataPacketSendEvent extends Event implements Cancellable{
use CancellableTrait;
/**
diff --git a/src/event/server/LowMemoryEvent.php b/src/event/server/LowMemoryEvent.php
index aea9afa80..a30e747e5 100644
--- a/src/event/server/LowMemoryEvent.php
+++ b/src/event/server/LowMemoryEvent.php
@@ -23,13 +23,14 @@ declare(strict_types=1);
namespace pocketmine\event\server;
+use pocketmine\event\Event;
use pocketmine\utils\Process;
/**
* Called when the server is in a low-memory state as defined by the properties
* Plugins should free caches or other non-essential data.
*/
-class LowMemoryEvent extends ServerEvent{
+class LowMemoryEvent extends Event{
public function __construct(
private int $memory,
private int $memoryLimit,
diff --git a/src/event/server/NetworkInterfaceEvent.php b/src/event/server/NetworkInterfaceEvent.php
index 5c1675f19..2278c1bc2 100644
--- a/src/event/server/NetworkInterfaceEvent.php
+++ b/src/event/server/NetworkInterfaceEvent.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\event\server;
+use pocketmine\event\Event;
use pocketmine\network\NetworkInterface;
-class NetworkInterfaceEvent extends ServerEvent{
+class NetworkInterfaceEvent extends Event{
public function __construct(
protected NetworkInterface $interface
){}
diff --git a/src/event/server/QueryRegenerateEvent.php b/src/event/server/QueryRegenerateEvent.php
index c51bc5054..02146621a 100644
--- a/src/event/server/QueryRegenerateEvent.php
+++ b/src/event/server/QueryRegenerateEvent.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\event\server;
+use pocketmine\event\Event;
use pocketmine\network\query\QueryInfo;
-class QueryRegenerateEvent extends ServerEvent{
+class QueryRegenerateEvent extends Event{
public function __construct(private QueryInfo $queryInfo){}
public function getQueryInfo() : QueryInfo{
diff --git a/src/event/server/ServerEvent.php b/src/event/server/ServerEvent.php
deleted file mode 100644
index 97e79279d..000000000
--- a/src/event/server/ServerEvent.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
Date: Sat, 17 May 2025 13:33:42 +0100
Subject: [PATCH 014/140] Consolidate Bedrock data version info this ensures we
don't have to go into a bunch of randomly scattered files to update version
numbers.
---
src/data/bedrock/WorldDataVersions.php | 67 +++++++++++++++++++
src/data/bedrock/block/BlockStateData.php | 13 +---
src/world/format/io/data/BedrockWorldData.php | 13 ++--
src/world/format/io/leveldb/LevelDB.php | 5 +-
4 files changed, 76 insertions(+), 22 deletions(-)
create mode 100644 src/data/bedrock/WorldDataVersions.php
diff --git a/src/data/bedrock/WorldDataVersions.php b/src/data/bedrock/WorldDataVersions.php
new file mode 100644
index 000000000..498dac9da
--- /dev/null
+++ b/src/data/bedrock/WorldDataVersions.php
@@ -0,0 +1,67 @@
+
Date: Sat, 17 May 2025 13:35:52 +0100
Subject: [PATCH 015/140] always the CS...
---
src/data/bedrock/WorldDataVersions.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/data/bedrock/WorldDataVersions.php b/src/data/bedrock/WorldDataVersions.php
index 498dac9da..e79478b11 100644
--- a/src/data/bedrock/WorldDataVersions.php
+++ b/src/data/bedrock/WorldDataVersions.php
@@ -43,7 +43,6 @@ final class WorldDataVersions{
(60 << 8) | //patch
(33); //revision
-
public const CHUNK = ChunkVersion::v1_21_40;
public const SUBCHUNK = SubChunkVersion::PALETTED_MULTI;
From 67f3bb9c5242dfab49ccb25d65edb4e00ac3f7e2 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 13:46:33 +0100
Subject: [PATCH 016/140] Update composer dependencies and fix an error found
by new PHPStan update
---
composer.json | 2 +-
composer.lock | 63 +++++++++++++++++++---------------
src/thread/ThreadCrashInfo.php | 2 +-
3 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/composer.json b/composer.json
index 7545806b4..8900eea51 100644
--- a/composer.json
+++ b/composer.json
@@ -52,7 +52,7 @@
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
- "phpstan/phpstan": "2.1.11",
+ "phpstan/phpstan": "2.1.16",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
diff --git a/composer.lock b/composer.lock
index d45311018..94eebda8c 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": "4dfc7b8c912d8d5fa194ddc0e97903fb",
+ "content-hash": "e3fffa76c2ce9dd0f5c2cd66a5aa097c",
"packages": [
{
"name": "adhocore/json-comment",
@@ -976,7 +976,7 @@
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.31.0",
+ "version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@@ -1035,7 +1035,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
},
"funding": [
{
@@ -1055,19 +1055,20 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.31.0",
+ "version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
+ "ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
@@ -1115,7 +1116,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
},
"funding": [
{
@@ -1131,22 +1132,22 @@
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2024-12-23T08:48:59+00:00"
}
],
"packages-dev": [
{
"name": "myclabs/deep-copy",
- "version": "1.13.0",
+ "version": "1.13.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "024473a478be9df5fdaca2c793f2232fe788e414"
+ "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
- "reference": "024473a478be9df5fdaca2c793f2232fe788e414",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c",
+ "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c",
"shasum": ""
},
"require": {
@@ -1185,7 +1186,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1"
},
"funding": [
{
@@ -1193,7 +1194,7 @@
"type": "tidelift"
}
],
- "time": "2025-02-12T12:17:51+00:00"
+ "time": "2025-04-29T12:36:36+00:00"
},
{
"name": "nikic/php-parser",
@@ -1373,16 +1374,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "2.1.11",
+ "version": "2.1.16",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30"
+ "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30",
- "reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
+ "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
"shasum": ""
},
"require": {
@@ -1427,7 +1428,7 @@
"type": "github"
}
],
- "time": "2025-03-24T13:45:00+00:00"
+ "time": "2025-05-16T09:40:10+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
@@ -1853,16 +1854,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "10.5.45",
+ "version": "10.5.46",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "bd68a781d8e30348bc297449f5234b3458267ae8"
+ "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8",
- "reference": "bd68a781d8e30348bc297449f5234b3458267ae8",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d",
+ "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d",
"shasum": ""
},
"require": {
@@ -1872,7 +1873,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.12.1",
+ "myclabs/deep-copy": "^1.13.1",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.1",
@@ -1934,7 +1935,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46"
},
"funding": [
{
@@ -1945,12 +1946,20 @@
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
"type": "tidelift"
}
],
- "time": "2025-02-06T16:08:12+00:00"
+ "time": "2025-05-02T06:46:24+00:00"
},
{
"name": "sebastian/cli-parser",
diff --git a/src/thread/ThreadCrashInfo.php b/src/thread/ThreadCrashInfo.php
index 66aae927a..6fffdc83b 100644
--- a/src/thread/ThreadCrashInfo.php
+++ b/src/thread/ThreadCrashInfo.php
@@ -84,6 +84,6 @@ final class ThreadCrashInfo extends ThreadSafe{
public function getThreadName() : string{ return $this->threadName; }
public function makePrettyMessage() : string{
- return sprintf("%s: \"%s\" in \"%s\" on line %d", $this->type ?? "Fatal error", $this->message, Filesystem::cleanPath($this->file), $this->line);
+ return sprintf("%s: \"%s\" in \"%s\" on line %d", $this->type, $this->message, Filesystem::cleanPath($this->file), $this->line);
}
}
From dca37d5842a6405004aff5eeb3fca264f2b260df Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 14:11:57 +0100
Subject: [PATCH 017/140] Hack: forcibly remove symfony/polyfill-mbstring we
don't need this dependency anyway because mbstring is already provided.
---
composer.json | 3 ++
composer.lock | 83 +--------------------------------------------------
2 files changed, 4 insertions(+), 82 deletions(-)
diff --git a/composer.json b/composer.json
index 8900eea51..f24ddc7e5 100644
--- a/composer.json
+++ b/composer.json
@@ -57,6 +57,9 @@
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
},
+ "provide": {
+ "symfony/polyfill-mbstring": "*"
+ },
"autoload": {
"psr-4": {
"pocketmine\\": "src/"
diff --git a/composer.lock b/composer.lock
index 94eebda8c..2350246ed 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": "e3fffa76c2ce9dd0f5c2cd66a5aa097c",
+ "content-hash": "c2f2a1e28028894c1b12484f115732f0",
"packages": [
{
"name": "adhocore/json-comment",
@@ -1052,87 +1052,6 @@
}
],
"time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-mbstring",
- "version": "v1.32.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "shasum": ""
- },
- "require": {
- "ext-iconv": "*",
- "php": ">=7.2"
- },
- "provide": {
- "ext-mbstring": "*"
- },
- "suggest": {
- "ext-mbstring": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Mbstring\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for the Mbstring extension",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "mbstring",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-12-23T08:48:59+00:00"
}
],
"packages-dev": [
From e0864e7ee82d4295e2b1d80d0d057016b5e94956 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 14:54:26 +0100
Subject: [PATCH 018/140] composer: also axe unnecessary ctype polyfill
---
composer.json | 1 +
composer.lock | 81 +--------------------------------------------------
2 files changed, 2 insertions(+), 80 deletions(-)
diff --git a/composer.json b/composer.json
index f24ddc7e5..1482aa4cb 100644
--- a/composer.json
+++ b/composer.json
@@ -58,6 +58,7 @@
"phpunit/phpunit": "^10.5.24"
},
"provide": {
+ "symfony/polyfill-ctype": "*",
"symfony/polyfill-mbstring": "*"
},
"autoload": {
diff --git a/composer.lock b/composer.lock
index 2350246ed..1326fbc9a 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": "c2f2a1e28028894c1b12484f115732f0",
+ "content-hash": "b25d87be51beaaad7285a6b2e771ab4e",
"packages": [
{
"name": "adhocore/json-comment",
@@ -973,85 +973,6 @@
}
],
"time": "2024-10-25T15:07:50+00:00"
- },
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.32.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
}
],
"packages-dev": [
From abb004fbc5d03ff58a5f68f069b70d7e682fc70a Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Sat, 17 May 2025 15:00:53 +0100
Subject: [PATCH 019/140] Ready 5.28.1 (#6696)
---
changelogs/5.28.md | 6 ++++++
src/VersionInfo.php | 2 +-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/changelogs/5.28.md b/changelogs/5.28.md
index a2ede942f..74906ecc7 100644
--- a/changelogs/5.28.md
+++ b/changelogs/5.28.md
@@ -19,3 +19,9 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
## Internals
- Improved PHPStan error reporting for unsafe foreaches. Foreach on an array with implicit keys now generates different errors than foreach on an array with string keys.
+
+# 5.28.1
+Released 17th May 2025.
+
+## Fixes
+- Fixed errors when PlayStation players attempt to join due to null `TitleID`.
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index acc7db91c..7344085cf 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -32,7 +32,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.28.1";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
From 280911ec59103128b60e40a94c388fbd5907ea59 Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Sat, 17 May 2025 14:01:49 +0000
Subject: [PATCH 020/140] 5.28.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15085916916
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 7344085cf..885099701 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.28.1";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.28.2";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From a37353c0605d6b6424ffa66dd150c2b691c6a651 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 16:37:05 +0100
Subject: [PATCH 021/140] composer: fixed borked version constraints
bruhhhhhhhhhhhh
---
composer.json | 4 ++--
composer.lock | 14 +++++++-------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/composer.json b/composer.json
index 1482aa4cb..c744c320e 100644
--- a/composer.json
+++ b/composer.json
@@ -34,9 +34,9 @@
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
- "pocketmine/bedrock-data": "5.0.0+bedrock-1.21.80",
+ "pocketmine/bedrock-data": "~5.0.0+bedrock-1.21.80",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
- "pocketmine/bedrock-protocol": "38.0.0+bedrock-1.21.80",
+ "pocketmine/bedrock-protocol": "~38.0.0+bedrock-1.21.80",
"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 1326fbc9a..b82a014da 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": "b25d87be51beaaad7285a6b2e771ab4e",
+ "content-hash": "d8fa42f33a3bcb26014e6f862366dbd6",
"packages": [
{
"name": "adhocore/json-comment",
@@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "38.0.0+bedrock-1.21.80",
+ "version": "38.0.1+bedrock-1.21.80",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "a626561eaefeb6333c0d2726e2789ceb0aac0724"
+ "reference": "0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a626561eaefeb6333c0d2726e2789ceb0aac0724",
- "reference": "a626561eaefeb6333c0d2726e2789ceb0aac0724",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f",
+ "reference": "0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/38.0.0+bedrock-1.21.80"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/38.0.1+bedrock-1.21.80"
},
- "time": "2025-05-09T14:17:07+00:00"
+ "time": "2025-05-17T11:56:33+00:00"
},
{
"name": "pocketmine/binaryutils",
From 81d3017ad5e15e8f6ca846733826b47a5e90eba2 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Sat, 17 May 2025 16:44:19 +0100
Subject: [PATCH 022/140] Murphy's Law (#6698)
---
changelogs/5.28.md | 7 +++++++
src/VersionInfo.php | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/changelogs/5.28.md b/changelogs/5.28.md
index 74906ecc7..f378031f7 100644
--- a/changelogs/5.28.md
+++ b/changelogs/5.28.md
@@ -25,3 +25,10 @@ Released 17th May 2025.
## Fixes
- Fixed errors when PlayStation players attempt to join due to null `TitleID`.
+
+# 5.28.2
+Released 17th May 2025.
+
+## Fixes
+- Fixed version constraints which were incorrectly updated during the 1.21.80 update. This led to an unnoticed failure to update BedrockProtocol in the previous patch release.
+- Actually fixed PlayStation issues this time
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 885099701..aa42e2e03 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -32,7 +32,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.28.2";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
From 647c2587a8c40e641cebca331d06105e92edee8c Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Sat, 17 May 2025 15:45:22 +0000
Subject: [PATCH 023/140] 5.28.3 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15086729525
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index aa42e2e03..615024656 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.28.2";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.28.3";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From 657e6c8130154629c21e4ed9c148386ca6d3af89 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 17:24:53 +0100
Subject: [PATCH 024/140] Added trigger cron workflow for RestrictedActions
branch sync
we're having problems with the restricted action getting disabled due to repo inactivity,
so it's best we trigger it from here, since this repo's activity is what it's
interested in anyway.
---
.../workflows/branch-sync-cron-trigger.yml | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 .github/workflows/branch-sync-cron-trigger.yml
diff --git a/.github/workflows/branch-sync-cron-trigger.yml b/.github/workflows/branch-sync-cron-trigger.yml
new file mode 100644
index 000000000..145fcd222
--- /dev/null
+++ b/.github/workflows/branch-sync-cron-trigger.yml
@@ -0,0 +1,32 @@
+#Since GitHub automatically disables cron actions after 60 days of repo inactivity, we need the active repo (PM)
+#to trigger the branch merge workflow explicitly. This avoids the need for TOS-violating actions which we previously
+#used to keep the restricted action active, as the workflow depends on the activity of this repo anyway.
+
+name: Trigger branch sync
+
+on:
+ schedule:
+ - cron: "0 0 * * *" #once per day so we don't spam merge commits on busy days
+ workflow_dispatch: #for testing
+
+jobs:
+ trigger:
+ name: Trigger branch sync RestrictedActions workflow
+ runs-on: ubuntu-22.04
+
+ steps:
+ - name: Generate access token
+ id: generate-token
+ uses: actions/create-github-app-token@v2
+ with:
+ app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
+ private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
+ owner: ${{ github.repository_owner }}
+ repositories: RestrictedActions
+
+ - name: Dispatch branch sync restricted action
+ uses: peter-evans/repository-dispatch@v3
+ with:
+ token: ${{ steps.generate-token.outputs.token }}
+ repository: ${{ github.repository_owner }}/RestrictedActions
+ event-type: pocketmine_mp_branch_sync
From b5f236c019f360f0ac57aa4355810354f9ae80ac Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 18:09:14 +0100
Subject: [PATCH 025/140] Apparently we're supposed to use replace for this,
not provide
---
composer.json | 2 +-
composer.lock | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/composer.json b/composer.json
index c744c320e..979973893 100644
--- a/composer.json
+++ b/composer.json
@@ -57,7 +57,7 @@
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
},
- "provide": {
+ "replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-mbstring": "*"
},
diff --git a/composer.lock b/composer.lock
index b82a014da..9cb0721fc 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": "d8fa42f33a3bcb26014e6f862366dbd6",
+ "content-hash": "ceb98091ac3f61f1a4b87708c48dc75a",
"packages": [
{
"name": "adhocore/json-comment",
From 94fb5d95b92604840dabb719f04327efa559cf94 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 17 May 2025 19:09:54 +0100
Subject: [PATCH 026/140] CommonThreadPartsTrait: fixed thread crashes
sometimes missing cause info closes #6669
this happens because isTerminated returns true before the thread's shutdown handler runs,
so we join with the thread to make sure that shutdown handlers are done before returning.
... hopefully we don't get servers randomly deadlocking in shutdown handlers ???
---
src/thread/CommonThreadPartsTrait.php | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/thread/CommonThreadPartsTrait.php b/src/thread/CommonThreadPartsTrait.php
index e1c9d7c6b..de606a7b2 100644
--- a/src/thread/CommonThreadPartsTrait.php
+++ b/src/thread/CommonThreadPartsTrait.php
@@ -94,7 +94,17 @@ trait CommonThreadPartsTrait{
}
}
- public function getCrashInfo() : ?ThreadCrashInfo{ return $this->crashInfo; }
+ public function getCrashInfo() : ?ThreadCrashInfo{
+ //TODO: Joining a crashed worker might be a bit sus, but we need to make sure the thread's shutdown
+ //handler has run before we try to collect the crash info. As of 6.1.1, pmmpthread sets isTerminated=true
+ //*before* the shutdown handler is invoked, so we might land here before the crash info has been set.
+ //In the future this should probably be fixed by running the shutdown handlers before setting isTerminated,
+ //but this workaround should be good enough for now.
+ if($this->isTerminated() && !$this->isJoined()){
+ $this->join();
+ }
+ return $this->crashInfo;
+ }
public function start(int $options = NativeThread::INHERIT_NONE) : bool{
ThreadManager::getInstance()->add($this);
From 9606c0e0bbe054061714e48503d993a9aa8ca7b5 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Fri, 23 May 2025 22:16:57 +0100
Subject: [PATCH 027/140] Remove stale labels as well as Waiting on Author
labels
actions/stale is far too slow to do this itself since it processes lots of irrelevant crap on every run
---
.github/workflows/pr-remove-waiting-label.yml | 32 +++++++++++--------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/.github/workflows/pr-remove-waiting-label.yml b/.github/workflows/pr-remove-waiting-label.yml
index eb46043bd..da14e36ba 100644
--- a/.github/workflows/pr-remove-waiting-label.yml
+++ b/.github/workflows/pr-remove-waiting-label.yml
@@ -15,19 +15,23 @@ jobs:
with:
github-token: ${{ github.token }}
script: |
- const [owner, repo] = context.payload.repository.full_name.split('/');
- try {
- await github.rest.issues.removeLabel({
- owner: owner,
- repo: repo,
- issue_number: context.payload.number,
- name: "Status: Waiting on Author",
- });
- } catch (error) {
- if (error.status === 404) {
- //probably label wasn't set on the issue
- console.log('Failed to remove label (probably label isn\'t on the PR): ' + error.message);
- } else {
- throw error;
+ function removeLabel(owner, repo, issue_number, name) {
+ try {
+ await github.rest.issues.removeLabel({
+ owner: owner,
+ repo: repo,
+ issue_number: issue_number,
+ name: name,
+ });
+ } catch (error) {
+ if (error.status === 404) {
+ //probably label wasn't set on the issue
+ console.log('Failed to remove label ' + name + ' (probably label isn\'t on the PR): ' + error.message);
+ } else {
+ throw error;
+ }
}
}
+ const [owner, repo] = context.payload.repository.full_name.split('/');
+ removeLabel(owner, repo, context.payload.number, "Status: Waiting on Author");
+ removeLabel(owner, repo, context.payload.number, "Stale");
From 3636173d75d7b97414c86d7c6f32bade005185e9 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Fri, 23 May 2025 23:28:15 +0100
Subject: [PATCH 028/140] ...
---
.github/workflows/pr-remove-waiting-label.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr-remove-waiting-label.yml b/.github/workflows/pr-remove-waiting-label.yml
index da14e36ba..b7cd85acd 100644
--- a/.github/workflows/pr-remove-waiting-label.yml
+++ b/.github/workflows/pr-remove-waiting-label.yml
@@ -15,7 +15,7 @@ jobs:
with:
github-token: ${{ github.token }}
script: |
- function removeLabel(owner, repo, issue_number, name) {
+ async function removeLabel(owner, repo, issue_number, name) {
try {
await github.rest.issues.removeLabel({
owner: owner,
From e1af2a4af11abf148eb38c4b5d5e05c257fb124b Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 24 May 2025 16:19:48 +0100
Subject: [PATCH 029/140] Update language dependency
---
composer.json | 2 +-
composer.lock | 14 +++++++-------
src/lang/KnownTranslationFactory.php | 8 ++++++++
src/lang/KnownTranslationKeys.php | 2 ++
4 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/composer.json b/composer.json
index 979973893..a3b2fb6bd 100644
--- a/composer.json
+++ b/composer.json
@@ -41,7 +41,7 @@
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.7.0",
- "pocketmine/locale-data": "~2.24.0",
+ "pocketmine/locale-data": "~2.25.0",
"pocketmine/log": "^0.4.0",
"pocketmine/math": "~1.0.0",
"pocketmine/nbt": "~1.1.0",
diff --git a/composer.lock b/composer.lock
index 9cb0721fc..ef41f04cd 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": "ceb98091ac3f61f1a4b87708c48dc75a",
+ "content-hash": "b106b34fbd6c8abdfd45931bcb18bb69",
"packages": [
{
"name": "adhocore/json-comment",
@@ -471,16 +471,16 @@
},
{
"name": "pocketmine/locale-data",
- "version": "2.24.2",
+ "version": "2.25.1",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
- "reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b"
+ "reference": "8e6514f5a9638e69cdc2219c775fc7d3bb4c9fdd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/Language/zipball/2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
- "reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
+ "url": "https://api.github.com/repos/pmmp/Language/zipball/8e6514f5a9638e69cdc2219c775fc7d3bb4c9fdd",
+ "reference": "8e6514f5a9638e69cdc2219c775fc7d3bb4c9fdd",
"shasum": ""
},
"type": "library",
@@ -488,9 +488,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
- "source": "https://github.com/pmmp/Language/tree/2.24.2"
+ "source": "https://github.com/pmmp/Language/tree/2.25.1"
},
- "time": "2025-04-03T01:23:27+00:00"
+ "time": "2025-04-16T11:15:32+00:00"
},
{
"name": "pocketmine/log",
diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php
index 4e42419ea..eadd74f32 100644
--- a/src/lang/KnownTranslationFactory.php
+++ b/src/lang/KnownTranslationFactory.php
@@ -3035,6 +3035,14 @@ final class KnownTranslationFactory{
return new Translatable(KnownTranslationKeys::TILE_BED_TOOFAR, []);
}
+ public static function tile_respawn_anchor_notValid() : Translatable{
+ return new Translatable(KnownTranslationKeys::TILE_RESPAWN_ANCHOR_NOTVALID, []);
+ }
+
+ public static function tile_respawn_anchor_respawnSet() : Translatable{
+ return new Translatable(KnownTranslationKeys::TILE_RESPAWN_ANCHOR_RESPAWNSET, []);
+ }
+
public static function view_distance() : Translatable{
return new Translatable(KnownTranslationKeys::VIEW_DISTANCE, []);
}
diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php
index 6fbb32ecb..44a64c489 100644
--- a/src/lang/KnownTranslationKeys.php
+++ b/src/lang/KnownTranslationKeys.php
@@ -658,6 +658,8 @@ final class KnownTranslationKeys{
public const TILE_BED_NOSLEEP = "tile.bed.noSleep";
public const TILE_BED_OCCUPIED = "tile.bed.occupied";
public const TILE_BED_TOOFAR = "tile.bed.tooFar";
+ public const TILE_RESPAWN_ANCHOR_NOTVALID = "tile.respawn_anchor.notValid";
+ public const TILE_RESPAWN_ANCHOR_RESPAWNSET = "tile.respawn_anchor.respawnSet";
public const VIEW_DISTANCE = "view_distance";
public const WELCOME_TO_POCKETMINE = "welcome_to_pocketmine";
public const WHITELIST_ENABLE = "whitelist_enable";
From 4d5c27a7343fe78bfff901f2b911fc877581862e Mon Sep 17 00:00:00 2001
From: ipad54 <63200545+ipad54@users.noreply.github.com>
Date: Sat, 24 May 2025 23:01:36 +0300
Subject: [PATCH 030/140] Unit test block hardness & blast resistance values
(#6629)
---
src/block/BlockBreakInfo.php | 2 +-
src/block/VanillaBlocks.php | 171 +++++++++++++++---------------
tests/phpunit/block/BlockTest.php | 55 ++++++++++
3 files changed, 144 insertions(+), 84 deletions(-)
diff --git a/src/block/BlockBreakInfo.php b/src/block/BlockBreakInfo.php
index e77e06cfd..3d45caf3c 100644
--- a/src/block/BlockBreakInfo.php
+++ b/src/block/BlockBreakInfo.php
@@ -73,7 +73,7 @@ class BlockBreakInfo{
return new self(0.0, $toolType, $toolHarvestLevel, 0.0);
}
- public static function indestructible(float $blastResistance = 18000000.0) : self{
+ public static function indestructible(float $blastResistance = 18000003.75) : self{
return new self(-1.0, BlockToolType::NONE, 0, $blastResistance);
}
diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php
index 231004dfa..0a6d4b31c 100644
--- a/src/block/VanillaBlocks.php
+++ b/src/block/VanillaBlocks.php
@@ -859,7 +859,7 @@ final class VanillaBlocks{
$railBreakInfo = new Info(new BreakInfo(0.7));
self::register("activator_rail", fn(BID $id) => new ActivatorRail($id, "Activator Rail", $railBreakInfo));
self::register("anvil", fn(BID $id) => new Anvil($id, "Anvil", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD, 6000.0))));
- self::register("bamboo", fn(BID $id) => new Bamboo($id, "Bamboo", new Info(new class(2.0 /* 1.0 in PC */, ToolType::AXE) extends BreakInfo{
+ self::register("bamboo", fn(BID $id) => new Bamboo($id, "Bamboo", new Info(new class(1.0, ToolType::AXE) extends BreakInfo{
public function getBreakTime(Item $item) : float{
if($item->getBlockToolType() === ToolType::SWORD){
return 0.0;
@@ -867,7 +867,7 @@ final class VanillaBlocks{
return parent::getBreakTime($item);
}
}, [Tags::POTTABLE_PLANTS])));
- self::register("bamboo_sapling", fn(BID $id) => new BambooSapling($id, "Bamboo Sapling", new Info(BreakInfo::instant())));
+ self::register("bamboo_sapling", fn(BID $id) => new BambooSapling($id, "Bamboo Sapling", new Info(new BreakInfo(1.0))));
$bannerBreakInfo = new Info(BreakInfo::axe(1.0));
self::register("banner", fn(BID $id) => new FloorBanner($id, "Banner", $bannerBreakInfo), TileBanner::class);
@@ -876,7 +876,7 @@ final class VanillaBlocks{
self::register("barrier", fn(BID $id) => new Transparent($id, "Barrier", new Info(BreakInfo::indestructible())));
self::register("beacon", fn(BID $id) => new Beacon($id, "Beacon", new Info(new BreakInfo(3.0))), TileBeacon::class);
self::register("bed", fn(BID $id) => new Bed($id, "Bed Block", new Info(new BreakInfo(0.2))), TileBed::class);
- self::register("bedrock", fn(BID $id) => new Bedrock($id, "Bedrock", new Info(BreakInfo::indestructible())));
+ self::register("bedrock", fn(BID $id) => new Bedrock($id, "Bedrock", new Info(BreakInfo::indestructible(18000000.0))));
self::register("beetroots", fn(BID $id) => new Beetroot($id, "Beetroot Block", new Info(BreakInfo::instant())));
self::register("bell", fn(BID $id) => new Bell($id, "Bell", new Info(BreakInfo::pickaxe(5.0))), TileBell::class);
@@ -913,7 +913,7 @@ final class VanillaBlocks{
self::register("cobweb", fn(BID $id) => new Cobweb($id, "Cobweb", new Info(new BreakInfo(4.0, ToolType::SWORD | ToolType::SHEARS, 1))));
self::register("cocoa_pod", fn(BID $id) => new CocoaBlock($id, "Cocoa Block", new Info(BreakInfo::axe(0.2, null, 15.0))));
- self::register("coral_block", fn(BID $id) => new CoralBlock($id, "Coral Block", new Info(BreakInfo::pickaxe(7.0, ToolTier::WOOD))));
+ self::register("coral_block", fn(BID $id) => new CoralBlock($id, "Coral Block", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0))));
self::register("daylight_sensor", fn(BID $id) => new DaylightSensor($id, "Daylight Sensor", new Info(BreakInfo::axe(0.2))), TileDaylightSensor::class);
self::register("dead_bush", fn(BID $id) => new DeadBush($id, "Dead Bush", new Info(BreakInfo::instant(ToolType::SHEARS, 1), [Tags::POTTABLE_PLANTS])));
self::register("detector_rail", fn(BID $id) => new DetectorRail($id, "Detector Rail", $railBreakInfo));
@@ -930,15 +930,15 @@ final class VanillaBlocks{
self::register("pitcher_plant", fn(BID $id) => new DoublePlant($id, "Pitcher Plant", new Info(BreakInfo::instant())));
self::register("pitcher_crop", fn(BID $id) => new PitcherCrop($id, "Pitcher Crop", new Info(BreakInfo::instant())));
self::register("double_pitcher_crop", fn(BID $id) => new DoublePitcherCrop($id, "Double Pitcher Crop", new Info(BreakInfo::instant())));
- self::register("dragon_egg", fn(BID $id) => new DragonEgg($id, "Dragon Egg", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD))));
+ self::register("dragon_egg", fn(BID $id) => new DragonEgg($id, "Dragon Egg", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, blastResistance: 45.0))));
self::register("dried_kelp", fn(BID $id) => new DriedKelp($id, "Dried Kelp Block", new Info(new BreakInfo(0.5, ToolType::NONE, 0, 12.5))));
self::register("emerald", fn(BID $id) => new Opaque($id, "Emerald Block", new Info(BreakInfo::pickaxe(5.0, ToolTier::IRON, 30.0))));
self::register("enchanting_table", fn(BID $id) => new EnchantingTable($id, "Enchanting Table", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD, 6000.0))), TileEnchantingTable::class);
- self::register("end_portal_frame", fn(BID $id) => new EndPortalFrame($id, "End Portal Frame", new Info(BreakInfo::indestructible())));
+ self::register("end_portal_frame", fn(BID $id) => new EndPortalFrame($id, "End Portal Frame", new Info(BreakInfo::indestructible(18000000.0))));
self::register("end_rod", fn(BID $id) => new EndRod($id, "End Rod", new Info(BreakInfo::instant())));
self::register("end_stone", fn(BID $id) => new Opaque($id, "End Stone", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, 45.0))));
- $endBrickBreakInfo = new Info(BreakInfo::pickaxe(0.8, ToolTier::WOOD, 4.0));
+ $endBrickBreakInfo = new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, 45.0));
self::register("end_stone_bricks", fn(BID $id) => new Opaque($id, "End Stone Bricks", $endBrickBreakInfo));
self::register("end_stone_brick_stairs", fn(BID $id) => new Stair($id, "End Stone Brick Stairs", $endBrickBreakInfo));
@@ -962,7 +962,7 @@ final class VanillaBlocks{
self::register("torchflower", fn(BID $id) => new Flower($id, "Torchflower", $flowerTypeInfo));
self::register("torchflower_crop", fn(BID $id) => new TorchflowerCrop($id, "Torchflower Crop", new Info(BreakInfo::instant())));
self::register("flower_pot", fn(BID $id) => new FlowerPot($id, "Flower Pot", new Info(BreakInfo::instant())), TileFlowerPot::class);
- self::register("frosted_ice", fn(BID $id) => new FrostedIce($id, "Frosted Ice", new Info(BreakInfo::pickaxe(2.5))));
+ self::register("frosted_ice", fn(BID $id) => new FrostedIce($id, "Frosted Ice", new Info(BreakInfo::pickaxe(0.5))));
self::register("furnace", fn(BID $id) => new Furnace($id, "Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD)), FurnaceType::FURNACE), TileNormalFurnace::class);
self::register("blast_furnace", fn(BID $id) => new Furnace($id, "Blast Furnace", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD)), FurnaceType::BLAST_FURNACE), TileBlastFurnace::class);
self::register("smoker", fn(BID $id) => new Furnace($id, "Smoker", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD)), FurnaceType::SMOKER), TileSmoker::class);
@@ -970,30 +970,28 @@ final class VanillaBlocks{
$glassBreakInfo = new Info(new BreakInfo(0.3));
self::register("glass", fn(BID $id) => new Glass($id, "Glass", $glassBreakInfo));
self::register("glass_pane", fn(BID $id) => new GlassPane($id, "Glass Pane", $glassBreakInfo));
- self::register("glowing_obsidian", fn(BID $id) => new GlowingObsidian($id, "Glowing Obsidian", new Info(BreakInfo::pickaxe(10.0, ToolTier::DIAMOND, 50.0))));
+ self::register("glowing_obsidian", fn(BID $id) => new GlowingObsidian($id, "Glowing Obsidian", new Info(BreakInfo::pickaxe(35.0, ToolTier::DIAMOND, 6000.0))));
self::register("glowstone", fn(BID $id) => new Glowstone($id, "Glowstone", new Info(BreakInfo::pickaxe(0.3))));
- self::register("glow_lichen", fn(BID $id) => new GlowLichen($id, "Glow Lichen", new Info(BreakInfo::axe(0.2, null, 0.2))));
+ self::register("glow_lichen", fn(BID $id) => new GlowLichen($id, "Glow Lichen", new Info(BreakInfo::axe(0.2))));
self::register("gold", fn(BID $id) => new Opaque($id, "Gold Block", new Info(BreakInfo::pickaxe(3.0, ToolTier::IRON, 30.0))));
- $grassBreakInfo = BreakInfo::shovel(0.6);
- self::register("grass", fn(BID $id) => new Grass($id, "Grass", new Info($grassBreakInfo, [Tags::DIRT])));
- self::register("grass_path", fn(BID $id) => new GrassPath($id, "Grass Path", new Info($grassBreakInfo)));
+ self::register("grass", fn(BID $id) => new Grass($id, "Grass", new Info(BreakInfo::shovel(0.6), [Tags::DIRT])));
+ self::register("grass_path", fn(BID $id) => new GrassPath($id, "Grass Path", new Info(BreakInfo::shovel(0.65))));
self::register("gravel", fn(BID $id) => new Gravel($id, "Gravel", new Info(BreakInfo::shovel(0.6))));
- $hardenedClayBreakInfo = new Info(BreakInfo::pickaxe(1.25, ToolTier::WOOD, 21.0));
- self::register("hardened_clay", fn(BID $id) => new HardenedClay($id, "Hardened Clay", $hardenedClayBreakInfo));
+ self::register("hardened_clay", fn(BID $id) => new HardenedClay($id, "Hardened Clay", new Info(BreakInfo::pickaxe(1.25, ToolTier::WOOD, 21.0))));
$hardenedGlassBreakInfo = new Info(new BreakInfo(10.0));
self::register("hardened_glass", fn(BID $id) => new HardenedGlass($id, "Hardened Glass", $hardenedGlassBreakInfo));
self::register("hardened_glass_pane", fn(BID $id) => new HardenedGlassPane($id, "Hardened Glass Pane", $hardenedGlassBreakInfo));
self::register("hay_bale", fn(BID $id) => new HayBale($id, "Hay Bale", new Info(new BreakInfo(0.5))));
- self::register("hopper", fn(BID $id) => new Hopper($id, "Hopper", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, 15.0))), TileHopper::class);
+ self::register("hopper", fn(BID $id) => new Hopper($id, "Hopper", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, 24.0))), TileHopper::class);
self::register("ice", fn(BID $id) => new Ice($id, "Ice", new Info(BreakInfo::pickaxe(0.5))));
$updateBlockBreakInfo = new Info(new BreakInfo(1.0));
self::register("info_update", fn(BID $id) => new Opaque($id, "update!", $updateBlockBreakInfo));
self::register("info_update2", fn(BID $id) => new Opaque($id, "ate!upd", $updateBlockBreakInfo));
- self::register("invisible_bedrock", fn(BID $id) => new Transparent($id, "Invisible Bedrock", new Info(BreakInfo::indestructible())));
+ self::register("invisible_bedrock", fn(BID $id) => new Transparent($id, "Invisible Bedrock", new Info(BreakInfo::indestructible(18000000.0))));
$ironBreakInfo = new Info(BreakInfo::pickaxe(5.0, ToolTier::STONE, 30.0));
self::register("iron", fn(BID $id) => new Opaque($id, "Iron Block", $ironBreakInfo));
@@ -1006,16 +1004,16 @@ final class VanillaBlocks{
self::register("item_frame", fn(BID $id) => new ItemFrame($id, "Item Frame", $itemFrameInfo), TileItemFrame::class);
self::register("glowing_item_frame", fn(BID $id) => new ItemFrame($id, "Glow Item Frame", $itemFrameInfo), TileGlowingItemFrame::class);
- self::register("jukebox", fn(BID $id) => new Jukebox($id, "Jukebox", new Info(BreakInfo::axe(0.8))), TileJukebox::class); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
+ self::register("jukebox", fn(BID $id) => new Jukebox($id, "Jukebox", new Info(BreakInfo::axe(2.0, blastResistance: 30.0))), TileJukebox::class);
self::register("ladder", fn(BID $id) => new Ladder($id, "Ladder", new Info(BreakInfo::axe(0.4))));
- $lanternBreakInfo = new Info(BreakInfo::pickaxe(5.0));
+ $lanternBreakInfo = new Info(BreakInfo::pickaxe(3.5));
self::register("lantern", fn(BID $id) => new Lantern($id, "Lantern", $lanternBreakInfo, 15));
self::register("soul_lantern", fn(BID $id) => new Lantern($id, "Soul Lantern", $lanternBreakInfo, 10));
self::register("lapis_lazuli", fn(BID $id) => new Opaque($id, "Lapis Lazuli Block", new Info(BreakInfo::pickaxe(3.0, ToolTier::STONE))));
self::register("lava", fn(BID $id) => new Lava($id, "Lava", new Info(BreakInfo::indestructible(500.0))));
- self::register("lectern", fn(BID $id) => new Lectern($id, "Lectern", new Info(BreakInfo::axe(2.0))), TileLectern::class);
+ self::register("lectern", fn(BID $id) => new Lectern($id, "Lectern", new Info(BreakInfo::axe(2.5))), TileLectern::class);
self::register("lever", fn(BID $id) => new Lever($id, "Lever", new Info(new BreakInfo(0.5))));
self::register("magma", fn(BID $id) => new Magma($id, "Magma Block", new Info(BreakInfo::pickaxe(0.5, ToolTier::WOOD))));
self::register("melon", fn(BID $id) => new Melon($id, "Melon Block", new Info(BreakInfo::axe(1.0))));
@@ -1065,14 +1063,15 @@ final class VanillaBlocks{
self::register("purpur_stairs", fn(BID $id) => new Stair($id, "Purpur Stairs", $purpurBreakInfo));
$quartzBreakInfo = new Info(BreakInfo::pickaxe(0.8, ToolTier::WOOD));
+ $smoothQuartzBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
self::register("quartz", fn(BID $id) => new Opaque($id, "Quartz Block", $quartzBreakInfo));
self::register("chiseled_quartz", fn(BID $id) => new SimplePillar($id, "Chiseled Quartz Block", $quartzBreakInfo));
self::register("quartz_pillar", fn(BID $id) => new SimplePillar($id, "Quartz Pillar", $quartzBreakInfo));
- self::register("smooth_quartz", fn(BID $id) => new Opaque($id, "Smooth Quartz Block", $quartzBreakInfo));
+ self::register("smooth_quartz", fn(BID $id) => new Opaque($id, "Smooth Quartz Block", $smoothQuartzBreakInfo));
self::register("quartz_bricks", fn(BID $id) => new Opaque($id, "Quartz Bricks", $quartzBreakInfo));
self::register("quartz_stairs", fn(BID $id) => new Stair($id, "Quartz Stairs", $quartzBreakInfo));
- self::register("smooth_quartz_stairs", fn(BID $id) => new Stair($id, "Smooth Quartz Stairs", $quartzBreakInfo));
+ self::register("smooth_quartz_stairs", fn(BID $id) => new Stair($id, "Smooth Quartz Stairs", $smoothQuartzBreakInfo));
self::register("rail", fn(BID $id) => new Rail($id, "Rail", $railBreakInfo));
self::register("red_mushroom", fn(BID $id) => new RedMushroom($id, "Red Mushroom", new Info(BreakInfo::instant(), [Tags::POTTABLE_PLANTS])));
@@ -1127,13 +1126,13 @@ final class VanillaBlocks{
$infestedStoneBreakInfo = new Info(BreakInfo::pickaxe(0.75));
self::register("infested_stone", fn(BID $id) => new InfestedStone($id, "Infested Stone", $infestedStoneBreakInfo, $stone));
self::register("infested_stone_brick", fn(BID $id) => new InfestedStone($id, "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick));
- self::register("infested_cobblestone", fn(BID $id) => new InfestedStone($id, "Infested Cobblestone", $infestedStoneBreakInfo, $cobblestone));
+ self::register("infested_cobblestone", fn(BID $id) => new InfestedStone($id, "Infested Cobblestone", new Info(BreakInfo::pickaxe(1.0, blastResistance: 3.75)), $cobblestone));
self::register("infested_mossy_stone_brick", fn(BID $id) => new InfestedStone($id, "Infested Mossy Stone Brick", $infestedStoneBreakInfo, $mossyStoneBrick));
self::register("infested_cracked_stone_brick", fn(BID $id) => new InfestedStone($id, "Infested Cracked Stone Brick", $infestedStoneBreakInfo, $crackedStoneBrick));
self::register("infested_chiseled_stone_brick", fn(BID $id) => new InfestedStone($id, "Infested Chiseled Stone Brick", $infestedStoneBreakInfo, $chiseledStoneBrick));
self::register("stone_stairs", fn(BID $id) => new Stair($id, "Stone Stairs", $stoneBreakInfo));
- self::register("smooth_stone", fn(BID $id) => new Opaque($id, "Smooth Stone", $stoneBreakInfo));
+ self::register("smooth_stone", fn(BID $id) => new Opaque($id, "Smooth Stone", new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0))));
self::register("andesite_stairs", fn(BID $id) => new Stair($id, "Andesite Stairs", $stoneBreakInfo));
self::register("diorite_stairs", fn(BID $id) => new Stair($id, "Diorite Stairs", $stoneBreakInfo));
self::register("granite_stairs", fn(BID $id) => new Stair($id, "Granite Stairs", $stoneBreakInfo));
@@ -1146,7 +1145,6 @@ final class VanillaBlocks{
self::register("stonecutter", fn(BID $id) => new Stonecutter($id, "Stonecutter", new Info(BreakInfo::pickaxe(3.5))));
self::register("stone_pressure_plate", fn(BID $id) => new StonePressurePlate($id, "Stone Pressure Plate", new Info(BreakInfo::pickaxe(0.5))));
- //TODO: in the future this won't be the same for all the types
$stoneSlabBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
self::register("brick_slab", fn(BID $id) => new Slab($id, "Brick", $stoneSlabBreakInfo));
@@ -1157,28 +1155,31 @@ final class VanillaBlocks{
self::register("sandstone_slab", fn(BID $id) => new Slab($id, "Sandstone", $stoneSlabBreakInfo));
self::register("smooth_stone_slab", fn(BID $id) => new Slab($id, "Smooth Stone", $stoneSlabBreakInfo));
self::register("stone_brick_slab", fn(BID $id) => new Slab($id, "Stone Brick", $stoneSlabBreakInfo));
- self::register("dark_prismarine_slab", fn(BID $id) => new Slab($id, "Dark Prismarine", $stoneSlabBreakInfo));
- self::register("mossy_cobblestone_slab", fn(BID $id) => new Slab($id, "Mossy Cobblestone", $stoneSlabBreakInfo));
- self::register("prismarine_slab", fn(BID $id) => new Slab($id, "Prismarine", $stoneSlabBreakInfo));
- self::register("prismarine_bricks_slab", fn(BID $id) => new Slab($id, "Prismarine Bricks", $stoneSlabBreakInfo));
- self::register("purpur_slab", fn(BID $id) => new Slab($id, "Purpur", $stoneSlabBreakInfo));
self::register("red_nether_brick_slab", fn(BID $id) => new Slab($id, "Red Nether Brick", $stoneSlabBreakInfo));
self::register("red_sandstone_slab", fn(BID $id) => new Slab($id, "Red Sandstone", $stoneSlabBreakInfo));
self::register("smooth_sandstone_slab", fn(BID $id) => new Slab($id, "Smooth Sandstone", $stoneSlabBreakInfo));
- self::register("andesite_slab", fn(BID $id) => new Slab($id, "Andesite", $stoneSlabBreakInfo));
- self::register("diorite_slab", fn(BID $id) => new Slab($id, "Diorite", $stoneSlabBreakInfo));
- self::register("end_stone_brick_slab", fn(BID $id) => new Slab($id, "End Stone Brick", $stoneSlabBreakInfo));
- self::register("granite_slab", fn(BID $id) => new Slab($id, "Granite", $stoneSlabBreakInfo));
- self::register("polished_andesite_slab", fn(BID $id) => new Slab($id, "Polished Andesite", $stoneSlabBreakInfo));
- self::register("polished_diorite_slab", fn(BID $id) => new Slab($id, "Polished Diorite", $stoneSlabBreakInfo));
- self::register("polished_granite_slab", fn(BID $id) => new Slab($id, "Polished Granite", $stoneSlabBreakInfo));
- self::register("smooth_red_sandstone_slab", fn(BID $id) => new Slab($id, "Smooth Red Sandstone", $stoneSlabBreakInfo));
self::register("cut_red_sandstone_slab", fn(BID $id) => new Slab($id, "Cut Red Sandstone", $stoneSlabBreakInfo));
self::register("cut_sandstone_slab", fn(BID $id) => new Slab($id, "Cut Sandstone", $stoneSlabBreakInfo));
- self::register("mossy_stone_brick_slab", fn(BID $id) => new Slab($id, "Mossy Stone Brick", $stoneSlabBreakInfo));
+ self::register("mossy_cobblestone_slab", fn(BID $id) => new Slab($id, "Mossy Cobblestone", $stoneSlabBreakInfo));
+ self::register("purpur_slab", fn(BID $id) => new Slab($id, "Purpur", $stoneSlabBreakInfo));
+ self::register("smooth_red_sandstone_slab", fn(BID $id) => new Slab($id, "Smooth Red Sandstone", $stoneSlabBreakInfo));
self::register("smooth_quartz_slab", fn(BID $id) => new Slab($id, "Smooth Quartz", $stoneSlabBreakInfo));
self::register("stone_slab", fn(BID $id) => new Slab($id, "Stone", $stoneSlabBreakInfo));
+ self::register("end_stone_brick_slab", fn(BID $id) => new Slab($id, "End Stone Brick", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, 30.0))));
+
+ $lightStoneSlabBreakInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0));
+ self::register("dark_prismarine_slab", fn(BID $id) => new Slab($id, "Dark Prismarine", $lightStoneSlabBreakInfo));
+ self::register("prismarine_slab", fn(BID $id) => new Slab($id, "Prismarine", $lightStoneSlabBreakInfo));
+ self::register("prismarine_bricks_slab", fn(BID $id) => new Slab($id, "Prismarine Bricks", $lightStoneSlabBreakInfo));
+ self::register("andesite_slab", fn(BID $id) => new Slab($id, "Andesite", $lightStoneSlabBreakInfo));
+ self::register("diorite_slab", fn(BID $id) => new Slab($id, "Diorite", $lightStoneSlabBreakInfo));
+ self::register("granite_slab", fn(BID $id) => new Slab($id, "Granite", $lightStoneSlabBreakInfo));
+ self::register("polished_andesite_slab", fn(BID $id) => new Slab($id, "Polished Andesite", $lightStoneSlabBreakInfo));
+ self::register("polished_diorite_slab", fn(BID $id) => new Slab($id, "Polished Diorite", $lightStoneSlabBreakInfo));
+ self::register("polished_granite_slab", fn(BID $id) => new Slab($id, "Polished Granite", $lightStoneSlabBreakInfo));
+ self::register("mossy_stone_brick_slab", fn(BID $id) => new Slab($id, "Mossy Stone Brick", $lightStoneSlabBreakInfo));
+
self::register("legacy_stonecutter", fn(BID $id) => new Opaque($id, "Legacy Stonecutter", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD))));
self::register("sugarcane", fn(BID $id) => new Sugarcane($id, "Sugarcane", new Info(BreakInfo::instant())));
self::register("sweet_berry_bush", fn(BID $id) => new SweetBerryBush($id, "Sweet Berry Bush", new Info(BreakInfo::instant())));
@@ -1237,25 +1238,26 @@ final class VanillaBlocks{
}
$sandstoneBreakInfo = new Info(BreakInfo::pickaxe(0.8, ToolTier::WOOD));
+ $smoothSandstoneBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
self::register("red_sandstone_stairs", fn(BID $id) => new Stair($id, "Red Sandstone Stairs", $sandstoneBreakInfo));
- self::register("smooth_red_sandstone_stairs", fn(BID $id) => new Stair($id, "Smooth Red Sandstone Stairs", $sandstoneBreakInfo));
+ self::register("smooth_red_sandstone_stairs", fn(BID $id) => new Stair($id, "Smooth Red Sandstone Stairs", $smoothSandstoneBreakInfo));
self::register("red_sandstone", fn(BID $id) => new Opaque($id, "Red Sandstone", $sandstoneBreakInfo));
self::register("chiseled_red_sandstone", fn(BID $id) => new Opaque($id, "Chiseled Red Sandstone", $sandstoneBreakInfo));
self::register("cut_red_sandstone", fn(BID $id) => new Opaque($id, "Cut Red Sandstone", $sandstoneBreakInfo));
- self::register("smooth_red_sandstone", fn(BID $id) => new Opaque($id, "Smooth Red Sandstone", $sandstoneBreakInfo));
+ self::register("smooth_red_sandstone", fn(BID $id) => new Opaque($id, "Smooth Red Sandstone", $smoothSandstoneBreakInfo));
self::register("sandstone_stairs", fn(BID $id) => new Stair($id, "Sandstone Stairs", $sandstoneBreakInfo));
- self::register("smooth_sandstone_stairs", fn(BID $id) => new Stair($id, "Smooth Sandstone Stairs", $sandstoneBreakInfo));
+ self::register("smooth_sandstone_stairs", fn(BID $id) => new Stair($id, "Smooth Sandstone Stairs", $smoothSandstoneBreakInfo));
self::register("sandstone", fn(BID $id) => new Opaque($id, "Sandstone", $sandstoneBreakInfo));
self::register("chiseled_sandstone", fn(BID $id) => new Opaque($id, "Chiseled Sandstone", $sandstoneBreakInfo));
self::register("cut_sandstone", fn(BID $id) => new Opaque($id, "Cut Sandstone", $sandstoneBreakInfo));
- self::register("smooth_sandstone", fn(BID $id) => new Opaque($id, "Smooth Sandstone", $sandstoneBreakInfo));
+ self::register("smooth_sandstone", fn(BID $id) => new Opaque($id, "Smooth Sandstone", $smoothSandstoneBreakInfo));
self::register("glazed_terracotta", fn(BID $id) => new GlazedTerracotta($id, "Glazed Terracotta", new Info(BreakInfo::pickaxe(1.4, ToolTier::WOOD))));
self::register("dyed_shulker_box", fn(BID $id) => new DyedShulkerBox($id, "Dyed Shulker Box", $shulkerBoxBreakInfo), TileShulkerBox::class);
self::register("stained_glass", fn(BID $id) => new StainedGlass($id, "Stained Glass", $glassBreakInfo));
self::register("stained_glass_pane", fn(BID $id) => new StainedGlassPane($id, "Stained Glass Pane", $glassBreakInfo));
- self::register("stained_clay", fn(BID $id) => new StainedHardenedClay($id, "Stained Clay", $hardenedClayBreakInfo));
+ self::register("stained_clay", fn(BID $id) => new StainedHardenedClay($id, "Stained Clay", new Info(BreakInfo::pickaxe(1.25, ToolTier::WOOD, 6.25))));
self::register("stained_hardened_glass", fn(BID $id) => new StainedHardenedGlass($id, "Stained Hardened Glass", $hardenedGlassBreakInfo));
self::register("stained_hardened_glass_pane", fn(BID $id) => new StainedHardenedGlassPane($id, "Stained Hardened Glass Pane", $hardenedGlassBreakInfo));
self::register("carpet", fn(BID $id) => new Carpet($id, "Carpet", new Info(new BreakInfo(0.1))));
@@ -1272,22 +1274,26 @@ final class VanillaBlocks{
}
})));
- //TODO: in the future these won't all have the same hardness; they only do now because of the old metadata crap
- $wallBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
- self::register("cobblestone_wall", fn(BID $id) => new Wall($id, "Cobblestone Wall", $wallBreakInfo));
- self::register("andesite_wall", fn(BID $id) => new Wall($id, "Andesite Wall", $wallBreakInfo));
- self::register("brick_wall", fn(BID $id) => new Wall($id, "Brick Wall", $wallBreakInfo));
- self::register("diorite_wall", fn(BID $id) => new Wall($id, "Diorite Wall", $wallBreakInfo));
- self::register("end_stone_brick_wall", fn(BID $id) => new Wall($id, "End Stone Brick Wall", $wallBreakInfo));
- self::register("granite_wall", fn(BID $id) => new Wall($id, "Granite Wall", $wallBreakInfo));
- self::register("mossy_stone_brick_wall", fn(BID $id) => new Wall($id, "Mossy Stone Brick Wall", $wallBreakInfo));
- self::register("mossy_cobblestone_wall", fn(BID $id) => new Wall($id, "Mossy Cobblestone Wall", $wallBreakInfo));
- self::register("nether_brick_wall", fn(BID $id) => new Wall($id, "Nether Brick Wall", $wallBreakInfo));
- self::register("prismarine_wall", fn(BID $id) => new Wall($id, "Prismarine Wall", $wallBreakInfo));
- self::register("red_nether_brick_wall", fn(BID $id) => new Wall($id, "Red Nether Brick Wall", $wallBreakInfo));
- self::register("red_sandstone_wall", fn(BID $id) => new Wall($id, "Red Sandstone Wall", $wallBreakInfo));
- self::register("sandstone_wall", fn(BID $id) => new Wall($id, "Sandstone Wall", $wallBreakInfo));
- self::register("stone_brick_wall", fn(BID $id) => new Wall($id, "Stone Brick Wall", $wallBreakInfo));
+ self::register("end_stone_brick_wall", fn(BID $id) => new Wall($id, "End Stone Brick Wall", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD, 45.0))));
+
+ $brickWallBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
+ self::register("cobblestone_wall", fn(BID $id) => new Wall($id, "Cobblestone Wall", $brickWallBreakInfo));
+ self::register("brick_wall", fn(BID $id) => new Wall($id, "Brick Wall", $brickWallBreakInfo));
+ self::register("mossy_cobblestone_wall", fn(BID $id) => new Wall($id, "Mossy Cobblestone Wall", $brickWallBreakInfo));
+ self::register("nether_brick_wall", fn(BID $id) => new Wall($id, "Nether Brick Wall", $brickWallBreakInfo));
+ self::register("red_nether_brick_wall", fn(BID $id) => new Wall($id, "Red Nether Brick Wall", $brickWallBreakInfo));
+
+ $stoneWallBreakInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0));
+ self::register("stone_brick_wall", fn(BID $id) => new Wall($id, "Stone Brick Wall", $stoneWallBreakInfo));
+ self::register("mossy_stone_brick_wall", fn(BID $id) => new Wall($id, "Mossy Stone Brick Wall", $stoneWallBreakInfo));
+ self::register("granite_wall", fn(BID $id) => new Wall($id, "Granite Wall", $stoneWallBreakInfo));
+ self::register("diorite_wall", fn(BID $id) => new Wall($id, "Diorite Wall", $stoneWallBreakInfo));
+ self::register("andesite_wall", fn(BID $id) => new Wall($id, "Andesite Wall", $stoneWallBreakInfo));
+ self::register("prismarine_wall", fn(BID $id) => new Wall($id, "Prismarine Wall", $stoneWallBreakInfo));
+
+ $sandstoneWallBreakInfo = new Info(BreakInfo::pickaxe(0.8, ToolTier::WOOD, 4.0));
+ self::register("red_sandstone_wall", fn(BID $id) => new Wall($id, "Red Sandstone Wall", $sandstoneWallBreakInfo));
+ self::register("sandstone_wall", fn(BID $id) => new Wall($id, "Sandstone Wall", $sandstoneWallBreakInfo));
self::registerElements();
@@ -1320,8 +1326,8 @@ final class VanillaBlocks{
self::register("mangrove_roots", fn(BID $id) => new MangroveRoots($id, "Mangrove Roots", new Info(BreakInfo::axe(0.7))));
self::register("muddy_mangrove_roots", fn(BID $id) => new SimplePillar($id, "Muddy Mangrove Roots", new Info(BreakInfo::shovel(0.7), [Tags::MUD])));
self::register("froglight", fn(BID $id) => new Froglight($id, "Froglight", new Info(new BreakInfo(0.3))));
- self::register("sculk", fn(BID $id) => new Sculk($id, "Sculk", new Info(new BreakInfo(0.6, ToolType::HOE))));
- self::register("reinforced_deepslate", fn(BID $id) => new class($id, "Reinforced Deepslate", new Info(new BreakInfo(55.0, ToolType::NONE, 0, 3600.0))) extends Opaque{
+ self::register("sculk", fn(BID $id) => new Sculk($id, "Sculk", new Info(new BreakInfo(0.2, ToolType::HOE))));
+ self::register("reinforced_deepslate", fn(BID $id) => new class($id, "Reinforced Deepslate", new Info(new BreakInfo(55.0, ToolType::NONE, 0, 6000.0))) extends Opaque{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
@@ -1537,7 +1543,7 @@ final class VanillaBlocks{
self::register("lapis_lazuli_ore", fn(BID $id) => new LapisOre($id, "Lapis Lazuli Ore", $stoneOreBreakInfo(ToolTier::STONE)));
self::register("redstone_ore", fn(BID $id) => new RedstoneOre($id, "Redstone Ore", $stoneOreBreakInfo(ToolTier::IRON)));
- $deepslateOreBreakInfo = fn(ToolTier $toolTier) => new Info(BreakInfo::pickaxe(4.5, $toolTier));
+ $deepslateOreBreakInfo = fn(ToolTier $toolTier) => new Info(BreakInfo::pickaxe(4.5, $toolTier, 15.0));
self::register("deepslate_coal_ore", fn(BID $id) => new CoalOre($id, "Deepslate Coal Ore", $deepslateOreBreakInfo(ToolTier::WOOD)));
self::register("deepslate_copper_ore", fn(BID $id) => new CopperOre($id, "Deepslate Copper Ore", $deepslateOreBreakInfo(ToolTier::STONE)));
self::register("deepslate_diamond_ore", fn(BID $id) => new DiamondOre($id, "Deepslate Diamond Ore", $deepslateOreBreakInfo(ToolTier::IRON)));
@@ -1581,10 +1587,10 @@ final class VanillaBlocks{
//for some reason, slabs have weird hardness like the legacy ones
$slabBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
- self::register("ancient_debris", fn(BID $id) => new class($id, "Ancient Debris", new Info(BreakInfo::pickaxe(30, ToolTier::DIAMOND, 3600.0))) extends Opaque{
+ self::register("ancient_debris", fn(BID $id) => new class($id, "Ancient Debris", new Info(BreakInfo::pickaxe(30, ToolTier::DIAMOND, 6000.0))) extends Opaque{
public function isFireProofAsItem() : bool{ return true; }
});
- $netheriteBreakInfo = new Info(BreakInfo::pickaxe(50, ToolTier::DIAMOND, 3600.0));
+ $netheriteBreakInfo = new Info(BreakInfo::pickaxe(50, ToolTier::DIAMOND, 6000.0));
self::register("netherite", fn(BID $id) => new class($id, "Netherite Block", $netheriteBreakInfo) extends Opaque{
public function isFireProofAsItem() : bool{ return true; }
});
@@ -1602,14 +1608,14 @@ final class VanillaBlocks{
self::register("gilded_blackstone", fn(BID $id) => new GildedBlackstone($id, "Gilded Blackstone", $blackstoneBreakInfo));
- //TODO: polished blackstone ought to have 2.0 hardness (as per java) but it's 1.5 in Bedrock (probably parity bug)
+ $polishedBlackstoneBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
$prefix = fn(string $thing) => "Polished Blackstone" . ($thing !== "" ? " $thing" : "");
- self::register("polished_blackstone", fn(BID $id) => new Opaque($id, $prefix(""), $blackstoneBreakInfo));
+ self::register("polished_blackstone", fn(BID $id) => new Opaque($id, $prefix(""), $polishedBlackstoneBreakInfo));
self::register("polished_blackstone_button", fn(BID $id) => new StoneButton($id, $prefix("Button"), new Info(BreakInfo::pickaxe(0.5))));
self::register("polished_blackstone_pressure_plate", fn(BID $id) => new StonePressurePlate($id, $prefix("Pressure Plate"), new Info(BreakInfo::pickaxe(0.5)), 20));
self::register("polished_blackstone_slab", fn(BID $id) => new Slab($id, $prefix(""), $slabBreakInfo));
- self::register("polished_blackstone_stairs", fn(BID $id) => new Stair($id, $prefix("Stairs"), $blackstoneBreakInfo));
- self::register("polished_blackstone_wall", fn(BID $id) => new Wall($id, $prefix("Wall"), $blackstoneBreakInfo));
+ self::register("polished_blackstone_stairs", fn(BID $id) => new Stair($id, $prefix("Stairs"), $polishedBlackstoneBreakInfo));
+ self::register("polished_blackstone_wall", fn(BID $id) => new Wall($id, $prefix("Wall"), $polishedBlackstoneBreakInfo));
self::register("chiseled_polished_blackstone", fn(BID $id) => new Opaque($id, "Chiseled Polished Blackstone", $blackstoneBreakInfo));
$prefix = fn(string $thing) => "Polished Blackstone Brick" . ($thing !== "" ? " $thing" : "");
@@ -1622,8 +1628,7 @@ final class VanillaBlocks{
self::register("soul_torch", fn(BID $id) => new Torch($id, "Soul Torch", new Info(BreakInfo::instant())));
self::register("soul_fire", fn(BID $id) => new SoulFire($id, "Soul Fire", new Info(BreakInfo::instant(), [Tags::FIRE])));
- //TODO: soul soul ought to have 0.5 hardness (as per java) but it's 1.0 in Bedrock (probably parity bug)
- self::register("soul_soil", fn(BID $id) => new Opaque($id, "Soul Soil", new Info(BreakInfo::shovel(1.0))));
+ self::register("soul_soil", fn(BID $id) => new Opaque($id, "Soul Soil", new Info(BreakInfo::shovel(0.5))));
self::register("shroomlight", fn(BID $id) => new class($id, "Shroomlight", new Info(new BreakInfo(1.0, ToolType::HOE))) extends Opaque{
public function getLightLevel() : int{ return 15; }
@@ -1641,7 +1646,7 @@ final class VanillaBlocks{
self::register("crimson_roots", fn(BID $id) => new NetherRoots($id, "Crimson Roots", $netherRootsInfo));
self::register("warped_roots", fn(BID $id) => new NetherRoots($id, "Warped Roots", $netherRootsInfo));
- self::register("chain", fn(BID $id) => new Chain($id, "Chain", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD))));
+ self::register("chain", fn(BID $id) => new Chain($id, "Chain", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD, 30.0))));
}
private static function registerBlocksR17() : void{
@@ -1659,7 +1664,7 @@ final class VanillaBlocks{
self::register("raw_gold", fn(BID $id) => new Opaque($id, "Raw Gold Block", new Info(BreakInfo::pickaxe(5, ToolTier::IRON, 30.0))));
self::register("raw_iron", fn(BID $id) => new Opaque($id, "Raw Iron Block", new Info(BreakInfo::pickaxe(5, ToolTier::STONE, 30.0))));
- $deepslateBreakInfo = new Info(BreakInfo::pickaxe(3, ToolTier::WOOD, 18.0));
+ $deepslateBreakInfo = new Info(BreakInfo::pickaxe(3, ToolTier::WOOD, 30.0));
self::register("deepslate", fn(BID $id) => new class($id, "Deepslate", $deepslateBreakInfo) extends SimplePillar{
public function getDropsForCompatibleTool(Item $item) : array{
return [VanillaBlocks::COBBLED_DEEPSLATE()->asItem()];
@@ -1671,29 +1676,29 @@ final class VanillaBlocks{
});
//TODO: parity issue here - in Java this has a hardness of 3.0, but in bedrock it's 3.5
- self::register("chiseled_deepslate", fn(BID $id) => new Opaque($id, "Chiseled Deepslate", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 18.0))));
+ self::register("chiseled_deepslate", fn(BID $id) => new Opaque($id, "Chiseled Deepslate", new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 30.0))));
- $deepslateBrickBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 18.0));
+ $deepslateBrickBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 30.0));
self::register("deepslate_bricks", fn(BID $id) => new Opaque($id, "Deepslate Bricks", $deepslateBrickBreakInfo));
self::register("deepslate_brick_slab", fn(BID $id) => new Slab($id, "Deepslate Brick", $deepslateBrickBreakInfo));
self::register("deepslate_brick_stairs", fn(BID $id) => new Stair($id, "Deepslate Brick Stairs", $deepslateBrickBreakInfo));
self::register("deepslate_brick_wall", fn(BID $id) => new Wall($id, "Deepslate Brick Wall", $deepslateBrickBreakInfo));
self::register("cracked_deepslate_bricks", fn(BID $id) => new Opaque($id, "Cracked Deepslate Bricks", $deepslateBrickBreakInfo));
- $deepslateTilesBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 18.0));
+ $deepslateTilesBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 30.0));
self::register("deepslate_tiles", fn(BID $id) => new Opaque($id, "Deepslate Tiles", $deepslateTilesBreakInfo));
self::register("deepslate_tile_slab", fn(BID $id) => new Slab($id, "Deepslate Tile", $deepslateTilesBreakInfo));
self::register("deepslate_tile_stairs", fn(BID $id) => new Stair($id, "Deepslate Tile Stairs", $deepslateTilesBreakInfo));
self::register("deepslate_tile_wall", fn(BID $id) => new Wall($id, "Deepslate Tile Wall", $deepslateTilesBreakInfo));
self::register("cracked_deepslate_tiles", fn(BID $id) => new Opaque($id, "Cracked Deepslate Tiles", $deepslateTilesBreakInfo));
- $cobbledDeepslateBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 18.0));
+ $cobbledDeepslateBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 30.0));
self::register("cobbled_deepslate", fn(BID $id) => new Opaque($id, "Cobbled Deepslate", $cobbledDeepslateBreakInfo));
self::register("cobbled_deepslate_slab", fn(BID $id) => new Slab($id, "Cobbled Deepslate", $cobbledDeepslateBreakInfo));
self::register("cobbled_deepslate_stairs", fn(BID $id) => new Stair($id, "Cobbled Deepslate Stairs", $cobbledDeepslateBreakInfo));
self::register("cobbled_deepslate_wall", fn(BID $id) => new Wall($id, "Cobbled Deepslate Wall", $cobbledDeepslateBreakInfo));
- $polishedDeepslateBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 18.0));
+ $polishedDeepslateBreakInfo = new Info(BreakInfo::pickaxe(3.5, ToolTier::WOOD, 30.0));
self::register("polished_deepslate", fn(BID $id) => new Opaque($id, "Polished Deepslate", $polishedDeepslateBreakInfo));
self::register("polished_deepslate_slab", fn(BID $id) => new Slab($id, "Polished Deepslate", $polishedDeepslateBreakInfo));
self::register("polished_deepslate_stairs", fn(BID $id) => new Stair($id, "Polished Deepslate Stairs", $polishedDeepslateBreakInfo));
@@ -1702,7 +1707,7 @@ final class VanillaBlocks{
self::register("tinted_glass", fn(BID $id) => new TintedGlass($id, "Tinted Glass", new Info(new BreakInfo(0.3))));
//blast resistance should be 30 if we were matched with java :(
- $copperBreakInfo = new Info(BreakInfo::pickaxe(3.0, ToolTier::STONE, 18.0));
+ $copperBreakInfo = new Info(BreakInfo::pickaxe(3.0, ToolTier::STONE, 30.0));
self::register("lightning_rod", fn(BID $id) => new LightningRod($id, "Lightning Rod", $copperBreakInfo));
self::register("copper", fn(BID $id) => new Copper($id, "Copper Block", $copperBreakInfo));
@@ -1730,8 +1735,8 @@ final class VanillaBlocks{
self::register("cave_vines", fn(BID $id) => new CaveVines($id, "Cave Vines", new Info(BreakInfo::instant())));
self::register("small_dripleaf", fn(BID $id) => new SmallDripleaf($id, "Small Dripleaf", new Info(BreakInfo::instant(ToolType::SHEARS, toolHarvestLevel: 1))));
- self::register("big_dripleaf_head", fn(BID $id) => new BigDripleafHead($id, "Big Dripleaf", new Info(BreakInfo::instant())));
- self::register("big_dripleaf_stem", fn(BID $id) => new BigDripleafStem($id, "Big Dripleaf Stem", new Info(BreakInfo::instant())));
+ self::register("big_dripleaf_head", fn(BID $id) => new BigDripleafHead($id, "Big Dripleaf", new Info(new BreakInfo(0.1))));
+ self::register("big_dripleaf_stem", fn(BID $id) => new BigDripleafStem($id, "Big Dripleaf Stem", new Info(new BreakInfo(0.1))));
}
private static function registerBlocksR18() : void{
@@ -1742,7 +1747,7 @@ final class VanillaBlocks{
self::register("mud", fn(BID $id) => new Opaque($id, "Mud", new Info(BreakInfo::shovel(0.5), [Tags::MUD])));
self::register("packed_mud", fn(BID $id) => new Opaque($id, "Packed Mud", new Info(BreakInfo::pickaxe(1.0, null, 15.0))));
- $mudBricksBreakInfo = new Info(BreakInfo::pickaxe(2.0, ToolTier::WOOD, 30.0));
+ $mudBricksBreakInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 15.0));
self::register("mud_bricks", fn(BID $id) => new Opaque($id, "Mud Bricks", $mudBricksBreakInfo));
self::register("mud_brick_slab", fn(BID $id) => new Slab($id, "Mud Brick", $mudBricksBreakInfo));
@@ -1754,7 +1759,7 @@ final class VanillaBlocks{
self::register("resin", fn(BID $id) => new Opaque($id, "Block of Resin", new Info(BreakInfo::instant())));
self::register("resin_clump", fn(BID $id) => new ResinClump($id, "Resin Clump", new Info(BreakInfo::instant())));
- $resinBricksInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD));
+ $resinBricksInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0));
self::register("resin_brick_slab", fn(BID $id) => new Slab($id, "Resin Brick", $resinBricksInfo));
self::register("resin_brick_stairs", fn(BID $id) => new Stair($id, "Resin Brick Stairs", $resinBricksInfo));
self::register("resin_brick_wall", fn(BID $id) => new Wall($id, "Resin Brick Wall", $resinBricksInfo));
diff --git a/tests/phpunit/block/BlockTest.php b/tests/phpunit/block/BlockTest.php
index 971564720..138a3e4e8 100644
--- a/tests/phpunit/block/BlockTest.php
+++ b/tests/phpunit/block/BlockTest.php
@@ -24,16 +24,22 @@ declare(strict_types=1);
namespace pocketmine\block;
use PHPUnit\Framework\TestCase;
+use pocketmine\data\bedrock\BedrockDataFiles;
+use pocketmine\data\bedrock\block\BlockTypeNames;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils;
+use pocketmine\world\format\io\GlobalBlockStateHandlers;
+use function array_fill_keys;
use function get_debug_type;
use function implode;
use function is_array;
+use function is_float;
use function is_int;
use function is_string;
use function json_decode;
use function log;
+use function round;
use const JSON_THROW_ON_ERROR;
class BlockTest extends TestCase{
@@ -95,6 +101,55 @@ class BlockTest extends TestCase{
}
}
+ public function testBlockBreakInfo() : void{
+ $propertiesTable = json_decode(Filesystem::fileGetContents(BedrockDataFiles::BLOCK_PROPERTIES_TABLE_JSON), true, 3, JSON_THROW_ON_ERROR);
+ if(!is_array($propertiesTable)){
+ throw new AssumptionFailedError("Block properties table must be an array");
+ }
+ $exceptions = array_fill_keys([
+ BlockTypeNames::AIR,
+ BlockTypeNames::WATER,
+ BlockTypeNames::FLOWING_WATER,
+ BlockTypeNames::LAVA,
+ BlockTypeNames::FLOWING_LAVA,
+ BlockTypeNames::MANGROVE_LOG, //For some reason ONLY this wood block has blast resistance 2 instead of 10...
+ ], true);
+
+ $serializer = GlobalBlockStateHandlers::getSerializer();
+ $testedBlocks = [];
+ $hardnessErrors = [];
+ $blastResistanceErrors = [];
+ foreach($this->blockFactory->getAllKnownStates() as $block){
+ $vanillaId = $serializer->serializeBlock($block)->getName();
+ if(isset($exceptions[$vanillaId]) || isset($testedBlocks[$vanillaId])){
+ continue;
+ }
+ if(!isset($propertiesTable[$vanillaId]) || !is_array($propertiesTable[$vanillaId])){
+ throw new AssumptionFailedError("$vanillaId does not exist in the vanilla block properties table or is not an array");
+ }
+ if(!isset($propertiesTable[$vanillaId]["hardness"]) || !is_float($propertiesTable[$vanillaId]["hardness"])){
+ throw new AssumptionFailedError("Hardness property is missing for $vanillaId or is not a float value");
+ }
+ if(!isset($propertiesTable[$vanillaId]["blastResistance"]) || !is_float($propertiesTable[$vanillaId]["blastResistance"])){
+ throw new AssumptionFailedError("Blast resistance property is missing for $vanillaId or is not a float value");
+ }
+ $testedBlocks[$vanillaId] = true;
+
+ $vanillaHardness = round($propertiesTable[$vanillaId]["hardness"], 5);
+ $vanillaBlastResistance = round($propertiesTable[$vanillaId]["blastResistance"], 5) * 5;
+
+ $breakInfo = $block->getBreakInfo();
+ if($breakInfo->getHardness() !== $vanillaHardness){
+ $hardnessErrors[] = "Hardness mismatch for $vanillaId (expected: $vanillaHardness, got " . $breakInfo->getHardness() . ")";
+ }
+ if($breakInfo->getBlastResistance() !== $vanillaBlastResistance){
+ $blastResistanceErrors[] = "Blast resistance mismatch for $vanillaId (expected: $vanillaBlastResistance, got " . $breakInfo->getBlastResistance() . ")";
+ }
+ }
+ self::assertEmpty($hardnessErrors, "Block hardness test failed:\n" . implode("\n", $hardnessErrors));
+ self::assertEmpty($blastResistanceErrors, "Block blast resistance test failed:\n" . implode("\n", $blastResistanceErrors));
+ }
+
/**
* @return int[][]|string[][]
* @phpstan-return array{array, array}
From eee2e62d81b6aeec02e668b2f36680bffdf39af7 Mon Sep 17 00:00:00 2001
From: zSALLAZAR <59490940+zSALLAZAR@users.noreply.github.com>
Date: Sun, 25 May 2025 10:01:46 +0200
Subject: [PATCH 031/140] Add EntityFrostWalkerEvent (#6673)
---
src/entity/Living.php | 20 ++++-
src/event/entity/EntityFrostWalkerEvent.php | 84 +++++++++++++++++++++
2 files changed, 100 insertions(+), 4 deletions(-)
create mode 100644 src/event/entity/EntityFrostWalkerEvent.php
diff --git a/src/entity/Living.php b/src/entity/Living.php
index 852344784..6d62c85d2 100644
--- a/src/entity/Living.php
+++ b/src/entity/Living.php
@@ -38,6 +38,7 @@ use pocketmine\event\entity\EntityDamageByChildEntityEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDeathEvent;
+use pocketmine\event\entity\EntityFrostWalkerEvent;
use pocketmine\inventory\ArmorInventory;
use pocketmine\inventory\CallbackInventoryListener;
use pocketmine\inventory\Inventory;
@@ -721,19 +722,30 @@ abstract class Living extends Entity{
$y = $this->location->getFloorY() - 1;
$baseZ = $this->location->getFloorZ();
- $frostedIce = VanillaBlocks::FROSTED_ICE();
+ $liquid = VanillaBlocks::WATER();
+ $targetBlock = VanillaBlocks::FROSTED_ICE();
+ if(EntityFrostWalkerEvent::hasHandlers()){
+ $ev = new EntityFrostWalkerEvent($this, $radius, $liquid, $targetBlock);
+ $ev->call();
+ if($ev->isCancelled()){
+ return;
+ }
+ $radius = $ev->getRadius();
+ $liquid = $ev->getLiquid();
+ $targetBlock = $ev->getTargetBlock();
+ }
+
for($x = $baseX - $radius; $x <= $baseX + $radius; $x++){
for($z = $baseZ - $radius; $z <= $baseZ + $radius; $z++){
$block = $world->getBlockAt($x, $y, $z);
if(
- !$block instanceof Water ||
- !$block->isSource() ||
+ !$block->isSameState($liquid) ||
$world->getBlockAt($x, $y + 1, $z)->getTypeId() !== BlockTypeIds::AIR ||
count($world->getNearbyEntities(AxisAlignedBB::one()->offset($x, $y, $z))) !== 0
){
continue;
}
- $world->setBlockAt($x, $y, $z, $frostedIce);
+ $world->setBlockAt($x, $y, $z, $targetBlock);
}
}
}
diff --git a/src/event/entity/EntityFrostWalkerEvent.php b/src/event/entity/EntityFrostWalkerEvent.php
new file mode 100644
index 000000000..15ba28268
--- /dev/null
+++ b/src/event/entity/EntityFrostWalkerEvent.php
@@ -0,0 +1,84 @@
+
+ */
+class EntityFrostWalkerEvent extends EntityEvent implements Cancellable{
+ use CancellableTrait;
+
+ public function __construct(
+ Living $entity,
+ private int $radius,
+ private Liquid $liquid,
+ private Block $targetBlock
+ ){
+ $this->entity = $entity;
+ }
+
+ public function getRadius() : int{
+ return $this->radius;
+ }
+
+ public function setRadius(int $radius) : void{
+ $this->radius = $radius;
+ }
+
+ /**
+ * Returns the liquid that gets frozen
+ */
+ public function getLiquid() : Liquid{
+ return $this->liquid;
+ }
+
+ /**
+ * Sets the liquid that gets frozen
+ */
+ public function setLiquid(Liquid $liquid) : void{
+ $this->liquid = $liquid;
+ }
+
+ /**
+ * Returns the block that replaces the liquid
+ */
+ public function getTargetBlock() : Block{
+ return $this->targetBlock;
+ }
+
+ /**
+ * Sets the block that replaces the liquid
+ */
+ public function setTargetBlock(Block $targetBlock) : void{
+ $this->targetBlock = $targetBlock;
+ }
+}
From 18b6b1742cd39e3a23fa590d8dc64d2dd94bacc0 Mon Sep 17 00:00:00 2001
From: zSALLAZAR <59490940+zSALLAZAR@users.noreply.github.com>
Date: Sun, 25 May 2025 10:04:33 +0200
Subject: [PATCH 032/140] Rename `PlayerExhaustEvent` to `EntityExhaustEvent`
(#6674)
Removed the `getPlayer` function
---
src/entity/Human.php | 6 +++---
src/entity/HungerManager.php | 10 +++++-----
src/entity/effect/HungerEffect.php | 4 ++--
.../EntityExhaustEvent.php} | 20 ++++++-------------
src/player/Player.php | 12 +++++------
5 files changed, 22 insertions(+), 30 deletions(-)
rename src/event/{player/PlayerExhaustEvent.php => entity/EntityExhaustEvent.php} (82%)
diff --git a/src/entity/Human.php b/src/entity/Human.php
index 1bed6d0a1..fd3287cdf 100644
--- a/src/entity/Human.php
+++ b/src/entity/Human.php
@@ -30,7 +30,7 @@ use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\effect\VanillaEffects;
use pocketmine\entity\projectile\ProjectileSource;
use pocketmine\event\entity\EntityDamageEvent;
-use pocketmine\event\player\PlayerExhaustEvent;
+use pocketmine\event\entity\EntityExhaustEvent;
use pocketmine\inventory\CallbackInventoryListener;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\InventoryHolder;
@@ -173,9 +173,9 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
public function jump() : void{
parent::jump();
if($this->isSprinting()){
- $this->hungerManager->exhaust(0.2, PlayerExhaustEvent::CAUSE_SPRINT_JUMPING);
+ $this->hungerManager->exhaust(0.2, EntityExhaustEvent::CAUSE_SPRINT_JUMPING);
}else{
- $this->hungerManager->exhaust(0.05, PlayerExhaustEvent::CAUSE_JUMPING);
+ $this->hungerManager->exhaust(0.05, EntityExhaustEvent::CAUSE_JUMPING);
}
}
diff --git a/src/entity/HungerManager.php b/src/entity/HungerManager.php
index 7e3b40e74..3167eaec0 100644
--- a/src/entity/HungerManager.php
+++ b/src/entity/HungerManager.php
@@ -24,8 +24,8 @@ declare(strict_types=1);
namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageEvent;
+use pocketmine\event\entity\EntityExhaustEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
-use pocketmine\event\player\PlayerExhaustEvent;
use pocketmine\world\World;
use function max;
use function min;
@@ -130,13 +130,13 @@ class HungerManager{
*
* @return float the amount of exhaustion level increased
*/
- public function exhaust(float $amount, int $cause = PlayerExhaustEvent::CAUSE_CUSTOM) : float{
+ public function exhaust(float $amount, int $cause = EntityExhaustEvent::CAUSE_CUSTOM) : float{
if(!$this->enabled){
return 0;
}
$evAmount = $amount;
- if(PlayerExhaustEvent::hasHandlers()){
- $ev = new PlayerExhaustEvent($this->entity, $amount, $cause);
+ if(EntityExhaustEvent::hasHandlers()){
+ $ev = new EntityExhaustEvent($this->entity, $amount, $cause);
$ev->call();
if($ev->isCancelled()){
return 0.0;
@@ -205,7 +205,7 @@ class HungerManager{
if($food >= 18){
if($health < $this->entity->getMaxHealth()){
$this->entity->heal(new EntityRegainHealthEvent($this->entity, 1, EntityRegainHealthEvent::CAUSE_SATURATION));
- $this->exhaust(6.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN);
+ $this->exhaust(6.0, EntityExhaustEvent::CAUSE_HEALTH_REGEN);
}
}elseif($food <= 0){
if(($difficulty === World::DIFFICULTY_EASY && $health > 10) || ($difficulty === World::DIFFICULTY_NORMAL && $health > 1) || $difficulty === World::DIFFICULTY_HARD){
diff --git a/src/entity/effect/HungerEffect.php b/src/entity/effect/HungerEffect.php
index 949b148bc..5ce85dfe8 100644
--- a/src/entity/effect/HungerEffect.php
+++ b/src/entity/effect/HungerEffect.php
@@ -26,7 +26,7 @@ namespace pocketmine\entity\effect;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\entity\Living;
-use pocketmine\event\player\PlayerExhaustEvent;
+use pocketmine\event\entity\EntityExhaustEvent;
class HungerEffect extends Effect{
@@ -36,7 +36,7 @@ class HungerEffect extends Effect{
public function applyEffect(Living $entity, EffectInstance $instance, float $potency = 1.0, ?Entity $source = null) : void{
if($entity instanceof Human){
- $entity->getHungerManager()->exhaust(0.1 * $instance->getEffectLevel(), PlayerExhaustEvent::CAUSE_POTION);
+ $entity->getHungerManager()->exhaust(0.1 * $instance->getEffectLevel(), EntityExhaustEvent::CAUSE_POTION);
}
}
}
diff --git a/src/event/player/PlayerExhaustEvent.php b/src/event/entity/EntityExhaustEvent.php
similarity index 82%
rename from src/event/player/PlayerExhaustEvent.php
rename to src/event/entity/EntityExhaustEvent.php
index 9a13ff900..6a4954a21 100644
--- a/src/event/player/PlayerExhaustEvent.php
+++ b/src/event/entity/EntityExhaustEvent.php
@@ -21,17 +21,16 @@
declare(strict_types=1);
-namespace pocketmine\event\player;
+namespace pocketmine\event\entity;
-use pocketmine\entity\Human;
+use pocketmine\entity\Entity;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
-use pocketmine\event\entity\EntityEvent;
/**
- * @phpstan-extends EntityEvent
+ * @phpstan-extends EntityEvent
*/
-class PlayerExhaustEvent extends EntityEvent implements Cancellable{
+class EntityExhaustEvent extends EntityEvent implements Cancellable{
use CancellableTrait;
public const CAUSE_ATTACK = 1;
@@ -47,18 +46,11 @@ class PlayerExhaustEvent extends EntityEvent implements Cancellable{
public const CAUSE_CUSTOM = 11;
public function __construct(
- protected Human $human,
+ Entity $entity,
private float $amount,
private int $cause
){
- $this->entity = $human;
- }
-
- /**
- * @return Human
- */
- public function getPlayer(){
- return $this->human;
+ $this->entity = $entity;
}
public function getAmount() : float{
diff --git a/src/player/Player.php b/src/player/Player.php
index ff8a67c94..056a628e3 100644
--- a/src/player/Player.php
+++ b/src/player/Player.php
@@ -46,6 +46,7 @@ use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\Skin;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
+use pocketmine\event\entity\EntityExhaustEvent;
use pocketmine\event\entity\EntityExtinguishEvent;
use pocketmine\event\inventory\InventoryCloseEvent;
use pocketmine\event\inventory\InventoryOpenEvent;
@@ -60,7 +61,6 @@ use pocketmine\event\player\PlayerDropItemEvent;
use pocketmine\event\player\PlayerEmoteEvent;
use pocketmine\event\player\PlayerEntityInteractEvent;
use pocketmine\event\player\PlayerEntityPickEvent;
-use pocketmine\event\player\PlayerExhaustEvent;
use pocketmine\event\player\PlayerGameModeChangeEvent;
use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\event\player\PlayerItemConsumeEvent;
@@ -1442,9 +1442,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
if($horizontalDistanceTravelled > 0){
//TODO: check for swimming
if($this->isSprinting()){
- $this->hungerManager->exhaust(0.01 * $horizontalDistanceTravelled, PlayerExhaustEvent::CAUSE_SPRINTING);
+ $this->hungerManager->exhaust(0.01 * $horizontalDistanceTravelled, EntityExhaustEvent::CAUSE_SPRINTING);
}else{
- $this->hungerManager->exhaust(0.0, PlayerExhaustEvent::CAUSE_WALKING);
+ $this->hungerManager->exhaust(0.0, EntityExhaustEvent::CAUSE_WALKING);
}
if($this->nextChunkOrderRun > 20){
@@ -1910,7 +1910,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$returnedItems = [];
if($this->getWorld()->useBreakOn($pos, $item, $this, true, $returnedItems)){
$this->returnItemsFromAction($oldItem, $item, $returnedItems);
- $this->hungerManager->exhaust(0.005, PlayerExhaustEvent::CAUSE_MINING);
+ $this->hungerManager->exhaust(0.005, EntityExhaustEvent::CAUSE_MINING);
return true;
}
}else{
@@ -2013,7 +2013,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$heldItem->onAttackEntity($entity, $returnedItems);
$this->returnItemsFromAction($oldItem, $heldItem, $returnedItems);
- $this->hungerManager->exhaust(0.1, PlayerExhaustEvent::CAUSE_ATTACK);
+ $this->hungerManager->exhaust(0.1, EntityExhaustEvent::CAUSE_ATTACK);
}
return true;
@@ -2584,7 +2584,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
protected function applyPostDamageEffects(EntityDamageEvent $source) : void{
parent::applyPostDamageEffects($source);
- $this->hungerManager->exhaust(0.1, PlayerExhaustEvent::CAUSE_DAMAGE);
+ $this->hungerManager->exhaust(0.1, EntityExhaustEvent::CAUSE_DAMAGE);
}
public function attack(EntityDamageEvent $source) : void{
From 5527a0c6bf4343b39cd6ed4526f75539ac6ddf19 Mon Sep 17 00:00:00 2001
From: ItzxDwi <107537435+ItzxDwi@users.noreply.github.com>
Date: Sun, 25 May 2025 16:07:41 +0800
Subject: [PATCH 033/140] Entity: make stepHeight accessable (#6702)
---
src/entity/Entity.php | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/src/entity/Entity.php b/src/entity/Entity.php
index 6681558ad..eb7098f1e 100644
--- a/src/entity/Entity.php
+++ b/src/entity/Entity.php
@@ -1187,12 +1187,14 @@ abstract class Entity{
$moveBB->offset(0, 0, $dz);
- if($this->stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
+ $stepHeight = $this->getStepHeight();
+
+ if($stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
$cx = $dx;
$cy = $dy;
$cz = $dz;
$dx = $wantedX;
- $dy = $this->stepHeight;
+ $dy = $stepHeight;
$dz = $wantedZ;
$stepBB = clone $this->boundingBox;
@@ -1262,6 +1264,14 @@ abstract class Entity{
Timings::$entityMove->stopTiming();
}
+ public function setStepHeight(float $stepHeight) : void{
+ $this->stepHeight = $stepHeight;
+ }
+
+ public function getStepHeight() : float{
+ return $this->stepHeight;
+ }
+
protected function checkGroundState(float $wantedX, float $wantedY, float $wantedZ, float $dx, float $dy, float $dz) : void{
$this->isCollidedVertically = $wantedY !== $dy;
$this->isCollidedHorizontally = ($wantedX !== $dx || $wantedZ !== $dz);
From 05eda887b11313b1db42224e8386504338da703f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o?= <57811430+SmallkingDev@users.noreply.github.com>
Date: Sun, 25 May 2025 09:35:26 +0100
Subject: [PATCH 034/140] Item: make setter methods fluent (#6678)
- `Item::clearCustomBlockData` previously, the instance was returned, but the return type has been changed
- `Item::setCanPlaceOn`, `Item::setCanDestroy` and `Item::setKeepOnDeath` now return `$this`
---
src/item/Item.php | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/item/Item.php b/src/item/Item.php
index 205f15e13..8f8623c79 100644
--- a/src/item/Item.php
+++ b/src/item/Item.php
@@ -125,7 +125,7 @@ class Item implements \JsonSerializable{
/**
* @return $this
*/
- public function clearCustomBlockData(){
+ public function clearCustomBlockData() : Item{
$this->blockEntityTag = null;
return $this;
}
@@ -202,11 +202,12 @@ class Item implements \JsonSerializable{
/**
* @param string[] $canPlaceOn
*/
- public function setCanPlaceOn(array $canPlaceOn) : void{
+ public function setCanPlaceOn(array $canPlaceOn) : Item{
$this->canPlaceOn = [];
foreach($canPlaceOn as $value){
$this->canPlaceOn[$value] = $value;
}
+ return $this;
}
/**
@@ -220,11 +221,12 @@ class Item implements \JsonSerializable{
/**
* @param string[] $canDestroy
*/
- public function setCanDestroy(array $canDestroy) : void{
+ public function setCanDestroy(array $canDestroy) : Item{
$this->canDestroy = [];
foreach($canDestroy as $value){
$this->canDestroy[$value] = $value;
}
+ return $this;
}
/**
@@ -234,8 +236,9 @@ class Item implements \JsonSerializable{
return $this->keepOnDeath;
}
- public function setKeepOnDeath(bool $keepOnDeath) : void{
+ public function setKeepOnDeath(bool $keepOnDeath) : Item{
$this->keepOnDeath = $keepOnDeath;
+ return $this;
}
/**
From a554d2acf5db00f577493517e36bb3ad07a6bdd0 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 25 May 2025 11:32:20 +0100
Subject: [PATCH 035/140] Revert change that can't go on stable
API additions need to wait for the next minor release
Revert "Entity: make stepHeight accessable (#6702)"
This reverts commit 5527a0c6bf4343b39cd6ed4526f75539ac6ddf19.
---
src/entity/Entity.php | 14 ++------------
1 file changed, 2 insertions(+), 12 deletions(-)
diff --git a/src/entity/Entity.php b/src/entity/Entity.php
index eb7098f1e..6681558ad 100644
--- a/src/entity/Entity.php
+++ b/src/entity/Entity.php
@@ -1187,14 +1187,12 @@ abstract class Entity{
$moveBB->offset(0, 0, $dz);
- $stepHeight = $this->getStepHeight();
-
- if($stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
+ if($this->stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
$cx = $dx;
$cy = $dy;
$cz = $dz;
$dx = $wantedX;
- $dy = $stepHeight;
+ $dy = $this->stepHeight;
$dz = $wantedZ;
$stepBB = clone $this->boundingBox;
@@ -1264,14 +1262,6 @@ abstract class Entity{
Timings::$entityMove->stopTiming();
}
- public function setStepHeight(float $stepHeight) : void{
- $this->stepHeight = $stepHeight;
- }
-
- public function getStepHeight() : float{
- return $this->stepHeight;
- }
-
protected function checkGroundState(float $wantedX, float $wantedY, float $wantedZ, float $dx, float $dy, float $dz) : void{
$this->isCollidedVertically = $wantedY !== $dy;
$this->isCollidedHorizontally = ($wantedX !== $dx || $wantedZ !== $dz);
From dd17adeaaf96745ff78dd39107adc9f9f9a43c6d Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 25 May 2025 11:33:47 +0100
Subject: [PATCH 036/140] Reintroduce step height additions for minor-next
Revert "Revert change that can't go on stable"
This reverts commit a554d2acf5db00f577493517e36bb3ad07a6bdd0.
---
src/entity/Entity.php | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/src/entity/Entity.php b/src/entity/Entity.php
index d73356df8..73a0b3a9c 100644
--- a/src/entity/Entity.php
+++ b/src/entity/Entity.php
@@ -1191,12 +1191,14 @@ abstract class Entity{
$moveBB->offset(0, 0, $dz);
- if($this->stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
+ $stepHeight = $this->getStepHeight();
+
+ if($stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
$cx = $dx;
$cy = $dy;
$cz = $dz;
$dx = $wantedX;
- $dy = $this->stepHeight;
+ $dy = $stepHeight;
$dz = $wantedZ;
$stepBB = clone $this->boundingBox;
@@ -1266,6 +1268,14 @@ abstract class Entity{
Timings::$entityMove->stopTiming();
}
+ public function setStepHeight(float $stepHeight) : void{
+ $this->stepHeight = $stepHeight;
+ }
+
+ public function getStepHeight() : float{
+ return $this->stepHeight;
+ }
+
protected function checkGroundState(float $wantedX, float $wantedY, float $wantedZ, float $dx, float $dy, float $dz) : void{
$this->isCollidedVertically = $wantedY !== $dy;
$this->isCollidedHorizontally = ($wantedX !== $dx || $wantedZ !== $dz);
From 059f4ee7bfb2b892dadce97fa3c54a0f680f60f9 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Tue, 27 May 2025 21:51:10 +0100
Subject: [PATCH 037/140] Extract GeneratorExecutor system from World, v2
(#6682)
- `AsyncGeneratorExecutor` class added that encapsulates the logic of generating chunks using async tasks as previously
- `GeneratorExecutor` interface added that can be implemented to provide chunks in other ways
- `SyncGeneratorExecutor` which invokes the generator directly on the main thread, useful for simple generators like `Flat` where async tasks are not needed
- Some redundant APIs were removed from `World` (these will probably come back as deprecated stubs for the remainder of 5.x, but I was having too much fun deleting code)
- Removed internal `World->registerGeneratorToWorker()` (no longer useful)
- `World` now invokes generator executor instead of posting AsyncTasks directly
- Some internal classes moved to `pocketmine\world\generator\executor` (PopulationTask excluded because plugins use it in lieu of being able to regenerate chunks
- Generators can opt into main-thread execution by setting the `$fast` parameter to `true` in `GeneratorManager::register()`
---
src/world/World.php | 74 +++++-------
src/world/generator/GeneratorManager.php | 7 +-
src/world/generator/GeneratorManagerEntry.php | 5 +-
src/world/generator/PopulationTask.php | 7 ++
.../executor/AsyncGeneratorExecutor.php | 106 ++++++++++++++++++
.../AsyncGeneratorRegisterTask.php} | 33 ++----
.../AsyncGeneratorUnregisterTask.php} | 15 +--
.../generator/executor/GeneratorExecutor.php | 38 +++++++
.../GeneratorExecutorSetupParameters.php | 50 +++++++++
.../executor/SyncGeneratorExecutor.php | 61 ++++++++++
.../ThreadLocalGeneratorContext.php | 4 +-
tests/phpstan/configs/actual-problems.neon | 12 +-
12 files changed, 318 insertions(+), 94 deletions(-)
create mode 100644 src/world/generator/executor/AsyncGeneratorExecutor.php
rename src/world/generator/{GeneratorRegisterTask.php => executor/AsyncGeneratorRegisterTask.php} (54%)
rename src/world/generator/{GeneratorUnregisterTask.php => executor/AsyncGeneratorUnregisterTask.php} (74%)
create mode 100644 src/world/generator/executor/GeneratorExecutor.php
create mode 100644 src/world/generator/executor/GeneratorExecutorSetupParameters.php
create mode 100644 src/world/generator/executor/SyncGeneratorExecutor.php
rename src/world/generator/{ => executor}/ThreadLocalGeneratorContext.php (94%)
diff --git a/src/world/World.php b/src/world/World.php
index c4d8f8671..792681a89 100644
--- a/src/world/World.php
+++ b/src/world/World.php
@@ -93,9 +93,11 @@ use pocketmine\world\format\io\GlobalBlockStateHandlers;
use pocketmine\world\format\io\WritableWorldProvider;
use pocketmine\world\format\LightArray;
use pocketmine\world\format\SubChunk;
+use pocketmine\world\generator\executor\AsyncGeneratorExecutor;
+use pocketmine\world\generator\executor\GeneratorExecutor;
+use pocketmine\world\generator\executor\GeneratorExecutorSetupParameters;
+use pocketmine\world\generator\executor\SyncGeneratorExecutor;
use pocketmine\world\generator\GeneratorManager;
-use pocketmine\world\generator\GeneratorRegisterTask;
-use pocketmine\world\generator\GeneratorUnregisterTask;
use pocketmine\world\generator\PopulationTask;
use pocketmine\world\light\BlockLightUpdate;
use pocketmine\world\light\LightPopulationTask;
@@ -336,11 +338,7 @@ class World implements ChunkManager{
*/
private array $chunkPopulationRequestQueueIndex = [];
- /**
- * @var true[]
- * @phpstan-var array
- */
- private array $generatorRegisteredWorkers = [];
+ private readonly GeneratorExecutor $generatorExecutor;
private bool $autoSave = true;
@@ -360,9 +358,6 @@ class World implements ChunkManager{
private bool $doingTick = false;
- /** @phpstan-var class-string */
- private string $generator;
-
private bool $unloaded = false;
/**
* @var \Closure[]
@@ -498,7 +493,23 @@ class World implements ChunkManager{
$generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator()) ??
throw new AssumptionFailedError("WorldManager should already have checked that the generator exists");
$generator->validateGeneratorOptions($this->provider->getWorldData()->getGeneratorOptions());
- $this->generator = $generator->getGeneratorClass();
+
+ $executorSetupParameters = new GeneratorExecutorSetupParameters(
+ worldMinY: $this->minY,
+ worldMaxY: $this->maxY,
+ generatorSeed: $this->getSeed(),
+ generatorClass: $generator->getGeneratorClass(),
+ generatorSettings: $this->provider->getWorldData()->getGeneratorOptions()
+ );
+ $this->generatorExecutor = $generator->isFast() ?
+ new SyncGeneratorExecutor($executorSetupParameters) :
+ new AsyncGeneratorExecutor(
+ $this->logger,
+ $this->workerPool,
+ $executorSetupParameters,
+ $this->worldId
+ );
+
$this->chunkPopulationRequestQueue = new \SplQueue();
$this->addOnUnloadCallback(function() : void{
$this->logger->debug("Cancelling unfulfilled generation requests");
@@ -534,17 +545,6 @@ class World implements ChunkManager{
$this->initRandomTickBlocksFromConfig($cfg);
$this->timings = new WorldTimings($this);
-
- $this->workerPool->addWorkerStartHook($workerStartHook = function(int $workerId) : void{
- if(array_key_exists($workerId, $this->generatorRegisteredWorkers)){
- $this->logger->debug("Worker $workerId with previously registered generator restarted, flagging as unregistered");
- unset($this->generatorRegisteredWorkers[$workerId]);
- }
- });
- $workerPool = $this->workerPool;
- $this->addOnUnloadCallback(static function() use ($workerPool, $workerStartHook) : void{
- $workerPool->removeWorkerStartHook($workerStartHook);
- });
}
private function initRandomTickBlocksFromConfig(ServerConfigGroup $cfg) : void{
@@ -585,21 +585,6 @@ class World implements ChunkManager{
return $this->tickRateTime;
}
- public function registerGeneratorToWorker(int $worker) : void{
- $this->logger->debug("Registering generator on worker $worker");
- $this->workerPool->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getWorldData()->getGeneratorOptions()), $worker);
- $this->generatorRegisteredWorkers[$worker] = true;
- }
-
- public function unregisterGenerator() : void{
- foreach($this->workerPool->getRunningWorkers() as $i){
- if(isset($this->generatorRegisteredWorkers[$i])){
- $this->workerPool->submitTaskToWorker(new GeneratorUnregisterTask($this), $i);
- }
- }
- $this->generatorRegisteredWorkers = [];
- }
-
public function getServer() : Server{
return $this->server;
}
@@ -657,7 +642,7 @@ class World implements ChunkManager{
$this->save();
- $this->unregisterGenerator();
+ $this->generatorExecutor->shutdown();
$this->provider->close();
$this->blockCache = [];
@@ -3486,8 +3471,8 @@ class World implements ChunkManager{
$centerChunk = $this->loadChunk($chunkX, $chunkZ);
$adjacentChunks = $this->getAdjacentChunks($chunkX, $chunkZ);
- $task = new PopulationTask(
- $this->worldId,
+
+ $this->generatorExecutor->populate(
$chunkX,
$chunkZ,
$centerChunk,
@@ -3500,15 +3485,6 @@ class World implements ChunkManager{
$this->generateChunkCallback($chunkPopulationLockId, $chunkX, $chunkZ, $centerChunk, $adjacentChunks, $temporaryChunkLoader);
}
);
- $workerId = $this->workerPool->selectWorker();
- if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){
- $this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline");
- unset($this->generatorRegisteredWorkers[$workerId]);
- }
- if(!isset($this->generatorRegisteredWorkers[$workerId])){
- $this->registerGeneratorToWorker($workerId);
- }
- $this->workerPool->submitTaskToWorker($task, $workerId);
return $resolver->getPromise();
}finally{
diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php
index 291ea91de..a1b00480e 100644
--- a/src/world/generator/GeneratorManager.php
+++ b/src/world/generator/GeneratorManager.php
@@ -50,7 +50,7 @@ final class GeneratorManager{
}catch(InvalidGeneratorOptionsException $e){
return $e;
}
- });
+ }, fast: true);
$this->addGenerator(Normal::class, "normal", fn() => null);
$this->addAlias("normal", "default");
$this->addGenerator(Nether::class, "nether", fn() => null);
@@ -62,6 +62,7 @@ final class GeneratorManager{
* @param string $name Alias for this generator type that can be written in configs
* @param \Closure $presetValidator Callback to validate generator options for new worlds
* @param bool $overwrite Whether to force overwriting any existing registered generator with the same name
+ * @param bool $fast Whether this generator is fast enough to run without async tasks
*
* @phpstan-param \Closure(string) : ?InvalidGeneratorOptionsException $presetValidator
*
@@ -69,7 +70,7 @@ final class GeneratorManager{
*
* @throws \InvalidArgumentException
*/
- public function addGenerator(string $class, string $name, \Closure $presetValidator, bool $overwrite = false) : void{
+ public function addGenerator(string $class, string $name, \Closure $presetValidator, bool $overwrite = false, bool $fast = false) : void{
Utils::testValidInstance($class, Generator::class);
$name = strtolower($name);
@@ -77,7 +78,7 @@ final class GeneratorManager{
throw new \InvalidArgumentException("Alias \"$name\" is already assigned");
}
- $this->list[$name] = new GeneratorManagerEntry($class, $presetValidator);
+ $this->list[$name] = new GeneratorManagerEntry($class, $presetValidator, $fast);
}
/**
diff --git a/src/world/generator/GeneratorManagerEntry.php b/src/world/generator/GeneratorManagerEntry.php
index 256ed27d5..942f6ee79 100644
--- a/src/world/generator/GeneratorManagerEntry.php
+++ b/src/world/generator/GeneratorManagerEntry.php
@@ -31,12 +31,15 @@ final class GeneratorManagerEntry{
*/
public function __construct(
private string $generatorClass,
- private \Closure $presetValidator
+ private \Closure $presetValidator,
+ private readonly bool $fast
){}
/** @phpstan-return class-string */
public function getGeneratorClass() : string{ return $this->generatorClass; }
+ public function isFast() : bool{ return $this->fast; }
+
/**
* @throws InvalidGeneratorOptionsException
*/
diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php
index a8366a306..971349a5b 100644
--- a/src/world/generator/PopulationTask.php
+++ b/src/world/generator/PopulationTask.php
@@ -27,11 +27,18 @@ use pocketmine\scheduler\AsyncTask;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\FastChunkSerializer;
+use pocketmine\world\generator\executor\ThreadLocalGeneratorContext;
use function array_map;
use function igbinary_serialize;
use function igbinary_unserialize;
/**
+ * @internal
+ *
+ * TODO: this should be moved to the executor namespace, but plugins have unfortunately used it directly due to the
+ * difficulty of regenerating chunks. This should be addressed in the future.
+ * For the remainder of PM5, we can't relocate this class.
+ *
* @phpstan-type OnCompletion \Closure(Chunk $centerChunk, array $adjacentChunks) : void
*/
class PopulationTask extends AsyncTask{
diff --git a/src/world/generator/executor/AsyncGeneratorExecutor.php b/src/world/generator/executor/AsyncGeneratorExecutor.php
new file mode 100644
index 000000000..d19b6e661
--- /dev/null
+++ b/src/world/generator/executor/AsyncGeneratorExecutor.php
@@ -0,0 +1,106 @@
+
+ */
+ private array $generatorRegisteredWorkers = [];
+
+ public function __construct(
+ \Logger $logger,
+ private readonly AsyncPool $workerPool,
+ private readonly GeneratorExecutorSetupParameters $setupParameters,
+ int $asyncContextId = null
+ ){
+ $this->logger = new \PrefixedLogger($logger, "AsyncGeneratorExecutor");
+
+ //TODO: we only allow setting this for PM5 because of PopulationTask uses in plugins
+ $this->asyncContextId = $asyncContextId ?? self::$nextAsyncContextId++;
+
+ $this->workerStartHook = function(int $workerId) : void{
+ if(array_key_exists($workerId, $this->generatorRegisteredWorkers)){
+ $this->logger->debug("Worker $workerId with previously registered generator restarted, flagging as unregistered");
+ unset($this->generatorRegisteredWorkers[$workerId]);
+ }
+ };
+ $this->workerPool->addWorkerStartHook($this->workerStartHook);
+ }
+
+ private function registerGeneratorToWorker(int $worker) : void{
+ $this->logger->debug("Registering generator on worker $worker");
+ $this->workerPool->submitTaskToWorker(new AsyncGeneratorRegisterTask($this->setupParameters, $this->asyncContextId), $worker);
+ $this->generatorRegisteredWorkers[$worker] = true;
+ }
+
+ private function unregisterGenerator() : void{
+ foreach($this->workerPool->getRunningWorkers() as $i){
+ if(isset($this->generatorRegisteredWorkers[$i])){
+ $this->workerPool->submitTaskToWorker(new AsyncGeneratorUnregisterTask($this->asyncContextId), $i);
+ }
+ }
+ $this->generatorRegisteredWorkers = [];
+ }
+
+ public function populate(int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks, \Closure $onCompletion) : void{
+ $task = new PopulationTask(
+ $this->asyncContextId,
+ $chunkX,
+ $chunkZ,
+ $centerChunk,
+ $adjacentChunks,
+ $onCompletion
+ );
+ $workerId = $this->workerPool->selectWorker();
+ if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){
+ $this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline");
+ unset($this->generatorRegisteredWorkers[$workerId]);
+ }
+ if(!isset($this->generatorRegisteredWorkers[$workerId])){
+ $this->registerGeneratorToWorker($workerId);
+ }
+ $this->workerPool->submitTaskToWorker($task, $workerId);
+ }
+
+ public function shutdown() : void{
+ $this->unregisterGenerator();
+ $this->workerPool->removeWorkerStartHook($this->workerStartHook);
+ }
+}
diff --git a/src/world/generator/GeneratorRegisterTask.php b/src/world/generator/executor/AsyncGeneratorRegisterTask.php
similarity index 54%
rename from src/world/generator/GeneratorRegisterTask.php
rename to src/world/generator/executor/AsyncGeneratorRegisterTask.php
index e2e773a35..5bc67834d 100644
--- a/src/world/generator/GeneratorRegisterTask.php
+++ b/src/world/generator/executor/AsyncGeneratorRegisterTask.php
@@ -21,37 +21,20 @@
declare(strict_types=1);
-namespace pocketmine\world\generator;
+namespace pocketmine\world\generator\executor;
use pocketmine\scheduler\AsyncTask;
-use pocketmine\world\World;
-class GeneratorRegisterTask extends AsyncTask{
- public int $seed;
- public int $worldId;
- public int $worldMinY;
- public int $worldMaxY;
+class AsyncGeneratorRegisterTask extends AsyncTask{
- /**
- * @phpstan-param class-string $generatorClass
- */
public function __construct(
- World $world,
- public string $generatorClass,
- public string $generatorSettings
- ){
- $this->seed = $world->getSeed();
- $this->worldId = $world->getId();
- $this->worldMinY = $world->getMinY();
- $this->worldMaxY = $world->getMaxY();
- }
+ private readonly GeneratorExecutorSetupParameters $setupParameters,
+ private readonly int $contextId
+ ){}
public function onRun() : void{
- /**
- * @var Generator $generator
- * @see Generator::__construct()
- */
- $generator = new $this->generatorClass($this->seed, $this->generatorSettings);
- ThreadLocalGeneratorContext::register(new ThreadLocalGeneratorContext($generator, $this->worldMinY, $this->worldMaxY), $this->worldId);
+ $setupParameters = $this->setupParameters;
+ $generator = $setupParameters->createGenerator();
+ ThreadLocalGeneratorContext::register(new ThreadLocalGeneratorContext($generator, $setupParameters->worldMinY, $setupParameters->worldMaxY), $this->contextId);
}
}
diff --git a/src/world/generator/GeneratorUnregisterTask.php b/src/world/generator/executor/AsyncGeneratorUnregisterTask.php
similarity index 74%
rename from src/world/generator/GeneratorUnregisterTask.php
rename to src/world/generator/executor/AsyncGeneratorUnregisterTask.php
index 41b4cd808..c771903f5 100644
--- a/src/world/generator/GeneratorUnregisterTask.php
+++ b/src/world/generator/executor/AsyncGeneratorUnregisterTask.php
@@ -21,19 +21,16 @@
declare(strict_types=1);
-namespace pocketmine\world\generator;
+namespace pocketmine\world\generator\executor;
use pocketmine\scheduler\AsyncTask;
-use pocketmine\world\World;
-class GeneratorUnregisterTask extends AsyncTask{
- public int $worldId;
-
- public function __construct(World $world){
- $this->worldId = $world->getId();
- }
+class AsyncGeneratorUnregisterTask extends AsyncTask{
+ public function __construct(
+ private readonly int $contextId
+ ){}
public function onRun() : void{
- ThreadLocalGeneratorContext::unregister($this->worldId);
+ ThreadLocalGeneratorContext::unregister($this->contextId);
}
}
diff --git a/src/world/generator/executor/GeneratorExecutor.php b/src/world/generator/executor/GeneratorExecutor.php
new file mode 100644
index 000000000..d3f62d410
--- /dev/null
+++ b/src/world/generator/executor/GeneratorExecutor.php
@@ -0,0 +1,38 @@
+ $adjacentChunks
+ * @phpstan-param \Closure(Chunk $centerChunk, array $adjacentChunks) : void $onCompletion
+ */
+ public function populate(int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks, \Closure $onCompletion) : void;
+
+ public function shutdown() : void;
+
+}
diff --git a/src/world/generator/executor/GeneratorExecutorSetupParameters.php b/src/world/generator/executor/GeneratorExecutorSetupParameters.php
new file mode 100644
index 000000000..b5fdb7bf9
--- /dev/null
+++ b/src/world/generator/executor/GeneratorExecutorSetupParameters.php
@@ -0,0 +1,50 @@
+ $generatorClass
+ */
+ public function __construct(
+ public readonly int $worldMinY,
+ public readonly int $worldMaxY,
+ public readonly int $generatorSeed,
+ public readonly string $generatorClass,
+ public readonly string $generatorSettings,
+ ){}
+
+ public function createGenerator() : Generator{
+ /**
+ * @var Generator $generator
+ * @see Generator::__construct()
+ */
+ $generator = new $this->generatorClass($this->generatorSeed, $this->generatorSettings);
+ return $generator;
+ }
+}
diff --git a/src/world/generator/executor/SyncGeneratorExecutor.php b/src/world/generator/executor/SyncGeneratorExecutor.php
new file mode 100644
index 000000000..79b5fdd00
--- /dev/null
+++ b/src/world/generator/executor/SyncGeneratorExecutor.php
@@ -0,0 +1,61 @@
+generator = $setupParameters->createGenerator();
+ $this->worldMinY = $setupParameters->worldMinY;
+ $this->worldMaxY = $setupParameters->worldMaxY;
+ }
+
+ public function populate(int $chunkX, int $chunkZ, ?Chunk $centerChunk, array $adjacentChunks, \Closure $onCompletion) : void{
+ [$centerChunk, $adjacentChunks] = PopulationUtils::populateChunkWithAdjacents(
+ $this->worldMinY,
+ $this->worldMaxY,
+ $this->generator,
+ $chunkX,
+ $chunkZ,
+ $centerChunk,
+ $adjacentChunks
+ );
+
+ $onCompletion($centerChunk, $adjacentChunks);
+ }
+
+ public function shutdown() : void{
+ //NOOP
+ }
+}
diff --git a/src/world/generator/ThreadLocalGeneratorContext.php b/src/world/generator/executor/ThreadLocalGeneratorContext.php
similarity index 94%
rename from src/world/generator/ThreadLocalGeneratorContext.php
rename to src/world/generator/executor/ThreadLocalGeneratorContext.php
index bcf99882b..bea8bb032 100644
--- a/src/world/generator/ThreadLocalGeneratorContext.php
+++ b/src/world/generator/executor/ThreadLocalGeneratorContext.php
@@ -21,7 +21,9 @@
declare(strict_types=1);
-namespace pocketmine\world\generator;
+namespace pocketmine\world\generator\executor;
+
+use pocketmine\world\generator\Generator;
/**
* Manages thread-local caches for generators and the things needed to support them
diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon
index d3adde422..2030a0dad 100644
--- a/tests/phpstan/configs/actual-problems.neon
+++ b/tests/phpstan/configs/actual-problems.neon
@@ -1272,18 +1272,18 @@ parameters:
count: 1
path: ../../../src/world/format/io/region/RegionLoader.php
- -
- message: '#^Dynamic new is not allowed\.$#'
- identifier: pocketmine.new.dynamic
- count: 1
- path: ../../../src/world/generator/GeneratorRegisterTask.php
-
-
message: '#^Method pocketmine\\world\\generator\\biome\\BiomeSelector\:\:pickBiome\(\) should return pocketmine\\world\\biome\\Biome but returns pocketmine\\world\\biome\\Biome\|null\.$#'
identifier: return.type
count: 1
path: ../../../src/world/generator/biome/BiomeSelector.php
+ -
+ message: '#^Dynamic new is not allowed\.$#'
+ identifier: pocketmine.new.dynamic
+ count: 1
+ path: ../../../src/world/generator/executor/GeneratorExecutorSetupParameters.php
+
-
message: '#^Cannot call method getBiomeId\(\) on pocketmine\\world\\format\\Chunk\|null\.$#'
identifier: method.nonObject
From bf33a625c93469b4f158e292c5868a161603daf0 Mon Sep 17 00:00:00 2001
From: Adam <116978956+b1zeyofficial@users.noreply.github.com>
Date: Wed, 28 May 2025 02:57:28 +0600
Subject: [PATCH 038/140] Implemented Respawn Anchor (#6646)
PlayerRespawnAnchorUseEvent is also added with options SET_SPAWN and EXPLODE, which allows plugins to customise the outcome of using the anchor in PM, which currently doesn't support dimensions. The event is also cancellable.
---
src/block/BlockTypeIds.php | 3 +-
src/block/RespawnAnchor.php | 123 +++++++++++++++++
src/block/VanillaBlocks.php | 3 +
.../convert/BlockObjectToStateSerializer.php | 5 +
.../BlockStateToObjectDeserializer.php | 4 +
src/entity/object/EndCrystal.php | 2 +-
src/entity/object/PrimedTNT.php | 2 +-
src/event/block/BlockExplodeEvent.php | 122 +++++++++++++++++
src/event/block/BlockPreExplodeEvent.php | 129 ++++++++++++++++++
src/event/entity/EntityExplodeEvent.php | 25 +++-
src/event/entity/EntityPreExplodeEvent.php | 50 ++++++-
.../player/PlayerRespawnAnchorUseEvent.php | 56 ++++++++
src/item/StringToItemParser.php | 1 +
src/player/Player.php | 17 +++
src/world/Explosion.php | 77 +++++++++--
src/world/sound/RespawnAnchorChargeSound.php | 35 +++++
src/world/sound/RespawnAnchorDepleteSound.php | 35 +++++
.../sound/RespawnAnchorSetSpawnSound.php | 35 +++++
.../block_factory_consistency_check.json | 1 +
19 files changed, 711 insertions(+), 14 deletions(-)
create mode 100644 src/block/RespawnAnchor.php
create mode 100644 src/event/block/BlockExplodeEvent.php
create mode 100644 src/event/block/BlockPreExplodeEvent.php
create mode 100644 src/event/player/PlayerRespawnAnchorUseEvent.php
create mode 100644 src/world/sound/RespawnAnchorChargeSound.php
create mode 100644 src/world/sound/RespawnAnchorDepleteSound.php
create mode 100644 src/world/sound/RespawnAnchorSetSpawnSound.php
diff --git a/src/block/BlockTypeIds.php b/src/block/BlockTypeIds.php
index c440cefdc..4af1894bd 100644
--- a/src/block/BlockTypeIds.php
+++ b/src/block/BlockTypeIds.php
@@ -786,8 +786,9 @@ final class BlockTypeIds{
public const RESIN_BRICKS = 10756;
public const RESIN_CLUMP = 10757;
public const CHISELED_RESIN_BRICKS = 10758;
+ public const RESPAWN_ANCHOR = 10759;
- public const FIRST_UNUSED_BLOCK_ID = 10759;
+ public const FIRST_UNUSED_BLOCK_ID = 10760;
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
diff --git a/src/block/RespawnAnchor.php b/src/block/RespawnAnchor.php
new file mode 100644
index 000000000..f702d240d
--- /dev/null
+++ b/src/block/RespawnAnchor.php
@@ -0,0 +1,123 @@
+boundedIntAuto(self::MIN_CHARGES, self::MAX_CHARGES, $this->charges);
+ }
+
+ public function getCharges() : int{
+ return $this->charges;
+ }
+
+ /** @return $this */
+ public function setCharges(int $charges) : self{
+ if($charges < self::MIN_CHARGES || $charges > self::MAX_CHARGES){
+ throw new \InvalidArgumentException("Charges must be between " . self::MIN_CHARGES . " and " . self::MAX_CHARGES . ", given: $charges");
+ }
+ $this->charges = $charges;
+ return $this;
+ }
+
+ public function getLightLevel() : int{
+ return $this->charges > 0 ? ($this->charges * 4) - 1 : 0;
+ }
+
+ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
+ if($item->getTypeId() === ItemTypeIds::fromBlockTypeId(BlockTypeIds::GLOWSTONE) && $this->charges < self::MAX_CHARGES){
+ $this->position->getWorld()->setBlock($this->position, $this->setCharges($this->charges + 1));
+ $this->position->getWorld()->addSound($this->position, new RespawnAnchorChargeSound());
+ return true;
+ }
+
+ if($this->charges > self::MIN_CHARGES){
+ if($player === null){
+ return false;
+ }
+
+ $ev = new PlayerRespawnAnchorUseEvent($player, $this, PlayerRespawnAnchorUseEvent::ACTION_EXPLODE);
+ $ev->call();
+ if($ev->isCancelled()){
+ return false;
+ }
+
+ switch($ev->getAction()){
+ case PlayerRespawnAnchorUseEvent::ACTION_EXPLODE:
+ $this->explode($player);
+ return false;
+
+ case PlayerRespawnAnchorUseEvent::ACTION_SET_SPAWN:
+ if($player->getSpawn() !== null && $player->getSpawn()->equals($this->position)){
+ return true;
+ }
+
+ $player->setSpawn($this->position);
+ $this->position->getWorld()->addSound($this->position, new RespawnAnchorSetSpawnSound());
+ $player->sendMessage(KnownTranslationFactory::tile_respawn_anchor_respawnSet()->prefix(TextFormat::GRAY));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function explode(?Player $player) : void{
+ $ev = new BlockPreExplodeEvent($this, 5, $player);
+ $ev->setIncendiary(true);
+
+ $ev->call();
+ if($ev->isCancelled()){
+ return;
+ }
+
+ $this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
+
+ $explosion = new Explosion(Position::fromObject($this->position->add(0.5, 0.5, 0.5), $this->position->getWorld()), $ev->getRadius(), $this);
+ $explosion->setFireChance($ev->getFireChance());
+
+ if($ev->isBlockBreaking()){
+ $explosion->explodeA();
+ }
+ $explosion->explodeB();
+ }
+}
diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php
index 0a6d4b31c..54ec27fc2 100644
--- a/src/block/VanillaBlocks.php
+++ b/src/block/VanillaBlocks.php
@@ -694,6 +694,7 @@ use function strtolower;
* @method static Stair RESIN_BRICK_STAIRS()
* @method static Wall RESIN_BRICK_WALL()
* @method static ResinClump RESIN_CLUMP()
+ * @method static RespawnAnchor RESPAWN_ANCHOR()
* @method static DoublePlant ROSE_BUSH()
* @method static Sand SAND()
* @method static Opaque SANDSTONE()
@@ -1647,6 +1648,8 @@ final class VanillaBlocks{
self::register("warped_roots", fn(BID $id) => new NetherRoots($id, "Warped Roots", $netherRootsInfo));
self::register("chain", fn(BID $id) => new Chain($id, "Chain", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD, 30.0))));
+
+ self::register("respawn_anchor", fn(BID $id) => new RespawnAnchor($id, "Respawn Anchor", new Info(BreakInfo::pickaxe(50.0, ToolTier::DIAMOND, 6000.0))));
}
private static function registerBlocksR17() : void{
diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
index 45784d409..27d550f13 100644
--- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
+++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
@@ -122,6 +122,7 @@ use pocketmine\block\RedstoneRepeater;
use pocketmine\block\RedstoneTorch;
use pocketmine\block\RedstoneWire;
use pocketmine\block\ResinClump;
+use pocketmine\block\RespawnAnchor;
use pocketmine\block\RuntimeBlockStateRegistry;
use pocketmine\block\Sapling;
use pocketmine\block\SeaPickle;
@@ -1754,6 +1755,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::RESIN_CLUMP)
->writeFacingFlags($block->getFaces());
});
+ $this->map(Blocks::RESPAWN_ANCHOR(), function(RespawnAnchor $block) : Writer{
+ return Writer::create(Ids::RESPAWN_ANCHOR)
+ ->writeInt(StateNames::RESPAWN_ANCHOR_CHARGE, $block->getCharges());
+ });
$this->map(Blocks::ROSE_BUSH(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::ROSE_BUSH)));
$this->mapSlab(Blocks::SANDSTONE_SLAB(), Ids::SANDSTONE_SLAB, Ids::SANDSTONE_DOUBLE_SLAB);
$this->mapStairs(Blocks::SANDSTONE_STAIRS(), Ids::SANDSTONE_STAIRS);
diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
index ed45a47d3..c55fde77a 100644
--- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
+++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
@@ -1717,6 +1717,10 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapStairs(Ids::RESIN_BRICK_STAIRS, fn() => Blocks::RESIN_BRICK_STAIRS());
$this->map(Ids::RESIN_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RESIN_BRICK_WALL(), $in));
$this->map(Ids::RESIN_CLUMP, fn(Reader $in) => Blocks::RESIN_CLUMP()->setFaces($in->readFacingFlags()));
+ $this->map(Ids::RESPAWN_ANCHOR, function(Reader $in) : Block{
+ return Blocks::RESPAWN_ANCHOR()
+ ->setCharges($in->readBoundedInt(StateNames::RESPAWN_ANCHOR_CHARGE, 0, 4));
+ });
$this->mapSlab(Ids::SANDSTONE_SLAB, Ids::SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SANDSTONE_SLAB());
$this->mapStairs(Ids::SANDSTONE_STAIRS, fn() => Blocks::SANDSTONE_STAIRS());
$this->map(Ids::SANDSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::SANDSTONE_WALL(), $in));
diff --git a/src/entity/object/EndCrystal.php b/src/entity/object/EndCrystal.php
index afaeb6769..74c7664bf 100644
--- a/src/entity/object/EndCrystal.php
+++ b/src/entity/object/EndCrystal.php
@@ -129,7 +129,7 @@ class EndCrystal extends Entity implements Explosive{
$ev = new EntityPreExplodeEvent($this, 6);
$ev->call();
if(!$ev->isCancelled()){
- $explosion = new Explosion($this->getPosition(), $ev->getRadius(), $this);
+ $explosion = new Explosion($this->getPosition(), $ev->getRadius(), $this, $ev->getFireChance());
if($ev->isBlockBreaking()){
$explosion->explodeA();
}
diff --git a/src/entity/object/PrimedTNT.php b/src/entity/object/PrimedTNT.php
index af3c97922..f3f299d70 100644
--- a/src/entity/object/PrimedTNT.php
+++ b/src/entity/object/PrimedTNT.php
@@ -121,7 +121,7 @@ class PrimedTNT extends Entity implements Explosive{
$ev->call();
if(!$ev->isCancelled()){
//TODO: deal with underwater TNT (underwater TNT treats water as if it has a blast resistance of 0)
- $explosion = new Explosion(Position::fromObject($this->location->add(0, $this->size->getHeight() / 2, 0), $this->getWorld()), $ev->getRadius(), $this);
+ $explosion = new Explosion(Position::fromObject($this->location->add(0, $this->size->getHeight() / 2, 0), $this->getWorld()), $ev->getRadius(), $this, $ev->getFireChance());
if($ev->isBlockBreaking()){
$explosion->explodeA();
}
diff --git a/src/event/block/BlockExplodeEvent.php b/src/event/block/BlockExplodeEvent.php
new file mode 100644
index 000000000..a8501d475
--- /dev/null
+++ b/src/event/block/BlockExplodeEvent.php
@@ -0,0 +1,122 @@
+ 100.0){
+ throw new \InvalidArgumentException("Yield must be in range 0.0 - 100.0");
+ }
+ }
+
+ public function getPosition() : Position{
+ return $this->position;
+ }
+
+ /**
+ * Returns the percentage chance of drops from each block destroyed by the explosion.
+ *
+ * @return float 0-100
+ */
+ public function getYield() : float{
+ return $this->yield;
+ }
+
+ /**
+ * Sets the percentage chance of drops from each block destroyed by the explosion.
+ *
+ * @param float $yield 0-100
+ */
+ public function setYield(float $yield) : void{
+ Utils::checkFloatNotInfOrNaN("yield", $yield);
+ if($yield < 0.0 || $yield > 100.0){
+ throw new \InvalidArgumentException("Yield must be in range 0.0 - 100.0");
+ }
+ $this->yield = $yield;
+ }
+
+ /**
+ * Returns a list of blocks destroyed by the explosion.
+ *
+ * @return Block[]
+ */
+ public function getAffectedBlocks() : array{
+ return $this->blocks;
+ }
+
+ /**
+ * Sets the blocks destroyed by the explosion.
+ *
+ * @param Block[] $blocks
+ */
+ public function setAffectedBlocks(array $blocks) : void{
+ Utils::validateArrayValueType($blocks, fn(Block $block) => null);
+ $this->blocks = $blocks;
+ }
+
+ /**
+ * Returns a list of affected blocks that will be replaced by fire.
+ *
+ * @return Block[]
+ */
+ public function getIgnitions() : array{
+ return $this->ignitions;
+ }
+
+ /**
+ * Set the list of blocks that will be replaced by fire.
+ *
+ * @param Block[] $ignitions
+ */
+ public function setIgnitions(array $ignitions) : void{
+ Utils::validateArrayValueType($ignitions, fn(Block $block) => null);
+ $this->ignitions = $ignitions;
+ }
+}
diff --git a/src/event/block/BlockPreExplodeEvent.php b/src/event/block/BlockPreExplodeEvent.php
new file mode 100644
index 000000000..f41cb8a63
--- /dev/null
+++ b/src/event/block/BlockPreExplodeEvent.php
@@ -0,0 +1,129 @@
+ 1.0){
+ throw new \InvalidArgumentException("Fire chance must be a number between 0 and 1.");
+ }
+ parent::__construct($block);
+ }
+
+ public function getRadius() : float{
+ return $this->radius;
+ }
+
+ public function setRadius(float $radius) : void{
+ Utils::checkFloatNotInfOrNaN("radius", $radius);
+ if($radius <= 0){
+ throw new \InvalidArgumentException("Explosion radius must be positive");
+ }
+ $this->radius = $radius;
+ }
+
+ public function isBlockBreaking() : bool{
+ return $this->blockBreaking;
+ }
+
+ public function setBlockBreaking(bool $affectsBlocks) : void{
+ $this->blockBreaking = $affectsBlocks;
+ }
+
+ /**
+ * Returns whether the explosion will create a fire.
+ */
+ public function isIncendiary() : bool{
+ return $this->fireChance > 0;
+ }
+
+ /**
+ * Sets whether the explosion will create a fire by filling fireChance with default values.
+ *
+ * If $incendiary is true, the fire chance will be filled only if explosion isn't currently creating a fire (if fire chance is 0).
+ */
+ public function setIncendiary(bool $incendiary) : void{
+ if(!$incendiary){
+ $this->fireChance = 0;
+ }elseif($this->fireChance <= 0){
+ $this->fireChance = Explosion::DEFAULT_FIRE_CHANCE;
+ }
+ }
+
+ /**
+ * Returns a chance between 0 and 1 of creating a fire.
+ */
+ public function getFireChance() : float{
+ return $this->fireChance;
+ }
+
+ /**
+ * Sets a chance between 0 and 1 of creating a fire.
+ * For example, if the chance is 1/3, then that amount of affected blocks will be ignited.
+ *
+ * @param float $fireChance 0 ... 1
+ */
+ public function setFireChance(float $fireChance) : void{
+ Utils::checkFloatNotInfOrNaN("fireChance", $fireChance);
+ if($fireChance < 0.0 || $fireChance > 1.0){
+ throw new \InvalidArgumentException("Fire chance must be a number between 0 and 1.");
+ }
+ $this->fireChance = $fireChance;
+ }
+
+ /**
+ * Returns the player who triggered the block explosion.
+ * Returns null if the block was exploded by other means.
+ */
+ public function getPlayer() : ?Player{
+ return $this->player;
+ }
+}
diff --git a/src/event/entity/EntityExplodeEvent.php b/src/event/entity/EntityExplodeEvent.php
index 0a0e4f696..c1750ccb3 100644
--- a/src/event/entity/EntityExplodeEvent.php
+++ b/src/event/entity/EntityExplodeEvent.php
@@ -43,13 +43,15 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
/**
* @param Block[] $blocks
- * @param float $yield 0-100
+ * @param float $yield 0-100
+ * @param Block[] $ignitions
*/
public function __construct(
Entity $entity,
protected Position $position,
protected array $blocks,
- protected float $yield
+ protected float $yield,
+ private array $ignitions
){
$this->entity = $entity;
if($yield < 0.0 || $yield > 100.0){
@@ -98,4 +100,23 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
}
$this->yield = $yield;
}
+
+ /**
+ * Set the list of blocks that will be replaced by fire.
+ *
+ * @param Block[] $ignitions
+ */
+ public function setIgnitions(array $ignitions) : void{
+ Utils::validateArrayValueType($ignitions, fn(Block $block) => null);
+ $this->ignitions = $ignitions;
+ }
+
+ /**
+ * Returns a list of affected blocks that will be replaced by fire.
+ *
+ * @return Block[]
+ */
+ public function getIgnitions() : array{
+ return $this->ignitions;
+ }
}
diff --git a/src/event/entity/EntityPreExplodeEvent.php b/src/event/entity/EntityPreExplodeEvent.php
index f02a85ecd..c88e83304 100644
--- a/src/event/entity/EntityPreExplodeEvent.php
+++ b/src/event/entity/EntityPreExplodeEvent.php
@@ -26,6 +26,8 @@ namespace pocketmine\event\entity;
use pocketmine\entity\Entity;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
+use pocketmine\utils\Utils;
+use pocketmine\world\Explosion;
/**
* Called when an entity decides to explode, before the explosion's impact is calculated.
@@ -42,11 +44,16 @@ class EntityPreExplodeEvent extends EntityEvent implements Cancellable{
public function __construct(
Entity $entity,
- protected float $radius
+ protected float $radius,
+ private float $fireChance = 0.0,
){
if($radius <= 0){
throw new \InvalidArgumentException("Explosion radius must be positive");
}
+ Utils::checkFloatNotInfOrNaN("fireChance", $fireChance);
+ if($fireChance < 0.0 || $fireChance > 1.0){
+ throw new \InvalidArgumentException("Fire chance must be between 0 and 1.");
+ }
$this->entity = $entity;
}
@@ -61,6 +68,47 @@ class EntityPreExplodeEvent extends EntityEvent implements Cancellable{
$this->radius = $radius;
}
+ /**
+ * Returns whether the explosion will create a fire.
+ */
+ public function isIncendiary() : bool{
+ return $this->fireChance > 0;
+ }
+
+ /**
+ * Sets whether the explosion will create a fire by filling fireChance with default values.
+ *
+ * If $incendiary is true, the fire chance will be filled only if explosion isn't currently creating a fire (if fire chance is 0).
+ */
+ public function setIncendiary(bool $incendiary) : void{
+ if(!$incendiary){
+ $this->fireChance = 0;
+ }elseif($this->fireChance <= 0){
+ $this->fireChance = Explosion::DEFAULT_FIRE_CHANCE;
+ }
+ }
+
+ /**
+ * Returns a chance between 0 and 1 of creating a fire.
+ */
+ public function getFireChance() : float{
+ return $this->fireChance;
+ }
+
+ /**
+ * Sets a chance between 0 and 1 of creating a fire.
+ * For example, if the chance is 1/3, then that amount of affected blocks will be ignited.
+ *
+ * @param float $fireChance 0 ... 1
+ */
+ public function setFireChance(float $fireChance) : void{
+ Utils::checkFloatNotInfOrNaN("fireChance", $fireChance);
+ if($fireChance < 0.0 || $fireChance > 1.0){
+ throw new \InvalidArgumentException("Fire chance must be between 0 and 1.");
+ }
+ $this->fireChance = $fireChance;
+ }
+
public function isBlockBreaking() : bool{
return $this->blockBreaking;
}
diff --git a/src/event/player/PlayerRespawnAnchorUseEvent.php b/src/event/player/PlayerRespawnAnchorUseEvent.php
new file mode 100644
index 000000000..be7697f11
--- /dev/null
+++ b/src/event/player/PlayerRespawnAnchorUseEvent.php
@@ -0,0 +1,56 @@
+player = $player;
+ }
+
+ public function getBlock() : Block{
+ return $this->block;
+ }
+
+ public function getAction() : int{
+ return $this->action;
+ }
+
+ public function setAction(int $action) : void{
+ $this->action = $action;
+ }
+}
diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php
index a3bd7b872..7a90babed 100644
--- a/src/item/StringToItemParser.php
+++ b/src/item/StringToItemParser.php
@@ -993,6 +993,7 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("resin_brick_wall", fn() => Blocks::RESIN_BRICK_WALL());
$result->registerBlock("resin_bricks", fn() => Blocks::RESIN_BRICKS());
$result->registerBlock("resin_clump", fn() => Blocks::RESIN_CLUMP());
+ $result->registerBlock("respawn_anchor", fn() => Blocks::RESPAWN_ANCHOR());
$result->registerBlock("rooted_dirt", fn() => Blocks::DIRT()->setDirtType(DirtType::ROOTED));
$result->registerBlock("rose", fn() => Blocks::POPPY());
$result->registerBlock("rose_bush", fn() => Blocks::ROSE_BUSH());
diff --git a/src/player/Player.php b/src/player/Player.php
index 3c494b980..6429d1281 100644
--- a/src/player/Player.php
+++ b/src/player/Player.php
@@ -26,6 +26,7 @@ namespace pocketmine\player;
use pocketmine\block\BaseSign;
use pocketmine\block\Bed;
use pocketmine\block\BlockTypeTags;
+use pocketmine\block\RespawnAnchor;
use pocketmine\block\UnknownBlock;
use pocketmine\block\VanillaBlocks;
use pocketmine\command\CommandSender;
@@ -136,6 +137,7 @@ use pocketmine\world\sound\EntityAttackNoDamageSound;
use pocketmine\world\sound\EntityAttackSound;
use pocketmine\world\sound\FireExtinguishSound;
use pocketmine\world\sound\ItemBreakSound;
+use pocketmine\world\sound\RespawnAnchorDepleteSound;
use pocketmine\world\sound\Sound;
use pocketmine\world\World;
use pocketmine\YmlServerProperties;
@@ -2538,6 +2540,21 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
}
$this->logger->debug("Respawn position located, completing respawn");
$ev = new PlayerRespawnEvent($this, $safeSpawn);
+ $spawnPosition = $ev->getRespawnPosition();
+ $spawnBlock = $spawnPosition->getWorld()->getBlock($spawnPosition);
+ if($spawnBlock instanceof RespawnAnchor){
+ if($spawnBlock->getCharges() > 0){
+ $spawnPosition->getWorld()->setBlock($spawnPosition, $spawnBlock->setCharges($spawnBlock->getCharges() - 1));
+ $spawnPosition->getWorld()->addSound($spawnPosition, new RespawnAnchorDepleteSound());
+ }else{
+ $defaultSpawn = $this->server->getWorldManager()->getDefaultWorld()?->getSpawnLocation();
+ if($defaultSpawn !== null){
+ $this->setSpawn($defaultSpawn);
+ $ev->setRespawnPosition($defaultSpawn);
+ $this->sendMessage(KnownTranslationFactory::tile_respawn_anchor_notValid()->prefix(TextFormat::GRAY));
+ }
+ }
+ }
$ev->call();
$realSpawn = Position::fromObject($ev->getRespawnPosition()->add(0.5, 0, 0.5), $ev->getRespawnPosition()->getWorld());
diff --git a/src/world/Explosion.php b/src/world/Explosion.php
index 601f9109e..9e83d06be 100644
--- a/src/world/Explosion.php
+++ b/src/world/Explosion.php
@@ -26,16 +26,20 @@ namespace pocketmine\world;
use pocketmine\block\Block;
use pocketmine\block\RuntimeBlockStateRegistry;
use pocketmine\block\TNT;
+use pocketmine\block\utils\SupportType;
use pocketmine\block\VanillaBlocks;
use pocketmine\entity\Entity;
+use pocketmine\event\block\BlockExplodeEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityExplodeEvent;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
+use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\utils\AssumptionFailedError;
+use pocketmine\utils\Utils;
use pocketmine\world\format\SubChunk;
use pocketmine\world\particle\HugeExplodeSeedParticle;
use pocketmine\world\sound\ExplodeSound;
@@ -48,25 +52,36 @@ use function mt_rand;
use function sqrt;
class Explosion{
+ public const DEFAULT_FIRE_CHANCE = 1.0 / 3.0;
+
private int $rays = 16;
public World $world;
- /** @var Block[] */
+ /**
+ * @var Block[]
+ * @phpstan-var array
+ */
public array $affectedBlocks = [];
public float $stepLen = 0.3;
+ /** @var Block[] */
+ private array $fireIgnitions = [];
private SubChunkExplorer $subChunkExplorer;
public function __construct(
public Position $source,
public float $radius,
- private Entity|Block|null $what = null
+ private Entity|Block|null $what = null,
+ private float $fireChance = 0.0
){
if(!$this->source->isValid()){
throw new \InvalidArgumentException("Position does not have a valid world");
}
$this->world = $this->source->getWorld();
-
+ Utils::checkFloatNotInfOrNaN("fireChance", $fireChance);
+ if($fireChance < 0.0 || $fireChance > 1.0){
+ throw new \InvalidArgumentException("Fire chance must be a number between 0 and 1.");
+ }
if($radius <= 0){
throw new \InvalidArgumentException("Explosion radius must be greater than 0, got $radius");
}
@@ -85,6 +100,7 @@ class Explosion{
$blockFactory = RuntimeBlockStateRegistry::getInstance();
$mRays = $this->rays - 1;
+ $incendiary = $this->fireChance > 0;
for($i = 0; $i < $this->rays; ++$i){
for($j = 0; $j < $this->rays; ++$j){
for($k = 0; $k < $this->rays; ++$k){
@@ -127,7 +143,12 @@ class Explosion{
$_block = $this->world->getBlockAt($vBlockX, $vBlockY, $vBlockZ, true, false);
foreach($_block->getAffectedBlocks() as $_affectedBlock){
$_affectedBlockPos = $_affectedBlock->getPosition();
- $this->affectedBlocks[World::blockHash($_affectedBlockPos->x, $_affectedBlockPos->y, $_affectedBlockPos->z)] = $_affectedBlock;
+ $posHash = World::blockHash($_affectedBlockPos->x, $_affectedBlockPos->y, $_affectedBlockPos->z);
+ $this->affectedBlocks[$posHash] = $_affectedBlock;
+
+ if($incendiary && Utils::getRandomFloat() <= $this->fireChance){
+ $this->fireIgnitions[$posHash] = $_affectedBlock;
+ }
}
}
}
@@ -150,13 +171,32 @@ class Explosion{
$yield = min(100, (1 / $this->radius) * 100);
if($this->what instanceof Entity){
- $ev = new EntityExplodeEvent($this->what, $this->source, $this->affectedBlocks, $yield);
+ $ev = new EntityExplodeEvent($this->what, $this->source, $this->affectedBlocks, $yield, $this->fireIgnitions);
+
+ $ev->call();
+ if($ev->isCancelled()){
+ return false;
+ }
+
+ $yield = $ev->getYield();
+ $this->affectedBlocks = $ev->getBlockList();
+ $this->fireIgnitions = $ev->getIgnitions();
+ }elseif($this->what instanceof Block){
+ $ev = new BlockExplodeEvent(
+ $this->what,
+ $this->source,
+ $this->affectedBlocks,
+ $yield,
+ $this->fireIgnitions,
+ );
+
$ev->call();
if($ev->isCancelled()){
return false;
}else{
$yield = $ev->getYield();
- $this->affectedBlocks = $ev->getBlockList();
+ $this->affectedBlocks = $ev->getAffectedBlocks();
+ $this->fireIgnitions = $ev->getIgnitions();
}
}
@@ -198,8 +238,9 @@ class Explosion{
$air = VanillaItems::AIR();
$airBlock = VanillaBlocks::AIR();
+ $fireBlock = VanillaBlocks::FIRE();
- foreach($this->affectedBlocks as $block){
+ foreach($this->affectedBlocks as $hash => $block){
$pos = $block->getPosition();
if($block instanceof TNT){
$block->ignite(mt_rand(10, 30));
@@ -212,7 +253,13 @@ class Explosion{
if(($t = $this->world->getTileAt($pos->x, $pos->y, $pos->z)) !== null){
$t->onBlockDestroyed(); //needed to create drops for inventories
}
- $this->world->setBlockAt($pos->x, $pos->y, $pos->z, $airBlock);
+ $targetBlock =
+ isset($this->fireIgnitions[$hash]) &&
+ $block->getSide(Facing::DOWN)->getSupportType(Facing::UP) === SupportType::FULL ?
+ $fireBlock :
+ $airBlock;
+
+ $this->world->setBlockAt($pos->x, $pos->y, $pos->z, $targetBlock);
}
}
@@ -221,4 +268,18 @@ class Explosion{
return true;
}
+
+ /**
+ * Sets a chance between 0 and 1 of creating a fire.
+ * For example, if the chance is 1/3, then that amount of affected blocks will be ignited.
+ *
+ * @param float $fireChance 0 ... 1
+ */
+ public function setFireChance(float $fireChance) : void{
+ Utils::checkFloatNotInfOrNaN("fireChance", $fireChance);
+ if($fireChance < 0.0 || $fireChance > 1.0){
+ throw new \InvalidArgumentException("Fire chance must be a number between 0 and 1.");
+ }
+ $this->fireChance = $fireChance;
+ }
}
diff --git a/src/world/sound/RespawnAnchorChargeSound.php b/src/world/sound/RespawnAnchorChargeSound.php
new file mode 100644
index 000000000..5a5731262
--- /dev/null
+++ b/src/world/sound/RespawnAnchorChargeSound.php
@@ -0,0 +1,35 @@
+
Date: Wed, 28 May 2025 21:00:22 +0100
Subject: [PATCH 039/140] Stem drops seeds according to binomial distribution
fixes #6709
we really need a better way to reverse-engineer the chance parameter for these
as the wiki just gives a probability table, which is quite tiresome to extract
patterns from.
---
src/block/Stem.php | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/block/Stem.php b/src/block/Stem.php
index 2ac95aa3f..2b6f2150c 100644
--- a/src/block/Stem.php
+++ b/src/block/Stem.php
@@ -25,11 +25,12 @@ namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\CropGrowthHelper;
+use pocketmine\block\utils\FortuneDropHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
+use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use function array_rand;
-use function mt_rand;
abstract class Stem extends Crops{
protected int $facing = Facing::UP;
@@ -90,8 +91,10 @@ abstract class Stem extends Crops{
}
public function getDropsForCompatibleTool(Item $item) : array{
+ //TODO: bit annoying we have to pass an Item instance here
+ //this should not be affected by Fortune, but still follows a binomial distribution
return [
- $this->asItem()->setCount(mt_rand(0, 2))
+ $this->asItem()->setCount(FortuneDropHelper::binomial(VanillaItems::AIR(), 0, chance: ($this->age + 1) / 15))
];
}
}
From b40b99fe72cec89b0b785e904cbaff9664c6fb0c Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 28 May 2025 21:32:48 +0100
Subject: [PATCH 040/140] Player: fixed crash on action item return
this can happen if the old item had a lower max damage than the new one, and the new
one has a damage higher than the old one's max damage.
it can also happen if the damage was overridden to some illegal value by a custom item
as seen in https://crash.pmmp.io/view/12754811
---
src/player/Player.php | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/player/Player.php b/src/player/Player.php
index 1c67b7182..e0a42ed1d 100644
--- a/src/player/Player.php
+++ b/src/player/Player.php
@@ -1641,7 +1641,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$newReplica = clone $oldHeldItem;
$newReplica->setCount($newHeldItem->getCount());
if($newReplica instanceof Durable && $newHeldItem instanceof Durable){
- $newReplica->setDamage($newHeldItem->getDamage());
+ $newDamage = $newHeldItem->getDamage();
+ if($newDamage >= 0 && $newDamage <= $newReplica->getMaxDurability()){
+ $newReplica->setDamage($newDamage);
+ }
}
$damagedOrDeducted = $newReplica->equalsExact($newHeldItem);
From 035d2dec230d14ec06887e3d49f4526a619fd0c2 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 28 May 2025 22:03:29 +0100
Subject: [PATCH 041/140] LevelDB: make unknown block errors way less annoying
these would previously generate a new line for every error. since errors are
often repeated for different offsets (e.g. different states of the same
block), we can save a lot of spam by deduplicating them and telling which
offsets the errors occurred in.
---
src/world/format/io/leveldb/LevelDB.php | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php
index 6223e66b8..3a64f93f6 100644
--- a/src/world/format/io/leveldb/LevelDB.php
+++ b/src/world/format/io/leveldb/LevelDB.php
@@ -36,6 +36,7 @@ use pocketmine\nbt\TreeRoot;
use pocketmine\utils\Binary;
use pocketmine\utils\BinaryDataException;
use pocketmine\utils\BinaryStream;
+use pocketmine\utils\Utils;
use pocketmine\VersionInfo;
use pocketmine\world\format\Chunk;
use pocketmine\world\format\io\BaseWorldProvider;
@@ -204,23 +205,29 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$blockStateData = $this->blockDataUpgrader->upgradeBlockStateNbt($blockStateNbt);
}catch(BlockStateDeserializeException $e){
//while not ideal, this is not a fatal error
- $blockDecodeErrors[] = "Palette offset $i / Upgrade error: " . $e->getMessage() . ", NBT: " . $blockStateNbt->toString();
+ $errorMessage = "Upgrade error: " . $e->getMessage() . ", NBT: " . $blockStateNbt->toString();
+ $blockDecodeErrors[$errorMessage][] = $i;
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
continue;
}
try{
$palette[] = $this->blockStateDeserializer->deserialize($blockStateData);
}catch(UnsupportedBlockStateException $e){
- $blockDecodeErrors[] = "Palette offset $i / " . $e->getMessage();
+ $blockDecodeErrors[$e->getMessage()][] = $i;
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
}catch(BlockStateDeserializeException $e){
- $blockDecodeErrors[] = "Palette offset $i / Deserialize error: " . $e->getMessage() . ", NBT: " . $blockStateNbt->toString();
+ $errorMessage = "Deserialize error: " . $e->getMessage() . ", NBT: " . $blockStateNbt->toString();
+ $blockDecodeErrors[$errorMessage][] = $i;
$palette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
}
}
if(count($blockDecodeErrors) > 0){
- $logger->error("Errors decoding blocks:\n - " . implode("\n - ", $blockDecodeErrors));
+ $finalErrors = [];
+ foreach(Utils::promoteKeys($blockDecodeErrors) as $errorMessage => $paletteOffsets){
+ $finalErrors[] = "$errorMessage (palette offsets: " . implode(", ", $paletteOffsets) . ")";
+ }
+ $logger->error("Errors decoding blocks:\n - " . implode("\n - ", $finalErrors));
}
//TODO: exceptions
From 56da492e48bf94cf5da4153f48f6d872ba8c0f21 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 28 May 2025 22:10:20 +0100
Subject: [PATCH 042/140] World: make less noise about deleted tile entities no
need to repeat the same message 100 times
---
src/world/World.php | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/src/world/World.php b/src/world/World.php
index 792681a89..5c5e4cfbf 100644
--- a/src/world/World.php
+++ b/src/world/World.php
@@ -2982,6 +2982,8 @@ class World implements ChunkManager{
if(count($chunkData->getEntityNBT()) !== 0){
$this->timings->syncChunkLoadEntities->startTiming();
$entityFactory = EntityFactory::getInstance();
+
+ $deletedEntities = [];
foreach($chunkData->getEntityNBT() as $k => $nbt){
try{
$entity = $entityFactory->createFromData($this, $nbt);
@@ -2998,18 +3000,23 @@ class World implements ChunkManager{
}elseif($saveIdTag instanceof IntTag){ //legacy MCPE format
$saveId = "legacy(" . $saveIdTag->getValue() . ")";
}
- $logger->warning("Deleted unknown entity type $saveId");
+ $deletedEntities[$saveId] = ($deletedEntities[$saveId] ?? 0) + 1;
}
//TODO: we can't prevent entities getting added to unloaded chunks if they were saved in the wrong place
//here, because entities currently add themselves to the world
}
+ foreach(Utils::promoteKeys($deletedEntities) as $saveId => $count){
+ $logger->warning("Deleted unknown entity type $saveId x$count");
+ }
$this->timings->syncChunkLoadEntities->stopTiming();
}
if(count($chunkData->getTileNBT()) !== 0){
$this->timings->syncChunkLoadTileEntities->startTiming();
$tileFactory = TileFactory::getInstance();
+
+ $deletedTiles = [];
foreach($chunkData->getTileNBT() as $k => $nbt){
try{
$tile = $tileFactory->createFromData($this, $nbt);
@@ -3019,7 +3026,8 @@ class World implements ChunkManager{
continue;
}
if($tile === null){
- $logger->warning("Deleted unknown tile entity type " . $nbt->getString("id", ""));
+ $saveId = $nbt->getString("id", "");
+ $deletedTiles[$saveId] = ($deletedTiles[$saveId] ?? 0) + 1;
continue;
}
@@ -3035,6 +3043,10 @@ class World implements ChunkManager{
}
}
+ foreach(Utils::promoteKeys($deletedTiles) as $saveId => $count){
+ $logger->warning("Deleted unknown tile entity type $saveId x$count");
+ }
+
$this->timings->syncChunkLoadTileEntities->stopTiming();
}
}
From 0910a219d4b66d53f1387eea27f25efbc4e34572 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 28 May 2025 23:29:37 +0100
Subject: [PATCH 043/140] Fixed improper pre-checking of PlayerAuthInputPacket
flags
---
composer.json | 2 +-
composer.lock | 14 +++++++-------
src/network/mcpe/handler/InGamePacketHandler.php | 2 +-
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/composer.json b/composer.json
index 979973893..d2064bcd6 100644
--- a/composer.json
+++ b/composer.json
@@ -36,7 +36,7 @@
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
"pocketmine/bedrock-data": "~5.0.0+bedrock-1.21.80",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
- "pocketmine/bedrock-protocol": "~38.0.0+bedrock-1.21.80",
+ "pocketmine/bedrock-protocol": "~38.1.0+bedrock-1.21.80",
"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 9cb0721fc..2e2e5a600 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": "ceb98091ac3f61f1a4b87708c48dc75a",
+ "content-hash": "fe62caebfdb35cd8bd57c8e61879b7c0",
"packages": [
{
"name": "adhocore/json-comment",
@@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "38.0.1+bedrock-1.21.80",
+ "version": "38.1.0+bedrock-1.21.80",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f"
+ "reference": "a1fa215563517050045309bb779a67f75843b867"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f",
- "reference": "0c1c13e970a2e1ded1609d0b442b4fcfd24cd21f",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a1fa215563517050045309bb779a67f75843b867",
+ "reference": "a1fa215563517050045309bb779a67f75843b867",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/38.0.1+bedrock-1.21.80"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/38.1.0+bedrock-1.21.80"
},
- "time": "2025-05-17T11:56:33+00:00"
+ "time": "2025-05-28T22:19:59+00:00"
},
{
"name": "pocketmine/binaryutils",
diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php
index eec200e4b..927ba38fa 100644
--- a/src/network/mcpe/handler/InGamePacketHandler.php
+++ b/src/network/mcpe/handler/InGamePacketHandler.php
@@ -211,7 +211,7 @@ class InGamePacketHandler extends PacketHandler{
}
$inputFlags = $packet->getInputFlags();
- if($inputFlags !== $this->lastPlayerAuthInputFlags){
+ if($this->lastPlayerAuthInputFlags === null || !$inputFlags->equals($this->lastPlayerAuthInputFlags)){
$this->lastPlayerAuthInputFlags = $inputFlags;
$sneaking = $inputFlags->get(PlayerAuthInputFlags::SNEAKING);
From b4b6bbe29f21754039db11ab8ca7d0758e4b43b5 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Thu, 29 May 2025 17:18:45 +0100
Subject: [PATCH 044/140] BaseInventory: fixed internalAddItem() setting air
slots to air this bug was introduced in #4237, but it was unnoticed due to
having no adverse effects other than noisy debugs and network traffic.
---
src/inventory/BaseInventory.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php
index 0d5d1ffe6..c4afda43a 100644
--- a/src/inventory/BaseInventory.php
+++ b/src/inventory/BaseInventory.php
@@ -256,7 +256,7 @@ abstract class BaseInventory implements Inventory, SlotValidatedInventory{
$slotItem->setCount($slotItem->getCount() + $amount);
$this->setItem($i, $slotItem);
if($newItem->getCount() <= 0){
- break;
+ return $newItem;
}
}
}
@@ -270,7 +270,7 @@ abstract class BaseInventory implements Inventory, SlotValidatedInventory{
$slotItem->setCount($amount);
$this->setItem($slotIndex, $slotItem);
if($newItem->getCount() <= 0){
- break;
+ return $newItem;
}
}
}
From e99665fb12299519ad50f0da7f08000af9e2bc45 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 2 Jun 2025 14:08:14 +0000
Subject: [PATCH 045/140] Bump docker/build-push-action in the github-actions
group (#6719)
---
.github/workflows/build-docker-image.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
index dc282ab71..a3921f820 100644
--- a/.github/workflows/build-docker-image.yml
+++ b/.github/workflows/build-docker-image.yml
@@ -53,7 +53,7 @@ jobs:
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag
- uses: docker/build-push-action@v6.16.0
+ uses: docker/build-push-action@v6.18.0
with:
push: true
context: ./pocketmine-mp
@@ -66,7 +66,7 @@ jobs:
- name: Build image for major tag
if: steps.channel.outputs.CHANNEL == 'stable'
- uses: docker/build-push-action@v6.16.0
+ uses: docker/build-push-action@v6.18.0
with:
push: true
context: ./pocketmine-mp
@@ -79,7 +79,7 @@ jobs:
- name: Build image for minor tag
if: steps.channel.outputs.CHANNEL == 'stable'
- uses: docker/build-push-action@v6.16.0
+ uses: docker/build-push-action@v6.18.0
with:
push: true
context: ./pocketmine-mp
@@ -92,7 +92,7 @@ jobs:
- name: Build image for latest tag
if: steps.channel.outputs.CHANNEL == 'stable'
- uses: docker/build-push-action@v6.16.0
+ uses: docker/build-push-action@v6.18.0
with:
push: true
context: ./pocketmine-mp
From a4ac28592c6c5f5876927aa2a140b65dad63d786 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Mon, 2 Jun 2025 15:17:00 +0100
Subject: [PATCH 046/140] Updated dependencies
---
composer.json | 2 +-
composer.lock | 24 +++++++++++-----------
tests/phpstan/configs/actual-problems.neon | 6 ------
tests/phpstan/configs/phpstan-bugs.neon | 12 -----------
4 files changed, 13 insertions(+), 31 deletions(-)
diff --git a/composer.json b/composer.json
index d2064bcd6..1935bc290 100644
--- a/composer.json
+++ b/composer.json
@@ -52,7 +52,7 @@
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
- "phpstan/phpstan": "2.1.16",
+ "phpstan/phpstan": "2.1.17",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
diff --git a/composer.lock b/composer.lock
index 2e2e5a600..cb60c7ace 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": "fe62caebfdb35cd8bd57c8e61879b7c0",
+ "content-hash": "69921783f476a0704fa1f8924b901a89",
"packages": [
{
"name": "adhocore/json-comment",
@@ -1038,16 +1038,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.4.0",
+ "version": "v5.5.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "447a020a1f875a434d62f2a401f53b82a396e494"
+ "reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
- "reference": "447a020a1f875a434d62f2a401f53b82a396e494",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
+ "reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
"shasum": ""
},
"require": {
@@ -1090,9 +1090,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
},
- "time": "2024-12-30T11:07:19+00:00"
+ "time": "2025-05-31T08:24:38+00:00"
},
{
"name": "phar-io/manifest",
@@ -1214,16 +1214,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "2.1.16",
+ "version": "2.1.17",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9"
+ "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
- "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053",
+ "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053",
"shasum": ""
},
"require": {
@@ -1268,7 +1268,7 @@
"type": "github"
}
],
- "time": "2025-05-16T09:40:10+00:00"
+ "time": "2025-05-21T20:55:28+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon
index d3adde422..39ae4948c 100644
--- a/tests/phpstan/configs/actual-problems.neon
+++ b/tests/phpstan/configs/actual-problems.neon
@@ -702,12 +702,6 @@ parameters:
count: 1
path: ../../../src/inventory/transaction/InventoryTransaction.php
- -
- message: '#^Cannot cast mixed to int\.$#'
- identifier: cast.int
- count: 2
- path: ../../../src/item/Item.php
-
-
message: '#^Parameter \#1 \$buffer of method pocketmine\\nbt\\BaseNbtSerializer\:\:read\(\) expects string, mixed given\.$#'
identifier: argument.type
diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon
index aeb3fae29..75b1e82a7 100644
--- a/tests/phpstan/configs/phpstan-bugs.neon
+++ b/tests/phpstan/configs/phpstan-bugs.neon
@@ -18,12 +18,6 @@ parameters:
count: 1
path: ../../../src/Server.php
- -
- message: '#^Method pocketmine\\block\\Block\:\:readStateFromWorld\(\) is marked as impure but does not have any side effects\.$#'
- identifier: impureMethod.pure
- count: 1
- path: ../../../src/block/Block.php
-
-
message: '#^Method pocketmine\\block\\DoubleTallGrass\:\:traitGetDropsForIncompatibleTool\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
@@ -252,9 +246,3 @@ parameters:
count: 2
path: ../../phpunit/promise/PromiseTest.php
- -
- message: '#^Strict comparison using \=\=\= between 0 and 0 will always evaluate to true\.$#'
- identifier: identical.alwaysTrue
- count: 1
- path: ../rules/UnsafeForeachArrayOfStringRule.php
-
From 5ebbcd5d33286d37f311a1c9f8a69100dcaf87e9 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Mon, 2 Jun 2025 15:24:25 +0100
Subject: [PATCH 047/140] Move to newer systems for movement and block break
handling (#6718)
MS is due to remove the non-server-auth versions of all of this stuff.
Fortunately v3 server auth movement works just fine without any changes,
although we will need to start sending player tick in some packets if
someone wants to actually use the rewind stuff.
---
src/network/mcpe/InventoryManager.php | 19 +++--
.../mcpe/handler/InGamePacketHandler.php | 85 +++++++++++--------
.../mcpe/handler/ItemStackRequestExecutor.php | 26 +++++-
.../mcpe/handler/PreSpawnPacketHandler.php | 2 +-
4 files changed, 89 insertions(+), 43 deletions(-)
diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php
index 2ff23a73a..19bd94fce 100644
--- a/src/network/mcpe/InventoryManager.php
+++ b/src/network/mcpe/InventoryManager.php
@@ -41,6 +41,7 @@ use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\item\enchantment\EnchantingOption;
use pocketmine\item\enchantment\EnchantmentInstance;
+use pocketmine\item\Item;
use pocketmine\network\mcpe\cache\CreativeInventoryCache;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
@@ -228,17 +229,25 @@ class InventoryManager{
return null;
}
- private function addPredictedSlotChange(Inventory $inventory, int $slot, ItemStack $item) : void{
+ private function addPredictedSlotChangeInternal(Inventory $inventory, int $slot, ItemStack $item) : void{
$this->inventories[spl_object_id($inventory)]->predictions[$slot] = $item;
}
- public function addTransactionPredictedSlotChanges(InventoryTransaction $tx) : void{
+ public function addPredictedSlotChange(Inventory $inventory, int $slot, Item $item) : void{
$typeConverter = $this->session->getTypeConverter();
+ $itemStack = $typeConverter->coreItemStackToNet($item);
+ $this->addPredictedSlotChangeInternal($inventory, $slot, $itemStack);
+ }
+
+ public function addTransactionPredictedSlotChanges(InventoryTransaction $tx) : void{
foreach($tx->getActions() as $action){
if($action instanceof SlotChangeAction){
//TODO: ItemStackRequestExecutor can probably build these predictions with much lower overhead
- $itemStack = $typeConverter->coreItemStackToNet($action->getTargetItem());
- $this->addPredictedSlotChange($action->getInventory(), $action->getSlot(), $itemStack);
+ $this->addPredictedSlotChange(
+ $action->getInventory(),
+ $action->getSlot(),
+ $action->getTargetItem()
+ );
}
}
}
@@ -267,7 +276,7 @@ class InventoryManager{
}
[$inventory, $slot] = $info;
- $this->addPredictedSlotChange($inventory, $slot, $action->newItem->getItemStack());
+ $this->addPredictedSlotChangeInternal($inventory, $slot, $action->newItem->getItemStack());
}
}
diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php
index eec200e4b..c2ca3cb5c 100644
--- a/src/network/mcpe/handler/InGamePacketHandler.php
+++ b/src/network/mcpe/handler/InGamePacketHandler.php
@@ -136,6 +136,8 @@ class InGamePacketHandler extends PacketHandler{
protected ?float $lastPlayerAuthInputPitch = null;
protected ?BitSet $lastPlayerAuthInputFlags = null;
+ protected ?BlockPosition $lastBlockAttacked = null;
+
public bool $forceMoveSync = false;
protected ?string $lastRequestedFullSkinId = null;
@@ -248,6 +250,28 @@ class InGamePacketHandler extends PacketHandler{
$packetHandled = true;
+ $useItemTransaction = $packet->getItemInteractionData();
+ if($useItemTransaction !== null){
+ if(count($useItemTransaction->getTransactionData()->getActions()) > 100){
+ throw new PacketHandlingException("Too many actions in item use transaction");
+ }
+
+ $this->inventoryManager->setCurrentItemStackRequestId($useItemTransaction->getRequestId());
+ $this->inventoryManager->addRawPredictedSlotChanges($useItemTransaction->getTransactionData()->getActions());
+ if(!$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){
+ $packetHandled = false;
+ $this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")");
+ }else{
+ $this->inventoryManager->syncMismatchedPredictedSlotChanges();
+ }
+ $this->inventoryManager->setCurrentItemStackRequestId(null);
+ }
+
+ $itemStackRequest = $packet->getItemStackRequest();
+ $itemStackResponseBuilder = $itemStackRequest !== null ? $this->handleSingleItemStackRequest($itemStackRequest) : null;
+
+ //itemstack request or transaction may set predictions for the outcome of these actions, so these need to be
+ //processed last
$blockActions = $packet->getBlockActions();
if($blockActions !== null){
if(count($blockActions) > 100){
@@ -268,27 +292,9 @@ class InGamePacketHandler extends PacketHandler{
}
}
- $useItemTransaction = $packet->getItemInteractionData();
- if($useItemTransaction !== null){
- if(count($useItemTransaction->getTransactionData()->getActions()) > 100){
- throw new PacketHandlingException("Too many actions in item use transaction");
- }
-
- $this->inventoryManager->setCurrentItemStackRequestId($useItemTransaction->getRequestId());
- $this->inventoryManager->addRawPredictedSlotChanges($useItemTransaction->getTransactionData()->getActions());
- if(!$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){
- $packetHandled = false;
- $this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")");
- }else{
- $this->inventoryManager->syncMismatchedPredictedSlotChanges();
- }
- $this->inventoryManager->setCurrentItemStackRequestId(null);
- }
-
- $itemStackRequest = $packet->getItemStackRequest();
if($itemStackRequest !== null){
- $result = $this->handleSingleItemStackRequest($itemStackRequest);
- $this->session->sendDataPacket(ItemStackResponsePacket::create([$result]));
+ $itemStackResponse = $itemStackResponseBuilder?->build() ?? new ItemStackResponse(ItemStackResponse::RESULT_ERROR, $itemStackRequest->getRequestId());
+ $this->session->sendDataPacket(ItemStackResponsePacket::create([$itemStackResponse]));
}
return $packetHandled;
@@ -498,13 +504,6 @@ class InGamePacketHandler extends PacketHandler{
//if only the client would tell us what blocks it thinks changed...
$this->syncBlocksNearby($vBlockPos, $data->getFace());
return true;
- case UseItemTransactionData::ACTION_BREAK_BLOCK:
- $blockPos = $data->getBlockPosition();
- $vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ());
- if(!$this->player->breakBlock($vBlockPos)){
- $this->syncBlocksNearby($vBlockPos, null);
- }
- return true;
case UseItemTransactionData::ACTION_CLICK_AIR:
if($this->player->isUsingItem()){
if(!$this->player->consumeHeldItem()){
@@ -580,7 +579,7 @@ class InGamePacketHandler extends PacketHandler{
return false;
}
- private function handleSingleItemStackRequest(ItemStackRequest $request) : ItemStackResponse{
+ private function handleSingleItemStackRequest(ItemStackRequest $request) : ?ItemStackResponseBuilder{
if(count($request->getActions()) > 60){
//recipe book auto crafting can affect all slots of the inventory when consuming inputs or producing outputs
//this means there could be as many as 50 CraftingConsumeInput actions or Place (taking the result) actions
@@ -597,7 +596,11 @@ class InGamePacketHandler extends PacketHandler{
$executor = new ItemStackRequestExecutor($this->player, $this->inventoryManager, $request);
try{
$transaction = $executor->generateInventoryTransaction();
- $result = $this->executeInventoryTransaction($transaction, $request->getRequestId());
+ if($transaction !== null){
+ $result = $this->executeInventoryTransaction($transaction, $request->getRequestId());
+ }else{
+ $result = true; //predictions only, just send responses
+ }
}catch(ItemStackRequestProcessException $e){
$result = false;
$this->session->getLogger()->debug("ItemStackRequest #" . $request->getRequestId() . " failed: " . $e->getMessage());
@@ -605,10 +608,7 @@ class InGamePacketHandler extends PacketHandler{
$this->inventoryManager->requestSyncAll();
}
- if(!$result){
- return new ItemStackResponse(ItemStackResponse::RESULT_ERROR, $request->getRequestId());
- }
- return $executor->buildItemStackResponse();
+ return $result ? $executor->getItemStackResponseBuilder() : null;
}
public function handleItemStackRequest(ItemStackRequestPacket $packet) : bool{
@@ -618,7 +618,7 @@ class InGamePacketHandler extends PacketHandler{
throw new PacketHandlingException("Too many requests in ItemStackRequestPacket");
}
foreach($packet->getRequests() as $request){
- $responses[] = $this->handleSingleItemStackRequest($request);
+ $responses[] = $this->handleSingleItemStackRequest($request)?->build() ?? new ItemStackResponse(ItemStackResponse::RESULT_ERROR, $request->getRequestId());
}
$this->session->sendDataPacket(ItemStackResponsePacket::create($responses));
@@ -681,16 +681,27 @@ class InGamePacketHandler extends PacketHandler{
switch($action){
case PlayerAction::START_BREAK:
+ case PlayerAction::CONTINUE_DESTROY_BLOCK: //destroy the next block while holding down left click
self::validateFacing($face);
+ if($this->lastBlockAttacked !== null && $blockPosition->equals($this->lastBlockAttacked)){
+ //the client will send CONTINUE_DESTROY_BLOCK for the currently targeted block directly before it
+ //sends PREDICT_DESTROY_BLOCK, but also when it starts to break the block
+ //this seems like a bug in the client and would cause spurious left-click events if we allowed it to
+ //be delivered to the player
+ $this->session->getLogger()->debug("Ignoring PlayerAction $action on $pos because we were already destroying this block");
+ break;
+ }
if(!$this->player->attackBlock($pos, $face)){
$this->syncBlocksNearby($pos, $face);
}
+ $this->lastBlockAttacked = $blockPosition;
break;
case PlayerAction::ABORT_BREAK:
case PlayerAction::STOP_BREAK:
$this->player->stopBreakBlock($pos);
+ $this->lastBlockAttacked = null;
break;
case PlayerAction::START_SLEEPING:
//unused
@@ -701,11 +712,17 @@ class InGamePacketHandler extends PacketHandler{
case PlayerAction::CRACK_BREAK:
self::validateFacing($face);
$this->player->continueBreakBlock($pos, $face);
+ $this->lastBlockAttacked = $blockPosition;
break;
case PlayerAction::INTERACT_BLOCK: //TODO: ignored (for now)
break;
case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK:
//TODO: do we need to handle this?
+ case PlayerAction::PREDICT_DESTROY_BLOCK:
+ if(!$this->player->breakBlock($pos)){
+ $this->syncBlocksNearby($pos, $face);
+ }
+ $this->lastBlockAttacked = null;
break;
case PlayerAction::START_ITEM_USE_ON:
case PlayerAction::STOP_ITEM_USE_ON:
diff --git a/src/network/mcpe/handler/ItemStackRequestExecutor.php b/src/network/mcpe/handler/ItemStackRequestExecutor.php
index 6db8f1e12..d71a1c6bf 100644
--- a/src/network/mcpe/handler/ItemStackRequestExecutor.php
+++ b/src/network/mcpe/handler/ItemStackRequestExecutor.php
@@ -33,9 +33,11 @@ use pocketmine\inventory\transaction\EnchantingTransaction;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\inventory\transaction\TransactionBuilder;
use pocketmine\inventory\transaction\TransactionBuilderInventory;
+use pocketmine\item\Durable;
use pocketmine\item\Item;
use pocketmine\network\mcpe\InventoryManager;
use pocketmine\network\mcpe\protocol\types\inventory\ContainerUIIds;
+use pocketmine\network\mcpe\protocol\types\inventory\FullContainerName;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftingConsumeInputStackRequestAction;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftingCreateSpecificResultStackRequestAction;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftRecipeAutoStackRequestAction;
@@ -47,6 +49,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\DropStackReque
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequest;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequestAction;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequestSlotInfo;
+use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\MineBlockStackRequestAction;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\PlaceStackRequestAction;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\SwapStackRequestAction;
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\TakeStackRequestAction;
@@ -362,6 +365,16 @@ class ItemStackRequestExecutor{
$this->setNextCreatedItem($nextResultItem);
}elseif($action instanceof DeprecatedCraftingResultsStackRequestAction){
//no obvious use
+ }elseif($action instanceof MineBlockStackRequestAction){
+ $slot = $action->getHotbarSlot();
+ $this->requestSlotInfos[] = new ItemStackRequestSlotInfo(new FullContainerName(ContainerUIIds::HOTBAR), $slot, $action->getStackId());
+ $inventory = $this->player->getInventory();
+ $usedItem = $inventory->slotExists($slot) ? $inventory->getItem($slot) : null;
+ $predictedDamage = $action->getPredictedDurability();
+ if($usedItem instanceof Durable && $predictedDamage >= 0 && $predictedDamage <= $usedItem->getMaxDurability()){
+ $usedItem->setDamage($predictedDamage);
+ $this->inventoryManager->addPredictedSlotChange($inventory, $slot, $usedItem);
+ }
}else{
throw new ItemStackRequestProcessException("Unhandled item stack request action");
}
@@ -370,7 +383,7 @@ class ItemStackRequestExecutor{
/**
* @throws ItemStackRequestProcessException
*/
- public function generateInventoryTransaction() : InventoryTransaction{
+ public function generateInventoryTransaction() : ?InventoryTransaction{
foreach(Utils::promoteKeys($this->request->getActions()) as $k => $action){
try{
$this->processItemStackRequestAction($action);
@@ -380,6 +393,9 @@ class ItemStackRequestExecutor{
}
$this->setNextCreatedItem(null);
$inventoryActions = $this->builder->generateActions();
+ if(count($inventoryActions) === 0){
+ return null;
+ }
$transaction = $this->specialTransaction ?? new InventoryTransaction($this->player);
foreach($inventoryActions as $action){
@@ -389,12 +405,16 @@ class ItemStackRequestExecutor{
return $transaction;
}
- public function buildItemStackResponse() : ItemStackResponse{
+ public function getItemStackResponseBuilder() : ItemStackResponseBuilder{
$builder = new ItemStackResponseBuilder($this->request->getRequestId(), $this->inventoryManager);
foreach($this->requestSlotInfos as $requestInfo){
$builder->addSlot($requestInfo->getContainerName()->getContainerId(), $requestInfo->getSlotId());
}
- return $builder->build();
+ return $builder;
+ }
+
+ public function buildItemStackResponse() : ItemStackResponse{
+ return $this->getItemStackResponseBuilder()->build();
}
}
diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php
index 9aa302c0c..161a679d6 100644
--- a/src/network/mcpe/handler/PreSpawnPacketHandler.php
+++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php
@@ -99,7 +99,7 @@ class PreSpawnPacketHandler extends PacketHandler{
$this->server->getMotd(),
"",
false,
- new PlayerMovementSettings(ServerAuthMovementMode::SERVER_AUTHORITATIVE_V2, 0, false),
+ new PlayerMovementSettings(ServerAuthMovementMode::SERVER_AUTHORITATIVE_V3, 0, true),
0,
0,
"",
From 4c3a2ef46ed15dbdccec415d78603a23fea41fb1 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 8 Jun 2025 18:44:37 +0100
Subject: [PATCH 048/140] Update dependencies (minor-next)
---
composer.json | 4 +--
composer.lock | 83 ++++++++++++++++++++++-----------------------------
2 files changed, 37 insertions(+), 50 deletions(-)
diff --git a/composer.json b/composer.json
index 8c56bbf81..e65a6fb8e 100644
--- a/composer.json
+++ b/composer.json
@@ -45,10 +45,10 @@
"pocketmine/log": "^0.4.0",
"pocketmine/math": "~1.0.0",
"pocketmine/nbt": "~1.1.0",
- "pocketmine/raklib": "~1.1.2",
+ "pocketmine/raklib": "~1.2.0",
"pocketmine/raklib-ipc": "~1.0.0",
"pocketmine/snooze": "^0.5.0",
- "ramsey/uuid": "~4.7.0",
+ "ramsey/uuid": "~4.8.0",
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
diff --git a/composer.lock b/composer.lock
index 10fb2a6ab..c01e7a299 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": "3db02308c5b44b94e1c990d60ffd2f28",
+ "content-hash": "7c3052613e98e566d8b00ae3c9119057",
"packages": [
{
"name": "adhocore/json-comment",
@@ -67,16 +67,16 @@
},
{
"name": "brick/math",
- "version": "0.12.3",
+ "version": "0.13.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
+ "reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
- "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
+ "url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04",
+ "reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04",
"shasum": ""
},
"require": {
@@ -115,7 +115,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.12.3"
+ "source": "https://github.com/brick/math/tree/0.13.1"
},
"funding": [
{
@@ -123,7 +123,7 @@
"type": "github"
}
],
- "time": "2025-02-28T13:11:00+00:00"
+ "time": "2025-03-29T13:50:30+00:00"
},
{
"name": "netresearch/jsonmapper",
@@ -618,16 +618,16 @@
},
{
"name": "pocketmine/raklib",
- "version": "1.1.2",
+ "version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
- "reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f"
+ "reference": "a28d05216d34dbd00e8aed827a58df6b4c11510b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/RakLib/zipball/4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
- "reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
+ "url": "https://api.github.com/repos/pmmp/RakLib/zipball/a28d05216d34dbd00e8aed827a58df6b4c11510b",
+ "reference": "a28d05216d34dbd00e8aed827a58df6b4c11510b",
"shasum": ""
},
"require": {
@@ -655,9 +655,9 @@
"description": "A RakNet server implementation written in PHP",
"support": {
"issues": "https://github.com/pmmp/RakLib/issues",
- "source": "https://github.com/pmmp/RakLib/tree/1.1.2"
+ "source": "https://github.com/pmmp/RakLib/tree/1.2.0"
},
- "time": "2025-04-06T03:38:21+00:00"
+ "time": "2025-06-08T17:36:06+00:00"
},
{
"name": "pocketmine/raklib-ipc",
@@ -818,20 +818,20 @@
},
{
"name": "ramsey/uuid",
- "version": "4.7.6",
+ "version": "4.8.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "91039bc1faa45ba123c4328958e620d382ec7088"
+ "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
- "reference": "91039bc1faa45ba123c4328958e620d382ec7088",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
+ "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
"shasum": ""
},
"require": {
- "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
+ "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
"ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
@@ -840,26 +840,23 @@
"rhumsaa/uuid": "self.version"
},
"require-dev": {
- "captainhook/captainhook": "^5.10",
+ "captainhook/captainhook": "^5.25",
"captainhook/plugin-composer": "^5.3",
- "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
- "doctrine/annotations": "^1.8",
- "ergebnis/composer-normalize": "^2.15",
- "mockery/mockery": "^1.3",
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+ "ergebnis/composer-normalize": "^2.47",
+ "mockery/mockery": "^1.6",
"paragonie/random-lib": "^2",
- "php-mock/php-mock": "^2.2",
- "php-mock/php-mock-mockery": "^1.3",
- "php-parallel-lint/php-parallel-lint": "^1.1",
- "phpbench/phpbench": "^1.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-mockery": "^1.1",
- "phpstan/phpstan-phpunit": "^1.1",
- "phpunit/phpunit": "^8.5 || ^9",
- "ramsey/composer-repl": "^1.4",
- "slevomat/coding-standard": "^8.4",
- "squizlabs/php_codesniffer": "^3.5",
- "vimeo/psalm": "^4.9"
+ "php-mock/php-mock": "^2.6",
+ "php-mock/php-mock-mockery": "^1.5",
+ "php-parallel-lint/php-parallel-lint": "^1.4.0",
+ "phpbench/phpbench": "^1.2.14",
+ "phpstan/extension-installer": "^1.4",
+ "phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-mockery": "^2.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpunit/phpunit": "^9.6",
+ "slevomat/coding-standard": "^8.18",
+ "squizlabs/php_codesniffer": "^3.13"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
@@ -894,19 +891,9 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.7.6"
+ "source": "https://github.com/ramsey/uuid/tree/4.8.1"
},
- "funding": [
- {
- "url": "https://github.com/ramsey",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-27T21:32:50+00:00"
+ "time": "2025-06-01T06:28:46+00:00"
},
{
"name": "symfony/filesystem",
From c3ea6edc220e7dede269fcbf2299fb011137f822 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 8 Jun 2025 18:49:27 +0100
Subject: [PATCH 049/140] Bump minimum PHP version to 8.3
---
.github/workflows/discord-release-notify.yml | 2 +-
.github/workflows/draft-release-pr-check.yml | 2 +-
.github/workflows/draft-release.yml | 2 +-
.github/workflows/main.yml | 2 +-
composer.json | 4 ++--
composer.lock | 6 +++---
src/PocketMine.php | 2 +-
7 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/discord-release-notify.yml b/.github/workflows/discord-release-notify.yml
index 93b2978aa..1116946da 100644
--- a/.github/workflows/discord-release-notify.yml
+++ b/.github/workflows/discord-release-notify.yml
@@ -15,7 +15,7 @@ jobs:
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.33.0
with:
- php-version: 8.2
+ php-version: 8.3
- name: Restore Composer package cache
uses: actions/cache@v4
diff --git a/.github/workflows/draft-release-pr-check.yml b/.github/workflows/draft-release-pr-check.yml
index 20b2200e6..de017f585 100644
--- a/.github/workflows/draft-release-pr-check.yml
+++ b/.github/workflows/draft-release-pr-check.yml
@@ -51,7 +51,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@2.33.0
with:
- php-version: 8.2
+ php-version: 8.3
- name: Restore Composer package cache
uses: actions/cache@v4
diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml
index fa20d1912..bf23ef5ad 100644
--- a/.github/workflows/draft-release.yml
+++ b/.github/workflows/draft-release.yml
@@ -18,7 +18,7 @@ on:
- "*"
env:
- PHP_VERSION: "8.2"
+ PHP_VERSION: "8.3"
jobs:
skip:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index cabda54be..f246f5802 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: ["8.1", "8.2", "8.3"]
+ php: ["8.3"]
uses: ./.github/workflows/main-php-matrix.yml
with:
diff --git a/composer.json b/composer.json
index 1754ad473..04f08bbeb 100644
--- a/composer.json
+++ b/composer.json
@@ -5,7 +5,7 @@
"homepage": "https://pmmp.io",
"license": "LGPL-3.0",
"require": {
- "php": "^8.1",
+ "php": "^8.3",
"php-64bit": "*",
"ext-chunkutils2": "^0.3.1",
"ext-crypto": "^0.3.1",
@@ -77,7 +77,7 @@
},
"config": {
"platform": {
- "php": "8.1.0"
+ "php": "8.3.0"
},
"sort-packages": true
},
diff --git a/composer.lock b/composer.lock
index c01e7a299..5eb9e6da3 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": "7c3052613e98e566d8b00ae3c9119057",
+ "content-hash": "3aa2808cfb5b30b7a4eb481d19d76c7e",
"packages": [
{
"name": "adhocore/json-comment",
@@ -2761,7 +2761,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": "^8.1",
+ "php": "^8.3",
"php-64bit": "*",
"ext-chunkutils2": "^0.3.1",
"ext-crypto": "^0.3.1",
@@ -2790,7 +2790,7 @@
},
"platform-dev": {},
"platform-overrides": {
- "php": "8.1.0"
+ "php": "8.3.0"
},
"plugin-api-version": "2.6.0"
}
diff --git a/src/PocketMine.php b/src/PocketMine.php
index a71c9768d..04b95dd32 100644
--- a/src/PocketMine.php
+++ b/src/PocketMine.php
@@ -55,7 +55,7 @@ namespace pocketmine {
require_once __DIR__ . '/VersionInfo.php';
- const MIN_PHP_VERSION = "8.1.0";
+ const MIN_PHP_VERSION = "8.3.0";
/**
* @param string $message
From 215da7e3f41b2ca30a90094518f6cf3e7234e7d8 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 8 Jun 2025 18:58:42 +0100
Subject: [PATCH 050/140] PHP 8.3 package bumps
---
composer.json | 4 +-
composer.lock | 622 ++++++++++++++++++++++++--------------------------
2 files changed, 298 insertions(+), 328 deletions(-)
diff --git a/composer.json b/composer.json
index 04f08bbeb..80e111175 100644
--- a/composer.json
+++ b/composer.json
@@ -49,13 +49,13 @@
"pocketmine/raklib-ipc": "~1.0.0",
"pocketmine/snooze": "^0.5.0",
"ramsey/uuid": "~4.8.0",
- "symfony/filesystem": "~6.4.0"
+ "symfony/filesystem": "~7.3.0"
},
"require-dev": {
"phpstan/phpstan": "2.1.17",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
- "phpunit/phpunit": "^10.5.24"
+ "phpunit/phpunit": "^12.2.1"
},
"replace": {
"symfony/polyfill-ctype": "*",
diff --git a/composer.lock b/composer.lock
index 5eb9e6da3..bd651e120 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": "3aa2808cfb5b30b7a4eb481d19d76c7e",
+ "content-hash": "d9a2346fa3dbb8503ac686e78349e7f0",
"packages": [
{
"name": "adhocore/json-comment",
@@ -897,25 +897,25 @@
},
{
"name": "symfony/filesystem",
- "version": "v6.4.13",
+ "version": "v7.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3"
+ "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3",
- "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
+ "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
- "symfony/process": "^5.4|^6.4|^7.0"
+ "symfony/process": "^6.4|^7.0"
},
"type": "library",
"autoload": {
@@ -943,7 +943,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v6.4.13"
+ "source": "https://github.com/symfony/filesystem/tree/v7.3.0"
},
"funding": [
{
@@ -959,7 +959,7 @@
"type": "tidelift"
}
],
- "time": "2024-10-25T15:07:50+00:00"
+ "time": "2024-10-25T15:15:23+00:00"
}
],
"packages-dev": [
@@ -1360,35 +1360,34 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "10.1.16",
+ "version": "12.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "7e308268858ed6baedc8704a304727d20bc07c77"
+ "reference": "9075a8efc66e11bc55c319062e147bdb06777267"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
- "reference": "7e308268858ed6baedc8704a304727d20bc07c77",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9075a8efc66e11bc55c319062e147bdb06777267",
+ "reference": "9075a8efc66e11bc55c319062e147bdb06777267",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^4.19.1 || ^5.1.0",
- "php": ">=8.1",
- "phpunit/php-file-iterator": "^4.1.0",
- "phpunit/php-text-template": "^3.0.1",
- "sebastian/code-unit-reverse-lookup": "^3.0.0",
- "sebastian/complexity": "^3.2.0",
- "sebastian/environment": "^6.1.0",
- "sebastian/lines-of-code": "^2.0.2",
- "sebastian/version": "^4.0.1",
+ "nikic/php-parser": "^5.4.0",
+ "php": ">=8.3",
+ "phpunit/php-file-iterator": "^6.0",
+ "phpunit/php-text-template": "^5.0",
+ "sebastian/complexity": "^5.0",
+ "sebastian/environment": "^8.0",
+ "sebastian/lines-of-code": "^4.0",
+ "sebastian/version": "^6.0",
"theseer/tokenizer": "^1.2.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.1"
+ "phpunit/phpunit": "^12.1"
},
"suggest": {
"ext-pcov": "PHP extension that provides line coverage",
@@ -1397,7 +1396,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "10.1.x-dev"
+ "dev-main": "12.3.x-dev"
}
},
"autoload": {
@@ -1426,40 +1425,52 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.0"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
+ "type": "tidelift"
}
],
- "time": "2024-08-22T04:31:57+00:00"
+ "time": "2025-05-23T15:49:03+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "4.1.0",
+ "version": "6.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
- "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -1487,7 +1498,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0"
},
"funding": [
{
@@ -1495,28 +1506,28 @@
"type": "github"
}
],
- "time": "2023-08-31T06:24:48+00:00"
+ "time": "2025-02-07T04:58:37+00:00"
},
{
"name": "phpunit/php-invoker",
- "version": "4.0.0",
+ "version": "6.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-invoker.git",
- "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
- "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
"ext-pcntl": "*",
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"suggest": {
"ext-pcntl": "*"
@@ -1524,7 +1535,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -1550,7 +1561,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
- "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0"
},
"funding": [
{
@@ -1558,32 +1570,32 @@
"type": "github"
}
],
- "time": "2023-02-03T06:56:09+00:00"
+ "time": "2025-02-07T04:58:58+00:00"
},
{
"name": "phpunit/php-text-template",
- "version": "3.0.1",
+ "version": "5.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
- "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.0-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -1610,7 +1622,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
- "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0"
},
"funding": [
{
@@ -1618,32 +1630,32 @@
"type": "github"
}
],
- "time": "2023-08-31T14:07:24+00:00"
+ "time": "2025-02-07T04:59:16+00:00"
},
{
"name": "phpunit/php-timer",
- "version": "6.0.0",
+ "version": "8.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
- "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "6.0-dev"
+ "dev-main": "8.0-dev"
}
},
"autoload": {
@@ -1669,7 +1681,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
- "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0"
},
"funding": [
{
@@ -1677,20 +1690,20 @@
"type": "github"
}
],
- "time": "2023-02-03T06:57:52+00:00"
+ "time": "2025-02-07T04:59:38+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "10.5.46",
+ "version": "12.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d"
+ "reference": "5f09fda04e7caea93cff50b4e90319184f3e6ee3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d",
- "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5f09fda04e7caea93cff50b4e90319184f3e6ee3",
+ "reference": "5f09fda04e7caea93cff50b4e90319184f3e6ee3",
"shasum": ""
},
"require": {
@@ -1703,26 +1716,22 @@
"myclabs/deep-copy": "^1.13.1",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
- "php": ">=8.1",
- "phpunit/php-code-coverage": "^10.1.16",
- "phpunit/php-file-iterator": "^4.1.0",
- "phpunit/php-invoker": "^4.0.0",
- "phpunit/php-text-template": "^3.0.1",
- "phpunit/php-timer": "^6.0.0",
- "sebastian/cli-parser": "^2.0.1",
- "sebastian/code-unit": "^2.0.0",
- "sebastian/comparator": "^5.0.3",
- "sebastian/diff": "^5.1.1",
- "sebastian/environment": "^6.1.0",
- "sebastian/exporter": "^5.1.2",
- "sebastian/global-state": "^6.0.2",
- "sebastian/object-enumerator": "^5.0.0",
- "sebastian/recursion-context": "^5.0.0",
- "sebastian/type": "^4.0.0",
- "sebastian/version": "^4.0.1"
- },
- "suggest": {
- "ext-soap": "To be able to generate mocks based on WSDL files"
+ "php": ">=8.3",
+ "phpunit/php-code-coverage": "^12.3.0",
+ "phpunit/php-file-iterator": "^6.0.0",
+ "phpunit/php-invoker": "^6.0.0",
+ "phpunit/php-text-template": "^5.0.0",
+ "phpunit/php-timer": "^8.0.0",
+ "sebastian/cli-parser": "^4.0.0",
+ "sebastian/comparator": "^7.0.1",
+ "sebastian/diff": "^7.0.0",
+ "sebastian/environment": "^8.0.2",
+ "sebastian/exporter": "^7.0.0",
+ "sebastian/global-state": "^8.0.0",
+ "sebastian/object-enumerator": "^7.0.0",
+ "sebastian/type": "^6.0.2",
+ "sebastian/version": "^6.0.0",
+ "staabm/side-effects-detector": "^1.0.5"
},
"bin": [
"phpunit"
@@ -1730,7 +1739,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "10.5-dev"
+ "dev-main": "12.2-dev"
}
},
"autoload": {
@@ -1762,7 +1771,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.2.1"
},
"funding": [
{
@@ -1786,32 +1795,32 @@
"type": "tidelift"
}
],
- "time": "2025-05-02T06:46:24+00:00"
+ "time": "2025-06-07T05:17:47+00:00"
},
{
"name": "sebastian/cli-parser",
- "version": "2.0.1",
+ "version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/cli-parser.git",
- "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
+ "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
- "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/6d584c727d9114bcdc14c86711cd1cad51778e7c",
+ "reference": "6d584c727d9114bcdc14c86711cd1cad51778e7c",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -1835,7 +1844,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
"security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
- "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.0.0"
},
"funding": [
{
@@ -1843,147 +1852,39 @@
"type": "github"
}
],
- "time": "2024-03-02T07:12:49+00:00"
- },
- {
- "name": "sebastian/code-unit",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit.git",
- "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
- "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
- "role": "lead"
- }
- ],
- "description": "Collection of value objects that represent the PHP code units",
- "homepage": "https://github.com/sebastianbergmann/code-unit",
- "support": {
- "issues": "https://github.com/sebastianbergmann/code-unit/issues",
- "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T06:58:43+00:00"
- },
- {
- "name": "sebastian/code-unit-reverse-lookup",
- "version": "3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
- "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^10.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Looks up which function or method a line of code belongs to",
- "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
- "support": {
- "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
- "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2023-02-03T06:59:15+00:00"
+ "time": "2025-02-07T04:53:50+00:00"
},
{
"name": "sebastian/comparator",
- "version": "5.0.3",
+ "version": "7.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e"
+ "reference": "b478f34614f934e0291598d0c08cbaba9644bee5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
- "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b478f34614f934e0291598d0c08cbaba9644bee5",
+ "reference": "b478f34614f934e0291598d0c08cbaba9644bee5",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-mbstring": "*",
- "php": ">=8.1",
- "sebastian/diff": "^5.0",
- "sebastian/exporter": "^5.0"
+ "php": ">=8.3",
+ "sebastian/diff": "^7.0",
+ "sebastian/exporter": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^10.5"
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-bcmath": "For comparing BcMath\\Number objects"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "5.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2023,7 +1924,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
- "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/7.0.1"
},
"funding": [
{
@@ -2031,33 +1932,33 @@
"type": "github"
}
],
- "time": "2024-10-18T14:56:07+00:00"
+ "time": "2025-03-07T07:00:32+00:00"
},
{
"name": "sebastian/complexity",
- "version": "3.2.0",
+ "version": "5.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git",
- "reference": "68ff824baeae169ec9f2137158ee529584553799"
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
- "reference": "68ff824baeae169ec9f2137158ee529584553799",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb",
"shasum": ""
},
"require": {
- "nikic/php-parser": "^4.18 || ^5.0",
- "php": ">=8.1"
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.2-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -2081,7 +1982,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues",
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
- "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
+ "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0"
},
"funding": [
{
@@ -2089,33 +1990,33 @@
"type": "github"
}
],
- "time": "2023-12-21T08:37:17+00:00"
+ "time": "2025-02-07T04:55:25+00:00"
},
{
"name": "sebastian/diff",
- "version": "5.1.1",
+ "version": "7.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
- "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0",
- "symfony/process": "^6.4"
+ "phpunit/phpunit": "^12.0",
+ "symfony/process": "^7.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "5.1-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2148,7 +2049,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy",
- "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
+ "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
},
"funding": [
{
@@ -2156,27 +2057,27 @@
"type": "github"
}
],
- "time": "2024-03-02T07:15:17+00:00"
+ "time": "2025-02-07T04:55:46+00:00"
},
{
"name": "sebastian/environment",
- "version": "6.1.0",
+ "version": "8.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
+ "reference": "d364b9e5d0d3b18a2573351a1786fbf96b7e0792"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
- "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d364b9e5d0d3b18a2573351a1786fbf96b7e0792",
+ "reference": "d364b9e5d0d3b18a2573351a1786fbf96b7e0792",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"suggest": {
"ext-posix": "*"
@@ -2184,7 +2085,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "6.1-dev"
+ "dev-main": "8.0-dev"
}
},
"autoload": {
@@ -2212,42 +2113,54 @@
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"security": "https://github.com/sebastianbergmann/environment/security/policy",
- "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
+ "source": "https://github.com/sebastianbergmann/environment/tree/8.0.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
+ "type": "tidelift"
}
],
- "time": "2024-03-23T08:47:14+00:00"
+ "time": "2025-05-21T15:05:44+00:00"
},
{
"name": "sebastian/exporter",
- "version": "5.1.2",
+ "version": "7.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "955288482d97c19a372d3f31006ab3f37da47adf"
+ "reference": "76432aafc58d50691a00d86d0632f1217a47b688"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf",
- "reference": "955288482d97c19a372d3f31006ab3f37da47adf",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/76432aafc58d50691a00d86d0632f1217a47b688",
+ "reference": "76432aafc58d50691a00d86d0632f1217a47b688",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
- "php": ">=8.1",
- "sebastian/recursion-context": "^5.0"
+ "php": ">=8.3",
+ "sebastian/recursion-context": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "5.1-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2290,7 +2203,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
- "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2"
+ "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.0"
},
"funding": [
{
@@ -2298,35 +2211,35 @@
"type": "github"
}
],
- "time": "2024-03-02T07:17:12+00:00"
+ "time": "2025-02-07T04:56:42+00:00"
},
{
"name": "sebastian/global-state",
- "version": "6.0.2",
+ "version": "8.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
+ "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
- "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc",
+ "reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc",
"shasum": ""
},
"require": {
- "php": ">=8.1",
- "sebastian/object-reflector": "^3.0",
- "sebastian/recursion-context": "^5.0"
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
},
"require-dev": {
"ext-dom": "*",
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "6.0-dev"
+ "dev-main": "8.0-dev"
}
},
"autoload": {
@@ -2352,7 +2265,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"security": "https://github.com/sebastianbergmann/global-state/security/policy",
- "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
+ "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.0"
},
"funding": [
{
@@ -2360,33 +2273,33 @@
"type": "github"
}
],
- "time": "2024-03-02T07:19:19+00:00"
+ "time": "2025-02-07T04:56:59+00:00"
},
{
"name": "sebastian/lines-of-code",
- "version": "2.0.2",
+ "version": "4.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
- "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
- "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f",
"shasum": ""
},
"require": {
- "nikic/php-parser": "^4.18 || ^5.0",
- "php": ">=8.1"
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -2410,7 +2323,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
"security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
- "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0"
},
"funding": [
{
@@ -2418,34 +2331,34 @@
"type": "github"
}
],
- "time": "2023-12-21T08:38:20+00:00"
+ "time": "2025-02-07T04:57:28+00:00"
},
{
"name": "sebastian/object-enumerator",
- "version": "5.0.0",
+ "version": "7.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
- "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894",
"shasum": ""
},
"require": {
- "php": ">=8.1",
- "sebastian/object-reflector": "^3.0",
- "sebastian/recursion-context": "^5.0"
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "5.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2467,7 +2380,8 @@
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
- "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0"
},
"funding": [
{
@@ -2475,32 +2389,32 @@
"type": "github"
}
],
- "time": "2023-02-03T07:08:32+00:00"
+ "time": "2025-02-07T04:57:48+00:00"
},
{
"name": "sebastian/object-reflector",
- "version": "3.0.0",
+ "version": "5.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
- "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "3.0-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -2522,7 +2436,8 @@
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
- "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0"
},
"funding": [
{
@@ -2530,32 +2445,32 @@
"type": "github"
}
],
- "time": "2023-02-03T07:06:18+00:00"
+ "time": "2025-02-07T04:58:17+00:00"
},
{
"name": "sebastian/recursion-context",
- "version": "5.0.0",
+ "version": "7.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "05909fb5bc7df4c52992396d0116aed689f93712"
+ "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712",
- "reference": "05909fb5bc7df4c52992396d0116aed689f93712",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c405ae3a63e01b32eb71577f8ec1604e39858a7c",
+ "reference": "c405ae3a63e01b32eb71577f8ec1604e39858a7c",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "5.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2585,7 +2500,8 @@
"homepage": "https://github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
- "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0"
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.0"
},
"funding": [
{
@@ -2593,32 +2509,32 @@
"type": "github"
}
],
- "time": "2023-02-03T07:05:40+00:00"
+ "time": "2025-02-07T05:00:01+00:00"
},
{
"name": "sebastian/type",
- "version": "4.0.0",
+ "version": "6.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
- "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
+ "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
- "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/1d7cd6e514384c36d7a390347f57c385d4be6069",
+ "reference": "1d7cd6e514384c36d7a390347f57c385d4be6069",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"require-dev": {
- "phpunit/phpunit": "^10.0"
+ "phpunit/phpunit": "^12.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -2641,7 +2557,8 @@
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
- "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/6.0.2"
},
"funding": [
{
@@ -2649,29 +2566,29 @@
"type": "github"
}
],
- "time": "2023-02-03T07:10:45+00:00"
+ "time": "2025-03-18T13:37:31+00:00"
},
{
"name": "sebastian/version",
- "version": "4.0.1",
+ "version": "6.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
- "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
- "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c",
"shasum": ""
},
"require": {
- "php": ">=8.1"
+ "php": ">=8.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -2694,7 +2611,8 @@
"homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
- "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/6.0.0"
},
"funding": [
{
@@ -2702,7 +2620,59 @@
"type": "github"
}
],
- "time": "2023-02-07T11:34:05+00:00"
+ "time": "2025-02-07T05:00:38+00:00"
+ },
+ {
+ "name": "staabm/side-effects-detector",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/staabm/side-effects-detector.git",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^1.12.6",
+ "phpunit/phpunit": "^9.6.21",
+ "symfony/var-dumper": "^5.4.43",
+ "tomasvotruba/type-coverage": "1.0.0",
+ "tomasvotruba/unused-public": "1.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A static analysis tool to detect side effects in PHP code",
+ "keywords": [
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/staabm/side-effects-detector/issues",
+ "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/staabm",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-20T05:08:20+00:00"
},
{
"name": "theseer/tokenizer",
From 48b80ecf78400f8644ab6f67e40aac702ffd65d1 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 8 Jun 2025 19:01:11 +0100
Subject: [PATCH 051/140] Change crashdump file name format this has bothered
me for ages since it sorts into some absurd order by default due to the name
starting with the day of the week.
this way it'll ensure that the files are always alphanumerically ordered, which means the most recent crashdump should always be
at the bottom.
---
src/Server.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Server.php b/src/Server.php
index 679a0ef0b..d6f0a8415 100644
--- a/src/Server.php
+++ b/src/Server.php
@@ -1618,7 +1618,7 @@ class Server{
if(!is_dir($crashFolder)){
mkdir($crashFolder);
}
- $crashDumpPath = Path::join($crashFolder, date("D_M_j-H.i.s-T_Y", (int) $dump->getData()->time) . ".log");
+ $crashDumpPath = Path::join($crashFolder, date("Y-m-d_H.i.s_T", (int) $dump->getData()->time) . ".log");
$fp = @fopen($crashDumpPath, "wb");
if(!is_resource($fp)){
From 6b5ff5016eaf49064479b3500621bf846304a35a Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 8 Jun 2025 19:09:12 +0100
Subject: [PATCH 052/140] Fixed double loading of PluginDescription
closes #4593
closes #6723
---
src/plugin/FolderPluginLoader.php | 7 ++-----
src/plugin/PharPluginLoader.php | 7 ++-----
src/plugin/PluginLoader.php | 2 +-
src/plugin/PluginManager.php | 2 +-
src/plugin/ScriptPluginLoader.php | 2 +-
5 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/src/plugin/FolderPluginLoader.php b/src/plugin/FolderPluginLoader.php
index 73f6b8841..b881b117b 100644
--- a/src/plugin/FolderPluginLoader.php
+++ b/src/plugin/FolderPluginLoader.php
@@ -41,11 +41,8 @@ class FolderPluginLoader implements PluginLoader{
/**
* Loads the plugin contained in $file
*/
- public function loadPlugin(string $path) : void{
- $description = $this->getPluginDescription($path);
- if($description !== null){
- $this->loader->addPath($description->getSrcNamespacePrefix(), "$path/src");
- }
+ public function loadPlugin(string $path, PluginDescription $description) : void{
+ $this->loader->addPath($description->getSrcNamespacePrefix(), "$path/src");
}
/**
diff --git a/src/plugin/PharPluginLoader.php b/src/plugin/PharPluginLoader.php
index 1ef8f2b84..865ab2edc 100644
--- a/src/plugin/PharPluginLoader.php
+++ b/src/plugin/PharPluginLoader.php
@@ -42,11 +42,8 @@ class PharPluginLoader implements PluginLoader{
/**
* Loads the plugin contained in $file
*/
- public function loadPlugin(string $path) : void{
- $description = $this->getPluginDescription($path);
- if($description !== null){
- $this->loader->addPath($description->getSrcNamespacePrefix(), "$path/src");
- }
+ public function loadPlugin(string $path, PluginDescription $description) : void{
+ $this->loader->addPath($description->getSrcNamespacePrefix(), "$path/src");
}
/**
diff --git a/src/plugin/PluginLoader.php b/src/plugin/PluginLoader.php
index d87daf9fc..b29448965 100644
--- a/src/plugin/PluginLoader.php
+++ b/src/plugin/PluginLoader.php
@@ -36,7 +36,7 @@ interface PluginLoader{
/**
* Loads the plugin contained in $file
*/
- public function loadPlugin(string $path) : void;
+ public function loadPlugin(string $path, PluginDescription $description) : void;
/**
* Gets the PluginDescription from the file
diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php
index 3750af3ef..5e4196d7d 100644
--- a/src/plugin/PluginManager.php
+++ b/src/plugin/PluginManager.php
@@ -150,7 +150,7 @@ class PluginManager{
}
$prefixed = $loader->getAccessProtocol() . $path;
- $loader->loadPlugin($prefixed);
+ $loader->loadPlugin($prefixed, $description);
$mainClass = $description->getMain();
if(!class_exists($mainClass, true)){
diff --git a/src/plugin/ScriptPluginLoader.php b/src/plugin/ScriptPluginLoader.php
index 8e45eaab8..1d0e42d53 100644
--- a/src/plugin/ScriptPluginLoader.php
+++ b/src/plugin/ScriptPluginLoader.php
@@ -46,7 +46,7 @@ class ScriptPluginLoader implements PluginLoader{
/**
* Loads the plugin contained in $file
*/
- public function loadPlugin(string $path) : void{
+ public function loadPlugin(string $path, PluginDescription $description) : void{
include_once $path;
}
From 9e773ed439deeaf61b1d0153e345a844e0ad8f84 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 8 Jun 2025 19:19:17 +0100
Subject: [PATCH 053/140] PHPUnit migrated to attributes :(
---
tests/phpunit/block/BrewingStandTest.php | 10 ++++------
.../command/utils/CommandStringHelperTest.php | 3 ++-
.../ConsoleReaderChildProcessUtilsTest.php | 9 +++------
.../block/upgrade/BlockStateUpgraderTest.php | 13 ++++++-------
tests/phpunit/event/HandlerListManagerTest.php | 7 +++----
.../item/LegacyStringToItemParserTest.php | 5 ++---
.../mcpe/convert/BlockTranslatorTest.php | 5 ++---
tests/phpunit/plugin/ApiVersionTest.php | 8 +++-----
tests/phpunit/scheduler/AsyncPoolTest.php | 4 ++--
.../phpunit/utils/CloningRegistryTraitTest.php | 3 ++-
tests/phpunit/utils/ConfigTest.php | 4 ++--
tests/phpunit/utils/UtilsTest.php | 18 +++++++-----------
.../format/io/region/RegionLoaderTest.php | 7 +++----
.../io/region/RegionLocationTableEntryTest.php | 5 ++---
14 files changed, 43 insertions(+), 58 deletions(-)
diff --git a/tests/phpunit/block/BrewingStandTest.php b/tests/phpunit/block/BrewingStandTest.php
index 85cdd90e1..d36326344 100644
--- a/tests/phpunit/block/BrewingStandTest.php
+++ b/tests/phpunit/block/BrewingStandTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use pocketmine\block\utils\BrewingStandSlot;
use function count;
@@ -39,11 +40,10 @@ class BrewingStandTest extends TestCase{
}
/**
- * @dataProvider slotsProvider
- *
* @param BrewingStandSlot[] $slots
* @phpstan-param list $slots
*/
+ #[DataProvider("slotsProvider")]
public function testHasAndSetSlot(array $slots) : void{
$block = VanillaBlocks::BREWING_STAND();
foreach($slots as $slot){
@@ -62,11 +62,10 @@ class BrewingStandTest extends TestCase{
}
/**
- * @dataProvider slotsProvider
- *
* @param BrewingStandSlot[] $slots
* @phpstan-param list $slots
*/
+ #[DataProvider("slotsProvider")]
public function testGetSlots(array $slots) : void{
$block = VanillaBlocks::BREWING_STAND();
@@ -83,11 +82,10 @@ class BrewingStandTest extends TestCase{
}
/**
- * @dataProvider slotsProvider
- *
* @param BrewingStandSlot[] $slots
* @phpstan-param list $slots
*/
+ #[DataProvider("slotsProvider")]
public function testSetSlots(array $slots) : void{
$block = VanillaBlocks::BREWING_STAND();
diff --git a/tests/phpunit/command/utils/CommandStringHelperTest.php b/tests/phpunit/command/utils/CommandStringHelperTest.php
index 047dc7ceb..01a869ad7 100644
--- a/tests/phpunit/command/utils/CommandStringHelperTest.php
+++ b/tests/phpunit/command/utils/CommandStringHelperTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\command\utils;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class CommandStringHelperTest extends TestCase{
@@ -47,9 +48,9 @@ class CommandStringHelperTest extends TestCase{
}
/**
- * @dataProvider parseQuoteAwareProvider
* @param string[] $expected
*/
+ #[DataProvider("parseQuoteAwareProvider")]
public function testParseQuoteAware(string $commandLine, array $expected) : void{
$actual = CommandStringHelper::parseQuoteAware($commandLine);
diff --git a/tests/phpunit/console/ConsoleReaderChildProcessUtilsTest.php b/tests/phpunit/console/ConsoleReaderChildProcessUtilsTest.php
index 31ae2e27a..5b9209861 100644
--- a/tests/phpunit/console/ConsoleReaderChildProcessUtilsTest.php
+++ b/tests/phpunit/console/ConsoleReaderChildProcessUtilsTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\console;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use function mt_rand;
use function str_repeat;
@@ -40,9 +41,7 @@ final class ConsoleReaderChildProcessUtilsTest extends TestCase{
yield ["give \"Steve\" golden_apple"];
}
- /**
- * @dataProvider commandStringProvider
- */
+ #[DataProvider("commandStringProvider")]
public function testCreateParseSymmetry(string $input) : void{
$counterCreate = $counterParse = mt_rand();
$message = ConsoleReaderChildProcessUtils::createMessage($input, $counterCreate);
@@ -74,9 +73,7 @@ final class ConsoleReaderChildProcessUtilsTest extends TestCase{
yield ["a" . ConsoleReaderChildProcessUtils::TOKEN_DELIMITER . "b", false]; //message with delimiter but not a valid IPC message
}
- /**
- * @dataProvider parseMessageProvider
- */
+ #[DataProvider("parseMessageProvider")]
public static function testParseMessage(string $message, bool $valid) : void{
$counter = $oldCounter = 0;
diff --git a/tests/phpunit/data/bedrock/block/upgrade/BlockStateUpgraderTest.php b/tests/phpunit/data/bedrock/block/upgrade/BlockStateUpgraderTest.php
index 91afd8ed9..9f4416a08 100644
--- a/tests/phpunit/data/bedrock/block/upgrade/BlockStateUpgraderTest.php
+++ b/tests/phpunit/data/bedrock/block/upgrade/BlockStateUpgraderTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\upgrade;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use pocketmine\block\Block;
use pocketmine\data\bedrock\block\BlockStateData;
@@ -126,9 +127,9 @@ class BlockStateUpgraderTest extends TestCase{
}
/**
- * @dataProvider removePropertyProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
+ #[DataProvider("removePropertyProvider")]
public function testRemoveProperty(\Closure $getStateData) : void{
$this->prepareRemovePropertySchema($this->getNewSchema());
@@ -151,9 +152,9 @@ class BlockStateUpgraderTest extends TestCase{
}
/**
- * @dataProvider renamePropertyProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
+ #[DataProvider("renamePropertyProvider")]
public function testRenameProperty(\Closure $getStateData, ?int $valueAfter) : void{
$this->prepareRenamePropertySchema($this->getNewSchema());
@@ -187,9 +188,9 @@ class BlockStateUpgraderTest extends TestCase{
}
/**
- * @dataProvider remapPropertyValueProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
+ #[DataProvider("remapPropertyValueProvider")]
public function testRemapPropertyValue(\Closure $getStateData, ?int $valueAfter) : void{
$this->prepareRemapPropertyValueSchema($this->getNewSchema());
@@ -199,9 +200,9 @@ class BlockStateUpgraderTest extends TestCase{
}
/**
- * @dataProvider remapPropertyValueProvider
* @phpstan-param \Closure() : BlockStateData $getStateData
*/
+ #[DataProvider("remapPropertyValueProvider")]
public function testRemapAndRenameProperty(\Closure $getStateData, ?int $valueAfter) : void{
$schema = $this->getNewSchema();
$this->prepareRenamePropertySchema($schema);
@@ -239,9 +240,7 @@ class BlockStateUpgraderTest extends TestCase{
yield [0x1_00_00_00, 0x1_00_01_00, false, 1]; //Block newer than schema: block must NOT be altered
}
- /**
- * @dataProvider upgraderVersionCompatibilityProvider
- */
+ #[DataProvider("upgraderVersionCompatibilityProvider")]
public function testUpgraderVersionCompatibility(int $schemaVersion, int $stateVersion, bool $shouldChange, int $schemaCount) : void{
for($i = 0; $i < $schemaCount; $i++){
$schema = $this->getNewSchemaVersion($schemaVersion, $i);
diff --git a/tests/phpunit/event/HandlerListManagerTest.php b/tests/phpunit/event/HandlerListManagerTest.php
index c61043dab..9a3c8e505 100644
--- a/tests/phpunit/event/HandlerListManagerTest.php
+++ b/tests/phpunit/event/HandlerListManagerTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\event;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use pocketmine\event\fixtures\TestAbstractAllowHandleEvent;
use pocketmine\event\fixtures\TestAbstractEvent;
@@ -63,10 +64,9 @@ class HandlerListManagerTest extends TestCase{
}
/**
- * @dataProvider isValidClassProvider
- *
* @phpstan-param \ReflectionClass $class
*/
+ #[DataProvider("isValidClassProvider")]
public function testIsValidClass(\ReflectionClass $class, bool $isValid, string $reason) : void{
self::assertSame($isValid, ($this->isValidFunc)($class), $reason);
}
@@ -83,11 +83,10 @@ class HandlerListManagerTest extends TestCase{
}
/**
- * @dataProvider resolveParentClassProvider
- *
* @phpstan-param \ReflectionClass $class
* @phpstan-param \ReflectionClass|null $expect
*/
+ #[DataProvider("resolveParentClassProvider")]
public function testResolveParentClass(\ReflectionClass $class, ?\ReflectionClass $expect) : void{
if($expect === null){
self::assertNull(($this->resolveParentFunc)($class));
diff --git a/tests/phpunit/item/LegacyStringToItemParserTest.php b/tests/phpunit/item/LegacyStringToItemParserTest.php
index f9243df7e..78f9e16b3 100644
--- a/tests/phpunit/item/LegacyStringToItemParserTest.php
+++ b/tests/phpunit/item/LegacyStringToItemParserTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\item;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use pocketmine\block\VanillaBlocks;
@@ -43,9 +44,7 @@ class LegacyStringToItemParserTest extends TestCase{
];
}
- /**
- * @dataProvider itemFromStringProvider
- */
+ #[DataProvider("itemFromStringProvider")]
public function testFromStringSingle(string $string, Item $expected) : void{
$item = LegacyStringToItemParser::getInstance()->parse($string);
diff --git a/tests/phpunit/network/mcpe/convert/BlockTranslatorTest.php b/tests/phpunit/network/mcpe/convert/BlockTranslatorTest.php
index ef8e297c4..864acbfeb 100644
--- a/tests/phpunit/network/mcpe/convert/BlockTranslatorTest.php
+++ b/tests/phpunit/network/mcpe/convert/BlockTranslatorTest.php
@@ -23,14 +23,13 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\convert;
+use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use PHPUnit\Framework\TestCase;
use pocketmine\block\RuntimeBlockStateRegistry;
class BlockTranslatorTest extends TestCase{
- /**
- * @doesNotPerformAssertions
- */
+ #[DoesNotPerformAssertions]
public function testAllBlockStatesSerialize() : void{
$blockTranslator = TypeConverter::getInstance()->getBlockTranslator();
foreach(RuntimeBlockStateRegistry::getInstance()->getAllKnownStates() as $state){
diff --git a/tests/phpunit/plugin/ApiVersionTest.php b/tests/phpunit/plugin/ApiVersionTest.php
index faa68200d..55afdbc73 100644
--- a/tests/phpunit/plugin/ApiVersionTest.php
+++ b/tests/phpunit/plugin/ApiVersionTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\plugin;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use function sort;
@@ -47,9 +48,7 @@ class ApiVersionTest extends TestCase{
yield ["3.0.0-ALPHA1", "4.0.0-ALPHA1", false];
}
- /**
- * @dataProvider compatibleApiProvider
- */
+ #[DataProvider("compatibleApiProvider")]
public function testCompatibleApi(string $myVersion, string $wantVersion, bool $expected) : void{
self::assertSame($expected, ApiVersion::isCompatible($myVersion, [$wantVersion]), "my version: $myVersion, their version: $wantVersion, expect " . ($expected ? "yes" : "no"));
}
@@ -67,11 +66,10 @@ class ApiVersionTest extends TestCase{
}
/**
- * @dataProvider ambiguousVersionsProvider
- *
* @param string[] $input
* @param string[] $expectedOutput
*/
+ #[DataProvider("ambiguousVersionsProvider")]
public function testFindAmbiguousVersions(array $input, array $expectedOutput) : void{
$ambiguous = ApiVersion::checkAmbiguousVersions($input);
diff --git a/tests/phpunit/scheduler/AsyncPoolTest.php b/tests/phpunit/scheduler/AsyncPoolTest.php
index 0f2e8554d..5f026c243 100644
--- a/tests/phpunit/scheduler/AsyncPoolTest.php
+++ b/tests/phpunit/scheduler/AsyncPoolTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\scheduler;
+use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use PHPUnit\Framework\TestCase;
use pmmp\thread\ThreadSafeArray;
use pocketmine\promise\PromiseResolver;
@@ -84,9 +85,8 @@ class AsyncPoolTest extends TestCase{
*
* Due to an unset() in the function body, other AsyncTask::__destruct() calls could be triggered during
* an AsyncTask's destruction. If done in the wrong way, this could lead to a crash.
- *
- * @doesNotPerformAssertions This test is checking for a crash condition, not a specific output.
*/
+ #[DoesNotPerformAssertions]
public function testTaskDestructorReentrancy() : void{
$this->pool->submitTask(new class extends AsyncTask{
public function __construct(){
diff --git a/tests/phpunit/utils/CloningRegistryTraitTest.php b/tests/phpunit/utils/CloningRegistryTraitTest.php
index e3b53ecb5..a343d0033 100644
--- a/tests/phpunit/utils/CloningRegistryTraitTest.php
+++ b/tests/phpunit/utils/CloningRegistryTraitTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\utils;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
final class CloningRegistryTraitTest extends TestCase{
@@ -37,9 +38,9 @@ final class CloningRegistryTraitTest extends TestCase{
}
/**
- * @dataProvider cloningRegistryMembersProvider
* @phpstan-param \Closure() : \stdClass $provider
*/
+ #[DataProvider("cloningRegistryMembersProvider")]
public function testEachMemberClone(\Closure $provider) : void{
self::assertNotSame($provider(), $provider(), "Cloning registry should never return the same object twice");
}
diff --git a/tests/phpunit/utils/ConfigTest.php b/tests/phpunit/utils/ConfigTest.php
index 55b4bc2d4..102a8dcf7 100644
--- a/tests/phpunit/utils/ConfigTest.php
+++ b/tests/phpunit/utils/ConfigTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\utils;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use function yaml_parse;
@@ -60,10 +61,9 @@ class ConfigTest extends TestCase{
}
/**
- * @dataProvider fixYamlIndexesProvider
- *
* @param mixed[] $expected
*/
+ #[DataProvider("fixYamlIndexesProvider")]
public function testFixYamlIndexes(string $test, array $expected) : void{
$fixed = Config::fixYAMLIndexes($test);
$decoded = yaml_parse($fixed);
diff --git a/tests/phpunit/utils/UtilsTest.php b/tests/phpunit/utils/UtilsTest.php
index f061abac2..96254ca01 100644
--- a/tests/phpunit/utils/UtilsTest.php
+++ b/tests/phpunit/utils/UtilsTest.php
@@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\utils;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use PHPUnit\Framework\TestCase;
use pocketmine\utils\fixtures\TestAbstractClass;
use pocketmine\utils\fixtures\TestInstantiableClass;
@@ -52,9 +54,7 @@ class UtilsTest extends TestCase{
];
}
- /**
- * @dataProvider parseDocCommentNewlineProvider
- */
+ #[DataProvider("parseDocCommentNewlineProvider")]
public function testParseDocCommentNewlines(string $docComment) : void{
$tags = Utils::parseDocComment($docComment);
@@ -76,9 +76,7 @@ class UtilsTest extends TestCase{
];
}
- /**
- * @dataProvider parseDocCommentOneLineProvider
- */
+ #[DataProvider("parseDocCommentOneLineProvider")]
public function testParseOneLineDocComment(string $comment) : void{
$tags = Utils::parseDocComment($comment);
self::assertArrayHasKey("ignoreCancelled", $tags);
@@ -120,11 +118,11 @@ class UtilsTest extends TestCase{
}
/**
- * @dataProvider validInstanceProvider
- * @doesNotPerformAssertions
* @phpstan-param class-string $className
* @phpstan-param class-string $baseName
*/
+ #[DataProvider("validInstanceProvider")]
+ #[DoesNotPerformAssertions]
public function testValidInstanceWithValidCombinations(string $className, string $baseName) : void{
Utils::testValidInstance($className, $baseName);
}
@@ -146,9 +144,7 @@ class UtilsTest extends TestCase{
];
}
- /**
- * @dataProvider validInstanceInvalidCombinationsProvider
- */
+ #[DataProvider("validInstanceInvalidCombinationsProvider")]
public function testValidInstanceInvalidParameters(string $className, string $baseName) : void{
$this->expectException(\InvalidArgumentException::class);
Utils::testValidInstance($className, $baseName); //@phpstan-ignore-line
diff --git a/tests/phpunit/world/format/io/region/RegionLoaderTest.php b/tests/phpunit/world/format/io/region/RegionLoaderTest.php
index ee96b6bc0..6d715867d 100644
--- a/tests/phpunit/world/format/io/region/RegionLoaderTest.php
+++ b/tests/phpunit/world/format/io/region/RegionLoaderTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use pocketmine\world\format\ChunkException;
use Symfony\Component\Filesystem\Path;
@@ -82,11 +83,10 @@ class RegionLoaderTest extends TestCase{
}
/**
- * @dataProvider outOfBoundsCoordsProvider
- *
* @throws ChunkException
* @throws \InvalidArgumentException
*/
+ #[DataProvider("outOfBoundsCoordsProvider")]
public function testWriteChunkOutOfBounds(int $x, int $z) : void{
$this->expectException(\InvalidArgumentException::class);
$this->region->writeChunk($x, $z, str_repeat("\x00", 1000));
@@ -107,11 +107,10 @@ class RegionLoaderTest extends TestCase{
}
/**
- * @dataProvider outOfBoundsCoordsProvider
- *
* @throws \InvalidArgumentException
* @throws \pocketmine\world\format\io\exception\CorruptedChunkException
*/
+ #[DataProvider("outOfBoundsCoordsProvider")]
public function testReadChunkOutOfBounds(int $x, int $z) : void{
$this->expectException(\InvalidArgumentException::class);
$this->region->readChunk($x, $z);
diff --git a/tests/phpunit/world/format/io/region/RegionLocationTableEntryTest.php b/tests/phpunit/world/format/io/region/RegionLocationTableEntryTest.php
index 498e2767e..7aa67fabc 100644
--- a/tests/phpunit/world/format/io/region/RegionLocationTableEntryTest.php
+++ b/tests/phpunit/world/format/io/region/RegionLocationTableEntryTest.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\world\format\io\region;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use function sprintf;
@@ -40,9 +41,7 @@ class RegionLocationTableEntryTest extends TestCase{
yield [new RegionLocationTableEntry(2, 4, 0), new RegionLocationTableEntry(3, 1, 0), true];
}
- /**
- * @dataProvider overlapDataProvider
- */
+ #[DataProvider("overlapDataProvider")]
public function testOverlap(RegionLocationTableEntry $entry1, RegionLocationTableEntry $entry2, bool $overlaps) : void{
$stringify = function(RegionLocationTableEntry $entry) : string{
return sprintf("entry first=%d last=%d size=%d", $entry->getFirstSector(), $entry->getLastSector(), $entry->getSectorCount());
From 8229ee18126da6e5dbef0632232faddd3d767340 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Wed, 11 Jun 2025 21:02:31 +0100
Subject: [PATCH 054/140] ChunkLoader is now a final class (#6730)
---
src/player/Player.php | 2 +-
src/world/ChunkLoader.php | 2 +-
src/world/World.php | 7 +++----
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/player/Player.php b/src/player/Player.php
index d0003d4b2..762187b24 100644
--- a/src/player/Player.php
+++ b/src/player/Player.php
@@ -342,7 +342,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->spawnThreshold = (int) (($this->server->getConfigGroup()->getPropertyInt(YmlServerProperties::CHUNK_SENDING_SPAWN_RADIUS, 4) ** 2) * M_PI);
$this->chunkSelector = new ChunkSelector();
- $this->chunkLoader = new class implements ChunkLoader{};
+ $this->chunkLoader = new ChunkLoader();
$this->chunkTicker = new ChunkTicker();
$world = $spawnLocation->getWorld();
//load the spawn chunk so we can see the terrain
diff --git a/src/world/ChunkLoader.php b/src/world/ChunkLoader.php
index 9e909e928..c81c8e3ea 100644
--- a/src/world/ChunkLoader.php
+++ b/src/world/ChunkLoader.php
@@ -32,6 +32,6 @@ namespace pocketmine\world;
* WARNING: When moving this object around in the world or destroying it,
* be sure to unregister the loader from chunks you're not using, otherwise you'll leak memory.
*/
-interface ChunkLoader{
+final class ChunkLoader{
}
diff --git a/src/world/World.php b/src/world/World.php
index 44c8d3cd7..7264b90e2 100644
--- a/src/world/World.php
+++ b/src/world/World.php
@@ -3321,7 +3321,7 @@ class World implements ChunkManager{
/** @phpstan-var PromiseResolver $resolver */
$resolver = $this->chunkPopulationRequestMap[$chunkHash] = new PromiseResolver();
if($associatedChunkLoader === null){
- $temporaryLoader = new class implements ChunkLoader{};
+ $temporaryLoader = new ChunkLoader();
$this->registerChunkLoader($temporaryLoader, $chunkX, $chunkZ);
$resolver->getPromise()->onCompletion(
fn() => $this->unregisterChunkLoader($temporaryLoader, $chunkX, $chunkZ),
@@ -3368,7 +3368,7 @@ class World implements ChunkManager{
return [$resolver, false];
}
- $temporaryChunkLoader = new class implements ChunkLoader{};
+ $temporaryChunkLoader = new ChunkLoader();
$this->registerChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ);
$chunk = $this->loadChunk($chunkX, $chunkZ);
$this->unregisterChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ);
@@ -3453,8 +3453,7 @@ class World implements ChunkManager{
$chunkPopulationLockId = new ChunkLockId();
- $temporaryChunkLoader = new class implements ChunkLoader{
- };
+ $temporaryChunkLoader = new ChunkLoader();
for($xx = -1; $xx <= 1; ++$xx){
for($zz = -1; $zz <= 1; ++$zz){
$this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId);
From 95b4db5169db52777b826f3ea804c42c52c42100 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Wed, 11 Jun 2025 21:29:03 +0100
Subject: [PATCH 055/140] Fix slow SubChunk garbage collection check, closes
#6574 (#6731)
---
src/world/format/SubChunk.php | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/world/format/SubChunk.php b/src/world/format/SubChunk.php
index d8546e7e9..cc6673430 100644
--- a/src/world/format/SubChunk.php
+++ b/src/world/format/SubChunk.php
@@ -134,11 +134,8 @@ class SubChunk{
foreach($this->blockLayers as $layer){
$layer->collectGarbage();
- foreach($layer->getPalette() as $p){
- if($p !== $this->emptyBlockId){
- $cleanedLayers[] = $layer;
- continue 2;
- }
+ if($layer->getBitsPerBlock() !== 0 || $layer->get(0, 0, 0) !== $this->emptyBlockId){
+ $cleanedLayers[] = $layer;
}
}
$this->blockLayers = $cleanedLayers;
From 9c71f4fc1ce6ed1beeff9f55b8b209fa361983cb Mon Sep 17 00:00:00 2001
From: Dries C <15795262+dries-c@users.noreply.github.com>
Date: Wed, 18 Jun 2025 02:15:00 +0200
Subject: [PATCH 056/140] Assemble 1.21.90 (#6736)
---
changelogs/5.29.md | 25 +++++++
composer.json | 4 +-
composer.lock | 26 +++----
src/VersionInfo.php | 4 +-
src/data/bedrock/item/ItemTypeNames.php | 1 +
.../mcpe/handler/LoginPacketHandler.php | 71 +++++++++++++++++--
.../mcpe/handler/PreSpawnPacketHandler.php | 3 +-
.../handler/ResourcePacksPacketHandler.php | 3 +-
src/world/format/io/data/BedrockWorldData.php | 4 +-
9 files changed, 115 insertions(+), 26 deletions(-)
create mode 100644 changelogs/5.29.md
diff --git a/changelogs/5.29.md b/changelogs/5.29.md
new file mode 100644
index 000000000..cb6e50da3
--- /dev/null
+++ b/changelogs/5.29.md
@@ -0,0 +1,25 @@
+# 5.29.0
+Released 18th June 2025.
+
+This is a support release for Minecraft: Bedrock Edition 1.21.90.
+
+**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.21.90.
+- Removed support for earlier versions.
+
+## Fixes
+- Fixed thread crashes sometimes not reporting proper cause information in crashdumps.
+- Fixed crash when a plugin replaced a player's held tool with a different tool with a damage exceeding the old tool's max damage during an action.
+- Fixed performance issue of `PlayerAuthInputPacket` input flags handling (broken change detection).
+- Fixed `BaseInventory->addItem()` triggering updates on empty slots when no items were added.
+- Fixed slow check in `SubChunk` block layer garbage collection.
+
+## Internals
+- `LoginPacketHandler->processLogin()` signature has changed. This will break any plugins overriding `LoginPacketHandler`. As noted above, this is _not_ covered by the API version guarantee.
+- Automated branch sync for `minor-next` and `major-next` is now triggered by `repository_dispatch` from a cron job in this repository instead of `RestrictedActions`. The `RestrictedActions` cron job was getting automatically disabled by GitHub due to repo inactivity.
diff --git a/composer.json b/composer.json
index 1935bc290..1decaac39 100644
--- a/composer.json
+++ b/composer.json
@@ -34,9 +34,9 @@
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
- "pocketmine/bedrock-data": "~5.0.0+bedrock-1.21.80",
+ "pocketmine/bedrock-data": "~5.1.0+bedrock-1.21.90",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
- "pocketmine/bedrock-protocol": "~38.1.0+bedrock-1.21.80",
+ "pocketmine/bedrock-protocol": "~39.0.0+bedrock-1.21.90",
"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 cb60c7ace..b6db8fe7d 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": "69921783f476a0704fa1f8924b901a89",
+ "content-hash": "bde74cbb65c043a2acf6f62b5b328e67",
"packages": [
{
"name": "adhocore/json-comment",
@@ -204,16 +204,16 @@
},
{
"name": "pocketmine/bedrock-data",
- "version": "5.0.0+bedrock-1.21.80",
+ "version": "5.1.0+bedrock-1.21.90",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
- "reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080"
+ "reference": "89ed34957aeccc63e517aa849af593adae958e98"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/e38d5ea19f794ec5216e5f96742237e8c4e7f080",
- "reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080",
+ "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/89ed34957aeccc63e517aa849af593adae958e98",
+ "reference": "89ed34957aeccc63e517aa849af593adae958e98",
"shasum": ""
},
"type": "library",
@@ -224,9 +224,9 @@
"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.21.80"
+ "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.90"
},
- "time": "2025-05-09T14:15:18+00:00"
+ "time": "2025-06-17T23:44:21+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
@@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "38.1.0+bedrock-1.21.80",
+ "version": "39.0.0+bedrock-1.21.90",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "a1fa215563517050045309bb779a67f75843b867"
+ "reference": "2b088183d12fc003523400867ee398e3893899ed"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a1fa215563517050045309bb779a67f75843b867",
- "reference": "a1fa215563517050045309bb779a67f75843b867",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2b088183d12fc003523400867ee398e3893899ed",
+ "reference": "2b088183d12fc003523400867ee398e3893899ed",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/38.1.0+bedrock-1.21.80"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/39.0.0+bedrock-1.21.90"
},
- "time": "2025-05-28T22:19:59+00:00"
+ "time": "2025-06-17T23:46:38+00:00"
},
{
"name": "pocketmine/binaryutils",
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 615024656..7033c2707 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.28.3";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const BASE_VERSION = "5.29.0";
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
diff --git a/src/data/bedrock/item/ItemTypeNames.php b/src/data/bedrock/item/ItemTypeNames.php
index 5f86cde96..d2ab0996b 100644
--- a/src/data/bedrock/item/ItemTypeNames.php
+++ b/src/data/bedrock/item/ItemTypeNames.php
@@ -380,6 +380,7 @@ final class ItemTypeNames{
public const MUSIC_DISC_RELIC = "minecraft:music_disc_relic";
public const MUSIC_DISC_STAL = "minecraft:music_disc_stal";
public const MUSIC_DISC_STRAD = "minecraft:music_disc_strad";
+ public const MUSIC_DISC_TEARS = "minecraft:music_disc_tears";
public const MUSIC_DISC_WAIT = "minecraft:music_disc_wait";
public const MUSIC_DISC_WARD = "minecraft:music_disc_ward";
public const MUTTON = "minecraft:mutton";
diff --git a/src/network/mcpe/handler/LoginPacketHandler.php b/src/network/mcpe/handler/LoginPacketHandler.php
index c15753dad..5c467f2d4 100644
--- a/src/network/mcpe/handler/LoginPacketHandler.php
+++ b/src/network/mcpe/handler/LoginPacketHandler.php
@@ -33,6 +33,8 @@ use pocketmine\network\mcpe\JwtUtils;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\LoginPacket;
use pocketmine\network\mcpe\protocol\types\login\AuthenticationData;
+use pocketmine\network\mcpe\protocol\types\login\AuthenticationInfo;
+use pocketmine\network\mcpe\protocol\types\login\AuthenticationType;
use pocketmine\network\mcpe\protocol\types\login\ClientData;
use pocketmine\network\mcpe\protocol\types\login\ClientDataToSkinDataHelper;
use pocketmine\network\mcpe\protocol\types\login\JwtChain;
@@ -42,7 +44,11 @@ use pocketmine\player\PlayerInfo;
use pocketmine\player\XboxLivePlayerInfo;
use pocketmine\Server;
use Ramsey\Uuid\Uuid;
+use function gettype;
use function is_array;
+use function is_object;
+use function json_decode;
+use const JSON_THROW_ON_ERROR;
/**
* Handles the initial login phase of the session. This handler is used as the initial state.
@@ -60,7 +66,9 @@ class LoginPacketHandler extends PacketHandler{
){}
public function handleLogin(LoginPacket $packet) : bool{
- $extraData = $this->fetchAuthData($packet->chainDataJwt);
+ $authInfo = $this->parseAuthInfo($packet->authInfoJson);
+ $jwtChain = $this->parseJwtChain($authInfo->Certificate);
+ $extraData = $this->fetchAuthData($jwtChain);
if(!Player::isValidUserName($extraData->displayName)){
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_invalidName());
@@ -139,11 +147,61 @@ class LoginPacketHandler extends PacketHandler{
return true;
}
- $this->processLogin($packet, $ev->isAuthRequired());
+ $this->processLogin($authInfo->Token, AuthenticationType::from($authInfo->AuthenticationType), $jwtChain->chain, $packet->clientDataJwt, $ev->isAuthRequired());
return true;
}
+ /**
+ * @throws PacketHandlingException
+ */
+ protected function parseAuthInfo(string $authInfo) : AuthenticationInfo{
+ try{
+ $authInfoJson = json_decode($authInfo, associative: false, flags: JSON_THROW_ON_ERROR);
+ }catch(\JsonException $e){
+ throw PacketHandlingException::wrap($e);
+ }
+ if(!is_object($authInfoJson)){
+ throw new \RuntimeException("Unexpected type for auth info data: " . gettype($authInfoJson) . ", expected object");
+ }
+
+ $mapper = new \JsonMapper();
+ $mapper->bExceptionOnMissingData = true;
+ $mapper->bExceptionOnUndefinedProperty = true;
+ $mapper->bStrictObjectTypeChecking = true;
+ try{
+ $clientData = $mapper->map($authInfoJson, new AuthenticationInfo());
+ }catch(\JsonMapper_Exception $e){
+ throw PacketHandlingException::wrap($e);
+ }
+ return $clientData;
+ }
+
+ /**
+ * @throws PacketHandlingException
+ */
+ protected function parseJwtChain(string $chainDataJwt) : JwtChain{
+ try{
+ $jwtChainJson = json_decode($chainDataJwt, associative: false, flags: JSON_THROW_ON_ERROR);
+ }catch(\JsonException $e){
+ throw PacketHandlingException::wrap($e);
+ }
+ if(!is_object($jwtChainJson)){
+ throw new \RuntimeException("Unexpected type for JWT chain data: " . gettype($jwtChainJson) . ", expected object");
+ }
+
+ $mapper = new \JsonMapper();
+ $mapper->bExceptionOnMissingData = true;
+ $mapper->bExceptionOnUndefinedProperty = true;
+ $mapper->bStrictObjectTypeChecking = true;
+ try{
+ $clientData = $mapper->map($jwtChainJson, new JwtChain());
+ }catch(\JsonMapper_Exception $e){
+ throw PacketHandlingException::wrap($e);
+ }
+ return $clientData;
+ }
+
/**
* @throws PacketHandlingException
*/
@@ -211,10 +269,15 @@ class LoginPacketHandler extends PacketHandler{
* TODO: This is separated for the purposes of allowing plugins (like Specter) to hack it and bypass authentication.
* In the future this won't be necessary.
*
+ * @param null|string[] $legacyCertificate
+ *
* @throws \InvalidArgumentException
*/
- protected function processLogin(LoginPacket $packet, bool $authRequired) : void{
- $this->server->getAsyncPool()->submitTask(new ProcessLoginTask($packet->chainDataJwt->chain, $packet->clientDataJwt, $authRequired, $this->authCallback));
+ protected function processLogin(string $token, AuthenticationType $authType, ?array $legacyCertificate, string $clientData, bool $authRequired) : void{
+ if($legacyCertificate === null){
+ throw new PacketHandlingException("Legacy certificate cannot be null");
+ }
+ $this->server->getAsyncPool()->submitTask(new ProcessLoginTask($legacyCertificate, $clientData, $authRequired, $this->authCallback));
$this->session->setHandler(null); //drop packets received during login verification
}
}
diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php
index 9aa302c0c..e528a5201 100644
--- a/src/network/mcpe/handler/PreSpawnPacketHandler.php
+++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php
@@ -40,7 +40,6 @@ use pocketmine\network\mcpe\protocol\types\Experiments;
use pocketmine\network\mcpe\protocol\types\LevelSettings;
use pocketmine\network\mcpe\protocol\types\NetworkPermissions;
use pocketmine\network\mcpe\protocol\types\PlayerMovementSettings;
-use pocketmine\network\mcpe\protocol\types\ServerAuthMovementMode;
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
use pocketmine\player\Player;
use pocketmine\Server;
@@ -99,7 +98,7 @@ class PreSpawnPacketHandler extends PacketHandler{
$this->server->getMotd(),
"",
false,
- new PlayerMovementSettings(ServerAuthMovementMode::SERVER_AUTHORITATIVE_V2, 0, false),
+ new PlayerMovementSettings(0, false),
0,
0,
"",
diff --git a/src/network/mcpe/handler/ResourcePacksPacketHandler.php b/src/network/mcpe/handler/ResourcePacksPacketHandler.php
index a1df394da..a9ffae6f7 100644
--- a/src/network/mcpe/handler/ResourcePacksPacketHandler.php
+++ b/src/network/mcpe/handler/ResourcePacksPacketHandler.php
@@ -120,7 +120,8 @@ class ResourcePacksPacketHandler extends PacketHandler{
hasAddons: false,
hasScripts: false,
worldTemplateId: Uuid::fromString(Uuid::NIL),
- worldTemplateVersion: ""
+ worldTemplateVersion: "",
+ forceDisableVibrantVisuals: true,
));
$this->session->getLogger()->debug("Waiting for client to accept resource packs");
}
diff --git a/src/world/format/io/data/BedrockWorldData.php b/src/world/format/io/data/BedrockWorldData.php
index d39c17a47..a971920ec 100644
--- a/src/world/format/io/data/BedrockWorldData.php
+++ b/src/world/format/io/data/BedrockWorldData.php
@@ -51,11 +51,11 @@ use function time;
class BedrockWorldData extends BaseNbtWorldData{
public const CURRENT_STORAGE_VERSION = 10;
- public const CURRENT_STORAGE_NETWORK_VERSION = 800;
+ public const CURRENT_STORAGE_NETWORK_VERSION = 818;
public const CURRENT_CLIENT_VERSION_TARGET = [
1, //major
21, //minor
- 80, //patch
+ 90, //patch
3, //revision
0 //is beta
];
From 8843b1b5685a07f626bf9f62be7d0b6ce12411b4 Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Wed, 18 Jun 2025 00:16:13 +0000
Subject: [PATCH 057/140] 5.29.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15720776704
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 7033c2707..ec525d6c3 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.29.0";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.29.1";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From 670d3fb9971c0622666894da359ad2bd0aa34d3d Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Wed, 18 Jun 2025 19:29:28 +0100
Subject: [PATCH 058/140] Mention developer team in draft release notification
---
.github/workflows/draft-release.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml
index fa20d1912..ca48ab8e0 100644
--- a/.github/workflows/draft-release.yml
+++ b/.github/workflows/draft-release.yml
@@ -188,4 +188,4 @@ jobs:
if: github.event_name == 'pull_request_target'
uses: thollander/actions-comment-pull-request@v3
with:
- message: "[Draft release ${{ steps.get-pm-version.outputs.PM_VERSION }}](${{ steps.create-draft.outputs.html_url }}) has been created for commit ${{ github.sha }}. Please review and publish it."
+ message: "${{ vars.DRAFT_RELEASE_NOTIFICATION_MENTION }} [Draft release ${{ steps.get-pm-version.outputs.PM_VERSION }}](${{ steps.create-draft.outputs.html_url }}) has been created for commit ${{ github.sha }}. Please review and publish it."
From 3643d3aeb81baf8ad2cc4e8b8409e6dd3ab1b5f5 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 18 Jun 2025 20:42:10 +0100
Subject: [PATCH 059/140] Ready 5.30.0 release
---
changelogs/5.30.md | 55 +++++++++++++++++++++++++++++++++++++++++++++
src/VersionInfo.php | 4 ++--
2 files changed, 57 insertions(+), 2 deletions(-)
create mode 100644 changelogs/5.30.md
diff --git a/changelogs/5.30.md b/changelogs/5.30.md
new file mode 100644
index 000000000..50889df26
--- /dev/null
+++ b/changelogs/5.30.md
@@ -0,0 +1,55 @@
+# 5.30.0
+Released 18th June 2025.
+
+This is a minor feature release containing API additions, internals cleanup and user experience improvements.
+
+**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
+- Significantly reduced log spam when unknown blocks, tiles and entities are found in saved worlds.
+- The file name structure for crashdumps has been changed to improve sorting order in file browsers.
+- Buffering is now skipped on the RakLib layer. In theory this could reduce player network latency by 10 ms (YMMV).
+
+## Gameplay
+### Blocks
+- Many blocks have had their hardness and blast resistance updated to match vanilla.
+- Implemented Respawn Anchor.
+- Melon Stem and Pumpkin Stem drop amounts should now match vanilla (using binomial distribution).
+
+## API
+## General
+- Verification of save registration has been added for blocks, entities and tiles. This is intended to make it easier to find mistakes when registering custom things, which previously would produce obscure core crashes.
+
+### `pocketmine\event\entity`
+- The following classes have been added:
+ - `EntityExtinguishEvent` - called when a burning entity is extinguished by water or other sources
+ - `EntityFrostWalkerEvent` - called every tick upon which an entity wearing Frost Walker boots moves; this can be used to customise or cancel the behaviour of the Frost Walker enchantment
+
+### `pocketmine\entity`
+- The following methods have been added:
+ - `public Entity->getStepHeight() : float`
+ - `public Entity->setStepHeight(float $stepHeight) : void`
+
+### `pocketmine\world\generator`
+- Generator execution has been decoupled from `PopulationTask` and async tasks in general. The following classes have been added:
+ - `executor\GeneratorExecutor`
+ - `executor\SyncGeneratorExecutor` - runs a generator on the main thread (used for flat world generation, which doesn't need threads)
+ - `executor\AsyncGeneratorExecutor` - runs a generator inside an async task, as before
+ - `PopulationUtils` - contains population business logic previously baked into `PopulationTask` - this permits the reuse of that logic outside async tasks
+- The following methods have signature changes:
+ - `GeneratorManager->addGenerator()` now accepts an optional `bool $fast` parameter, defaulting to `false`; setting this to `true` will cause your generator to run on the main thread
+- The following methods have been added:
+ - `public GeneratorManagerEntry->isFast() : bool` - returns whether this generator should run on the main thread
+- `PopulationTask` has been marked as `@internal`. In the next major version, it will move to the `generator\executor` namespace; however, for now it stays put because plugins currently have no other way to regenerate chunks.
+
+## Internals
+- World data version numbers have been consolidated in `pocketmine\data\bedrock\WorldDataVersions`. This removes the need to modify several different files to support new world versions, and reduces the chances of things getting missed.
+- Block hardness and blast resistance is now unit-tested against `block_properties_table.json` in `BedrockData`. This file comes from vanilla BDS, so we can use it to verify compliance.
+- Protocol-layer "server auth block breaking" has been enabled. Functionally, this is no different from the previous system, it just works differently on the network layer.
+- Various internal classes in the `pocketmine\world\generator` namespace have been moved to the `generator\executor` namespace.
+- Removed `World->registerGenerator()` and `World->unregisterGenerator()`.
+- Removed redundant calls to `curl_close()` (obsolete since PHP 8.0).
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index ec525d6c3..0b6a601bc 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.29.1";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const BASE_VERSION = "5.30.0";
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
From 682642087613f7c4ef5b34194253e2cd088fa3ce Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Wed, 18 Jun 2025 20:49:31 +0000
Subject: [PATCH 060/140] 5.30.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15743323722
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 0b6a601bc..e6b323974 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.30.0";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.30.1";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From 0e511ff783e5a5a3443622835fc775eecaf96c12 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 18 Jun 2025 21:55:53 +0100
Subject: [PATCH 061/140] smh
---
changelogs/5.30.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/changelogs/5.30.md b/changelogs/5.30.md
index 50889df26..6e9762ea9 100644
--- a/changelogs/5.30.md
+++ b/changelogs/5.30.md
@@ -24,11 +24,20 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
## General
- Verification of save registration has been added for blocks, entities and tiles. This is intended to make it easier to find mistakes when registering custom things, which previously would produce obscure core crashes.
+### `pocketmine\event\block`
+- The following classes have been added:
+ - `BlockPreExplodeEvent` - called before a block tries to explode
+ - `BlockExplodeEvent` - called when after a block's explosion calculation has been done, but before any changes are applied
+
### `pocketmine\event\entity`
- The following classes have been added:
- `EntityExtinguishEvent` - called when a burning entity is extinguished by water or other sources
- `EntityFrostWalkerEvent` - called every tick upon which an entity wearing Frost Walker boots moves; this can be used to customise or cancel the behaviour of the Frost Walker enchantment
+### `pocketmine\event\player`
+- The following classes have been added:
+ - `PlayerRespawnAnchorUseEvent` - called when a player interacts with a charged respawn anchor
+
### `pocketmine\entity`
- The following methods have been added:
- `public Entity->getStepHeight() : float`
From 04494e845c8ec9ae174604b6dde6c1cc6c22953a Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Fri, 20 Jun 2025 15:26:42 +0100
Subject: [PATCH 062/140] EntityExplodeEvent: Fixed accidental BC break
introduced by #6646
thanks @Yexeed
---
src/event/entity/EntityExplodeEvent.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/event/entity/EntityExplodeEvent.php b/src/event/entity/EntityExplodeEvent.php
index c1750ccb3..779ab879a 100644
--- a/src/event/entity/EntityExplodeEvent.php
+++ b/src/event/entity/EntityExplodeEvent.php
@@ -51,7 +51,7 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
protected Position $position,
protected array $blocks,
protected float $yield,
- private array $ignitions
+ private array $ignitions = []
){
$this->entity = $entity;
if($yield < 0.0 || $yield > 100.0){
From 258923cc78bc2fc5f9504e450cb3ba43a484d2c3 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sat, 21 Jun 2025 23:05:51 +0100
Subject: [PATCH 063/140] World: verify blockstate IDs in setChunk() I think
I've finally traced the source of these problems back to BuilderTools setting
bad values in async tasks :)
---
src/world/World.php | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/world/World.php b/src/world/World.php
index 5c5e4cfbf..ecec3d3b9 100644
--- a/src/world/World.php
+++ b/src/world/World.php
@@ -2625,6 +2625,16 @@ class World implements ChunkManager{
}
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
+ foreach($chunk->getSubChunks() as $subChunk){
+ foreach($subChunk->getBlockLayers() as $blockLayer){
+ foreach($blockLayer->getPalette() as $blockStateId){
+ if(!$this->blockStateRegistry->hasStateId($blockStateId)){
+ throw new \InvalidArgumentException("Provided chunk contains unknown/unregistered blocks (found unknown state ID $blockStateId)");
+ }
+ }
+ }
+ }
+
$chunkHash = World::chunkHash($chunkX, $chunkZ);
$oldChunk = $this->loadChunk($chunkX, $chunkZ);
if($oldChunk !== null && $oldChunk !== $chunk){
From 2a97b4294d90fcd01c520fb016db6ae11fa0159b Mon Sep 17 00:00:00 2001
From: ipad54 <63200545+ipad54@users.noreply.github.com>
Date: Mon, 23 Jun 2025 18:59:40 +0300
Subject: [PATCH 064/140] Fixed held block placement after respawn anchor
explosion (#6742)
---
src/block/RespawnAnchor.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/block/RespawnAnchor.php b/src/block/RespawnAnchor.php
index f702d240d..e19ea8f6d 100644
--- a/src/block/RespawnAnchor.php
+++ b/src/block/RespawnAnchor.php
@@ -85,7 +85,7 @@ final class RespawnAnchor extends Opaque{
switch($ev->getAction()){
case PlayerRespawnAnchorUseEvent::ACTION_EXPLODE:
$this->explode($player);
- return false;
+ return true;
case PlayerRespawnAnchorUseEvent::ACTION_SET_SPAWN:
if($player->getSpawn() !== null && $player->getSpawn()->equals($this->position)){
From 177fa7643493a0f2fda13daf9c583e9b6d468609 Mon Sep 17 00:00:00 2001
From: ipad54 <63200545+ipad54@users.noreply.github.com>
Date: Mon, 23 Jun 2025 22:57:33 +0300
Subject: [PATCH 065/140] Disable client-side locator bar (#6743)
Without a propper server-side implementation, it just a mess of white dots of nearby players
---
src/network/mcpe/handler/PreSpawnPacketHandler.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php
index ad3cafd39..99f65e78f 100644
--- a/src/network/mcpe/handler/PreSpawnPacketHandler.php
+++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php
@@ -81,7 +81,8 @@ class PreSpawnPacketHandler extends PacketHandler{
$levelSettings->lightningLevel = 0;
$levelSettings->commandsEnabled = true;
$levelSettings->gameRules = [
- "naturalregeneration" => new BoolGameRule(false, false) //Hack for client side regeneration
+ "naturalregeneration" => new BoolGameRule(false, false), //Hack for client side regeneration
+ "locatorbar" => new BoolGameRule(false, false) //Disable client-side tracking of nearby players
];
$levelSettings->experiments = new Experiments([], false);
From cb508f43823db5f5e8c7a1829dddae0f0959bae8 Mon Sep 17 00:00:00 2001
From: ipad54 <63200545+ipad54@users.noreply.github.com>
Date: Mon, 23 Jun 2025 23:30:48 +0300
Subject: [PATCH 066/140] Release 5.30.1 (#6744)
---
changelogs/5.30.md | 9 +++++++++
composer.lock | 24 ++++++++++++------------
src/VersionInfo.php | 2 +-
3 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/changelogs/5.30.md b/changelogs/5.30.md
index 6e9762ea9..3ecfd285e 100644
--- a/changelogs/5.30.md
+++ b/changelogs/5.30.md
@@ -62,3 +62,12 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
- Various internal classes in the `pocketmine\world\generator` namespace have been moved to the `generator\executor` namespace.
- Removed `World->registerGenerator()` and `World->unregisterGenerator()`.
- Removed redundant calls to `curl_close()` (obsolete since PHP 8.0).
+
+# 5.30.1
+Released 23rd June 2025.
+
+## Fixes
+- Fixed accidental break of backwards compatability in `EntityExplodeEvent` introduced in the previous release.
+- Fixed placement of player holding block when exploding respawn anchor.
+- Updated BedrockProtocol to fix incorrect encoding of `ServerScriptDebugDrawerPacket`.
+- Disabled client-side locator bar, allowing plugins to write their own implementations.
diff --git a/composer.lock b/composer.lock
index e8ca2f08d..2967a967f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "39.0.0+bedrock-1.21.90",
+ "version": "39.0.1+bedrock-1.21.90",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "2b088183d12fc003523400867ee398e3893899ed"
+ "reference": "fd231bad0d94024ff50169dc06e8c4fca5aa2eb3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2b088183d12fc003523400867ee398e3893899ed",
- "reference": "2b088183d12fc003523400867ee398e3893899ed",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/fd231bad0d94024ff50169dc06e8c4fca5aa2eb3",
+ "reference": "fd231bad0d94024ff50169dc06e8c4fca5aa2eb3",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/39.0.0+bedrock-1.21.90"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/39.0.1+bedrock-1.21.90"
},
- "time": "2025-06-17T23:46:38+00:00"
+ "time": "2025-06-23T13:22:50+00:00"
},
{
"name": "pocketmine/binaryutils",
@@ -1681,16 +1681,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "10.5.46",
+ "version": "10.5.47",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d"
+ "reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d",
- "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3",
+ "reference": "3637b3e50d32ab3a0d1a33b3b6177169ec3d95a3",
"shasum": ""
},
"require": {
@@ -1762,7 +1762,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.47"
},
"funding": [
{
@@ -1786,7 +1786,7 @@
"type": "tidelift"
}
],
- "time": "2025-05-02T06:46:24+00:00"
+ "time": "2025-06-20T11:29:11+00:00"
},
{
"name": "sebastian/cli-parser",
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index e6b323974..ee9effeb0 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -32,7 +32,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.30.1";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
From e41551843598411e256f60e7f42f66f57d42f243 Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Mon, 23 Jun 2025 20:31:58 +0000
Subject: [PATCH 067/140] 5.30.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15834488047
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index ee9effeb0..cb4ee32ca 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.30.1";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.30.2";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From 40a3ee68dd7ca1ba0121a81abb0441a01f288543 Mon Sep 17 00:00:00 2001
From: ItzxDwi <107537435+ItzxDwi@users.noreply.github.com>
Date: Tue, 24 Jun 2025 20:35:32 +0800
Subject: [PATCH 068/140] fix typo in changelog (#6745)
---
changelogs/5.30.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/changelogs/5.30.md b/changelogs/5.30.md
index 3ecfd285e..cc2ecbc1f 100644
--- a/changelogs/5.30.md
+++ b/changelogs/5.30.md
@@ -67,7 +67,7 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
Released 23rd June 2025.
## Fixes
-- Fixed accidental break of backwards compatability in `EntityExplodeEvent` introduced in the previous release.
+- Fixed accidental break of backwards compatibility in `EntityExplodeEvent` introduced in the previous release.
- Fixed placement of player holding block when exploding respawn anchor.
- Updated BedrockProtocol to fix incorrect encoding of `ServerScriptDebugDrawerPacket`.
- Disabled client-side locator bar, allowing plugins to write their own implementations.
From 3a5432b3162bab3e3119587a913c56d94555cd98 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 25 Jun 2025 00:16:12 +0000
Subject: [PATCH 069/140] Bump build/php from `1549433` to `ce1b095` (#6741)
---
build/php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build/php b/build/php
index 154943379..ce1b095a9 160000
--- a/build/php
+++ b/build/php
@@ -1 +1 @@
-Subproject commit 15494337976e645499e2e3e8c8b491227522be91
+Subproject commit ce1b095a9c6f47dadc7b5812da4e469d52f272bc
From 92c3ce7f02c8eb7412f61fb279373bacd10dc6e4 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Thu, 26 Jun 2025 00:10:46 +0100
Subject: [PATCH 070/140] Create copilot-setup-steps.yml
---
.github/workflows/copilot-setup-steps.yml | 41 +++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 .github/workflows/copilot-setup-steps.yml
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
new file mode 100644
index 000000000..a9dc4606c
--- /dev/null
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -0,0 +1,41 @@
+name: "Copilot Agent environment setup"
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - .github/workflows/copilot-setup-steps.yml
+ pull_request:
+ paths:
+ - .github/workflows/copilot-setup-steps.yml
+
+jobs:
+ # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
+ copilot-setup-steps:
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: pmmp/setup-php-action@3.2.0
+ with:
+ php-version: ${{ inputs.php }}
+ install-path: "./bin"
+ pm-version-major: ${{ inputs.pm-version-major }}
+
+ - name: Restore Composer package cache
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cache/composer/files
+ ~/.cache/composer/vcs
+ key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
+ restore-keys: |
+ composer-v2-cache-
+
+ - name: Install Composer dependencies
+ run: composer install --prefer-dist --no-interaction
From 3176e7549e887748ceb445be4819065c2de1fee9 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Thu, 26 Jun 2025 00:11:26 +0100
Subject: [PATCH 071/140] woops
---
.github/workflows/copilot-setup-steps.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index a9dc4606c..b777f4ea0 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -23,9 +23,9 @@ jobs:
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
with:
- php-version: ${{ inputs.php }}
+ php-version: 8.3
install-path: "./bin"
- pm-version-major: ${{ inputs.pm-version-major }}
+ pm-version-major: 5
- name: Restore Composer package cache
uses: actions/cache@v4
From 6dbd4282cbe23ce389309639c9b4a4181e96ee77 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Thu, 26 Jun 2025 00:12:12 +0100
Subject: [PATCH 072/140] fix cache key
---
.github/workflows/copilot-setup-steps.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index b777f4ea0..702860569 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -33,7 +33,7 @@ jobs:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
- key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
+ key: "composer-v2-cache-8.3-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
From 7ea0f2ff43c2edebc694604f3a82b029d9fa51b5 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Thu, 26 Jun 2025 00:14:34 +0100
Subject: [PATCH 073/140] copilot-setup-steps: also add extension stubs
---
.github/workflows/copilot-setup-steps.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index 702860569..ef0b122e1 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -39,3 +39,9 @@ jobs:
- name: Install Composer dependencies
run: composer install --prefer-dist --no-interaction
+
+ - name: Clone extension stubs
+ uses: actions/checkout@v4
+ with:
+ repository: pmmp/phpstorm-stubs
+ path: extension-stubs
From f1f6e796a424086647ea8ff647bbaa5f60104950 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Jul 2025 10:28:28 +0000
Subject: [PATCH 074/140] Bump the github-actions group with 2 updates (#6749)
---
.github/workflows/discord-release-notify.yml | 2 +-
.github/workflows/draft-release-pr-check.yml | 2 +-
.github/workflows/draft-release.yml | 4 ++--
.github/workflows/main.yml | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/discord-release-notify.yml b/.github/workflows/discord-release-notify.yml
index 93b2978aa..906f227ea 100644
--- a/.github/workflows/discord-release-notify.yml
+++ b/.github/workflows/discord-release-notify.yml
@@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP and tools
- uses: shivammathur/setup-php@2.33.0
+ uses: shivammathur/setup-php@2.34.1
with:
php-version: 8.2
diff --git a/.github/workflows/draft-release-pr-check.yml b/.github/workflows/draft-release-pr-check.yml
index 20b2200e6..b2575f9be 100644
--- a/.github/workflows/draft-release-pr-check.yml
+++ b/.github/workflows/draft-release-pr-check.yml
@@ -49,7 +49,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP
- uses: shivammathur/setup-php@2.33.0
+ uses: shivammathur/setup-php@2.34.1
with:
php-version: 8.2
diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml
index ca48ab8e0..014ea531c 100644
--- a/.github/workflows/draft-release.yml
+++ b/.github/workflows/draft-release.yml
@@ -87,7 +87,7 @@ jobs:
submodules: true
- name: Setup PHP
- uses: shivammathur/setup-php@2.33.0
+ uses: shivammathur/setup-php@2.34.1
with:
php-version: ${{ env.PHP_VERSION }}
@@ -165,7 +165,7 @@ jobs:
${{ github.workspace }}/core-permissions.rst
- name: Create draft release
- uses: ncipollo/release-action@v1.16.0
+ uses: ncipollo/release-action@v1.18.0
id: create-draft
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index cabda54be..4d020c10b 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP and tools
- uses: shivammathur/setup-php@2.33.0
+ uses: shivammathur/setup-php@2.34.1
with:
php-version: 8.3
tools: php-cs-fixer:3.75
From 50e15db9ac280f4646f33fc05283190092c53e28 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Tue, 8 Jul 2025 13:41:59 +0100
Subject: [PATCH 075/140] Prepare 5.31.0 release (#6752)
---
changelogs/5.31.md | 14 +++++++++++++
composer.json | 4 ++--
composer.lock | 26 ++++++++++++-------------
src/VersionInfo.php | 4 ++--
src/data/bedrock/item/ItemTypeNames.php | 1 +
5 files changed, 32 insertions(+), 17 deletions(-)
create mode 100644 changelogs/5.31.md
diff --git a/changelogs/5.31.md b/changelogs/5.31.md
new file mode 100644
index 000000000..60e797425
--- /dev/null
+++ b/changelogs/5.31.md
@@ -0,0 +1,14 @@
+# 5.31.0
+Released 8th July 2025.
+
+This is a support release for Minecraft: Bedrock Edition 1.21.93.
+
+**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.21.93.
+- Removed support for earlier versions.
diff --git a/composer.json b/composer.json
index 051550de6..419f29a4a 100644
--- a/composer.json
+++ b/composer.json
@@ -34,9 +34,9 @@
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
- "pocketmine/bedrock-data": "~5.1.0+bedrock-1.21.90",
+ "pocketmine/bedrock-data": "~5.2.0+bedrock-1.21.93",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
- "pocketmine/bedrock-protocol": "~39.0.0+bedrock-1.21.90",
+ "pocketmine/bedrock-protocol": "~39.1.0+bedrock-1.21.93",
"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 2967a967f..9f550b715 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": "9bf4984c23f688264d3ce6a729a6ec17",
+ "content-hash": "679ab8fc31e55b5170daa34258dc0fd4",
"packages": [
{
"name": "adhocore/json-comment",
@@ -204,16 +204,16 @@
},
{
"name": "pocketmine/bedrock-data",
- "version": "5.1.0+bedrock-1.21.90",
+ "version": "5.2.0+bedrock-1.21.93",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
- "reference": "89ed34957aeccc63e517aa849af593adae958e98"
+ "reference": "740e18e490c6a102b774518ff2224a06762bcaf8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/89ed34957aeccc63e517aa849af593adae958e98",
- "reference": "89ed34957aeccc63e517aa849af593adae958e98",
+ "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/740e18e490c6a102b774518ff2224a06762bcaf8",
+ "reference": "740e18e490c6a102b774518ff2224a06762bcaf8",
"shasum": ""
},
"type": "library",
@@ -224,9 +224,9 @@
"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.21.90"
+ "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.93"
},
- "time": "2025-06-17T23:44:21+00:00"
+ "time": "2025-07-08T12:30:28+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
@@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "39.0.1+bedrock-1.21.90",
+ "version": "39.1.0+bedrock-1.21.93",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "fd231bad0d94024ff50169dc06e8c4fca5aa2eb3"
+ "reference": "e9bc5fb691d18dab229a158462c13f0c6fea79c8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/fd231bad0d94024ff50169dc06e8c4fca5aa2eb3",
- "reference": "fd231bad0d94024ff50169dc06e8c4fca5aa2eb3",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/e9bc5fb691d18dab229a158462c13f0c6fea79c8",
+ "reference": "e9bc5fb691d18dab229a158462c13f0c6fea79c8",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/39.0.1+bedrock-1.21.90"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/39.1.0+bedrock-1.21.93"
},
- "time": "2025-06-23T13:22:50+00:00"
+ "time": "2025-07-08T12:31:39+00:00"
},
{
"name": "pocketmine/binaryutils",
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index cb4ee32ca..499833d34 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.30.2";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const BASE_VERSION = "5.31.0";
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
diff --git a/src/data/bedrock/item/ItemTypeNames.php b/src/data/bedrock/item/ItemTypeNames.php
index d2ab0996b..3178386ca 100644
--- a/src/data/bedrock/item/ItemTypeNames.php
+++ b/src/data/bedrock/item/ItemTypeNames.php
@@ -372,6 +372,7 @@ final class ItemTypeNames{
public const MUSIC_DISC_CREATOR = "minecraft:music_disc_creator";
public const MUSIC_DISC_CREATOR_MUSIC_BOX = "minecraft:music_disc_creator_music_box";
public const MUSIC_DISC_FAR = "minecraft:music_disc_far";
+ public const MUSIC_DISC_LAVA_CHICKEN = "minecraft:music_disc_lava_chicken";
public const MUSIC_DISC_MALL = "minecraft:music_disc_mall";
public const MUSIC_DISC_MELLOHI = "minecraft:music_disc_mellohi";
public const MUSIC_DISC_OTHERSIDE = "minecraft:music_disc_otherside";
From a1d74b57109a7c91ffab73718182f3b1e530fae3 Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Tue, 8 Jul 2025 12:43:11 +0000
Subject: [PATCH 076/140] 5.31.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/16143550499
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 499833d34..aeb4d9ff8 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.31.0";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.31.1";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From 4047cbaafe1685211c8a1eaf87f8780bbb7b1ad9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 23 Jul 2025 12:07:07 +0000
Subject: [PATCH 077/140] Bump phpstan/phpstan-strict-rules in the
development-patch-updates group (#6756)
---
composer.lock | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/composer.lock b/composer.lock
index 9f550b715..5981f64b3 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1312,16 +1312,16 @@
},
{
"name": "phpstan/phpstan-strict-rules",
- "version": "2.0.4",
+ "version": "2.0.5",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
- "reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a"
+ "reference": "1f1358da2f8e1317478c63c21beb9918c9821f6f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
- "reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
+ "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1f1358da2f8e1317478c63c21beb9918c9821f6f",
+ "reference": "1f1358da2f8e1317478c63c21beb9918c9821f6f",
"shasum": ""
},
"require": {
@@ -1354,9 +1354,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
- "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.4"
+ "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.5"
},
- "time": "2025-03-18T11:42:40+00:00"
+ "time": "2025-07-17T12:01:44+00:00"
},
{
"name": "phpunit/php-code-coverage",
From d41f1b288978109c69a58924baae3e0d93c3a534 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Fri, 25 Jul 2025 18:01:02 +0100
Subject: [PATCH 078/140] World: avoid hammering the disk looking for known
ungenerated chunks closes #6679
judging by the debug logs, this actually happens a lot during initial world generation,
which I suppose isn't that surprising.
---
src/world/World.php | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/world/World.php b/src/world/World.php
index ecec3d3b9..8602c5803 100644
--- a/src/world/World.php
+++ b/src/world/World.php
@@ -289,6 +289,12 @@ class World implements ChunkManager{
*/
private array $chunks = [];
+ /**
+ * @var true[]
+ * @phpstan-var array
+ */
+ private array $knownUngeneratedChunks = [];
+
/**
* @var Vector3[][] chunkHash => [relativeBlockHash => Vector3]
* @phpstan-var array>
@@ -625,6 +631,7 @@ class World implements ChunkManager{
self::getXZ($chunkHash, $chunkX, $chunkZ);
$this->unloadChunk($chunkX, $chunkZ, false);
}
+ $this->knownUngeneratedChunks = [];
foreach($this->entitiesByChunk as $chunkHash => $entities){
self::getXZ($chunkHash, $chunkX, $chunkZ);
@@ -2667,6 +2674,7 @@ class World implements ChunkManager{
}
$this->chunks[$chunkHash] = $chunk;
+ unset($this->knownUngeneratedChunks[$chunkHash]);
$this->blockCacheSize -= count($this->blockCache[$chunkHash] ?? []);
unset($this->blockCache[$chunkHash]);
@@ -2931,6 +2939,9 @@ class World implements ChunkManager{
if(isset($this->chunks[$chunkHash = World::chunkHash($x, $z)])){
return $this->chunks[$chunkHash];
}
+ if(isset($this->knownUngeneratedChunks[$chunkHash])){
+ return null;
+ }
$this->timings->syncChunkLoad->startTiming();
@@ -2950,6 +2961,7 @@ class World implements ChunkManager{
if($loadedChunkData === null){
$this->timings->syncChunkLoad->stopTiming();
+ $this->knownUngeneratedChunks[$chunkHash] = true;
return null;
}
From 866df55edf17d845fff362ff351e055e5d9b8fc7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 29 Jul 2025 09:25:19 +0000
Subject: [PATCH 079/140] Bump ramsey/uuid from 4.8.1 to 4.9.0 (#6748)
---
composer.json | 2 +-
composer.lock | 21 ++++++++++-----------
2 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/composer.json b/composer.json
index 419f29a4a..ce4994d4f 100644
--- a/composer.json
+++ b/composer.json
@@ -48,7 +48,7 @@
"pocketmine/raklib": "~1.2.0",
"pocketmine/raklib-ipc": "~1.0.0",
"pocketmine/snooze": "^0.5.0",
- "ramsey/uuid": "~4.8.0",
+ "ramsey/uuid": "~4.9.0",
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
diff --git a/composer.lock b/composer.lock
index 5981f64b3..0180fd0a6 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": "679ab8fc31e55b5170daa34258dc0fd4",
+ "content-hash": "4dc5ea726d881d8c52d1b5299485d940",
"packages": [
{
"name": "adhocore/json-comment",
@@ -818,21 +818,20 @@
},
{
"name": "ramsey/uuid",
- "version": "4.8.1",
+ "version": "4.9.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
+ "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
- "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0",
+ "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0",
"shasum": ""
},
"require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
- "ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
},
@@ -891,9 +890,9 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.8.1"
+ "source": "https://github.com/ramsey/uuid/tree/4.9.0"
},
- "time": "2025-06-01T06:28:46+00:00"
+ "time": "2025-06-25T14:20:11+00:00"
},
{
"name": "symfony/filesystem",
@@ -2757,7 +2756,7 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": {},
+ "stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@@ -2788,9 +2787,9 @@
"ext-zlib": ">=1.2.11",
"composer-runtime-api": "^2.0"
},
- "platform-dev": {},
+ "platform-dev": [],
"platform-overrides": {
"php": "8.1.0"
},
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.3.0"
}
From 40ea6dd30d9f5c874be39c2f8a6f5d19755268c3 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 29 Jul 2025 09:26:25 +0000
Subject: [PATCH 080/140] Bump phpstan/phpstan-strict-rules in the
development-patch-updates group (#6758)
---
composer.lock | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/composer.lock b/composer.lock
index 0180fd0a6..2e5e83a94 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1311,16 +1311,16 @@
},
{
"name": "phpstan/phpstan-strict-rules",
- "version": "2.0.5",
+ "version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
- "reference": "1f1358da2f8e1317478c63c21beb9918c9821f6f"
+ "reference": "f9f77efa9de31992a832ff77ea52eb42d675b094"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1f1358da2f8e1317478c63c21beb9918c9821f6f",
- "reference": "1f1358da2f8e1317478c63c21beb9918c9821f6f",
+ "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/f9f77efa9de31992a832ff77ea52eb42d675b094",
+ "reference": "f9f77efa9de31992a832ff77ea52eb42d675b094",
"shasum": ""
},
"require": {
@@ -1353,9 +1353,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
- "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.5"
+ "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.6"
},
- "time": "2025-07-17T12:01:44+00:00"
+ "time": "2025-07-21T12:19:29+00:00"
},
{
"name": "phpunit/php-code-coverage",
From a83c62a4a2e5eea17fdfc3eb2bfd55f31534a9e3 Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Wed, 30 Jul 2025 19:08:29 +0100
Subject: [PATCH 081/140] readme: Stop showing random PR statuses on CI badge
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 6f2b715ab..98f569346 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
-
+
From cc17e68072c1bcadefcab3c7ddb42cdb27be0dad Mon Sep 17 00:00:00 2001
From: Hugo_ <55756021+Dhaiven@users.noreply.github.com>
Date: Thu, 31 Jul 2025 08:48:47 +0200
Subject: [PATCH 082/140] Add blocks interfaces for commons properties (#6639)
---
src/block/ActivatorRail.php | 3 +-
src/block/AmethystCluster.php | 3 +-
src/block/Anvil.php | 3 +-
src/block/Barrel.php | 3 +-
src/block/BaseBanner.php | 3 +-
src/block/BaseBigDripleaf.php | 3 +-
src/block/BaseCoral.php | 3 +-
src/block/BaseSign.php | 3 +-
src/block/Bed.php | 4 +-
src/block/Bell.php | 3 +-
src/block/BoneBlock.php | 3 +-
src/block/Button.php | 3 +-
src/block/Cactus.php | 3 +-
src/block/CakeWithCandle.php | 3 +-
src/block/CakeWithDyedCandle.php | 3 +-
src/block/Campfire.php | 4 +-
src/block/Candle.php | 3 +-
src/block/Carpet.php | 3 +-
src/block/CarvedPumpkin.php | 3 +-
src/block/CaveVines.php | 3 +-
src/block/Chain.php | 3 +-
src/block/ChemistryTable.php | 3 +-
src/block/Chest.php | 3 +-
src/block/ChiseledBookshelf.php | 3 +-
src/block/ChorusFlower.php | 3 +-
src/block/CocoaBlock.php | 4 +-
src/block/Concrete.php | 3 +-
src/block/ConcretePowder.php | 3 +-
src/block/CopperBulb.php | 4 +-
src/block/CoralBlock.php | 3 +-
src/block/Crops.php | 3 +-
src/block/DaylightSensor.php | 3 +-
src/block/Door.php | 3 +-
src/block/DoublePitcherCrop.php | 3 +-
src/block/DyedCandle.php | 3 +-
src/block/DyedShulkerBox.php | 3 +-
src/block/EndPortalFrame.php | 3 +-
src/block/EndRod.php | 3 +-
src/block/EnderChest.php | 3 +-
src/block/FenceGate.php | 4 +-
src/block/Fire.php | 3 +-
src/block/FloorBanner.php | 3 +-
src/block/FloorSign.php | 3 +-
src/block/FrostedIce.php | 3 +-
src/block/Furnace.php | 3 +-
src/block/GlazedTerracotta.php | 4 +-
src/block/GlowLichen.php | 3 +-
src/block/HayBale.php | 3 +-
src/block/Hopper.php | 3 +-
src/block/ItemFrame.php | 3 +-
src/block/Ladder.php | 3 +-
src/block/Lectern.php | 3 +-
src/block/LightningRod.php | 3 +-
src/block/Loom.php | 3 +-
src/block/NetherVines.php | 3 +-
src/block/NetherWartPlant.php | 3 +-
src/block/PinkPetals.php | 3 +-
src/block/PitcherCrop.php | 3 +-
src/block/Planks.php | 3 +-
src/block/PoweredRail.php | 3 +-
src/block/RedstoneComparator.php | 5 +-
src/block/RedstoneLamp.php | 3 +-
src/block/RedstoneOre.php | 3 +-
src/block/RedstoneRepeater.php | 4 +-
src/block/RedstoneTorch.php | 3 +-
src/block/RedstoneWire.php | 3 +-
src/block/ResinClump.php | 3 +-
src/block/ShulkerBox.php | 3 +-
src/block/SimplePillar.php | 3 +-
src/block/SmallDripleaf.php | 3 +-
src/block/StainedGlass.php | 3 +-
src/block/StainedGlassPane.php | 3 +-
src/block/StainedHardenedClay.php | 3 +-
src/block/StainedHardenedGlass.php | 3 +-
src/block/StainedHardenedGlassPane.php | 3 +-
src/block/Stair.php | 3 +-
src/block/Stonecutter.php | 3 +-
src/block/Sugarcane.php | 3 +-
src/block/SweetBerryBush.php | 3 +-
src/block/Trapdoor.php | 3 +-
src/block/TripwireHook.php | 3 +-
src/block/WallBanner.php | 3 +-
src/block/WallCoralFan.php | 3 +-
src/block/WallSign.php | 3 +-
src/block/WeightedPressurePlate.php | 3 +-
src/block/Wood.php | 4 +-
src/block/WoodenButton.php | 3 +-
src/block/WoodenDoor.php | 3 +-
src/block/WoodenFence.php | 3 +-
src/block/WoodenPressurePlate.php | 3 +-
src/block/WoodenSlab.php | 3 +-
src/block/WoodenStairs.php | 3 +-
src/block/WoodenTrapdoor.php | 3 +-
src/block/Wool.php | 3 +-
src/block/utils/Ageable.php | 34 ++++++++++++
.../utils/AnalogRedstoneSignalEmitter.php | 34 ++++++++++++
src/block/utils/AnyFacing.php | 41 ++++++++++++++
src/block/utils/Colored.php | 34 ++++++++++++
src/block/utils/CoralMaterial.php | 41 ++++++++++++++
src/block/utils/HorizontalFacing.php | 41 ++++++++++++++
src/block/utils/Lightable.php | 34 ++++++++++++
src/block/utils/MultiFacing.php | 54 +++++++++++++++++++
src/block/utils/PillarRotation.php | 39 ++++++++++++++
src/block/utils/PoweredByRedstone.php | 34 ++++++++++++
src/block/utils/SignLikeRotation.php | 39 ++++++++++++++
src/block/utils/WoodMaterial.php | 29 ++++++++++
106 files changed, 652 insertions(+), 94 deletions(-)
create mode 100644 src/block/utils/Ageable.php
create mode 100644 src/block/utils/AnalogRedstoneSignalEmitter.php
create mode 100644 src/block/utils/AnyFacing.php
create mode 100644 src/block/utils/Colored.php
create mode 100644 src/block/utils/CoralMaterial.php
create mode 100644 src/block/utils/HorizontalFacing.php
create mode 100644 src/block/utils/Lightable.php
create mode 100644 src/block/utils/MultiFacing.php
create mode 100644 src/block/utils/PillarRotation.php
create mode 100644 src/block/utils/PoweredByRedstone.php
create mode 100644 src/block/utils/SignLikeRotation.php
create mode 100644 src/block/utils/WoodMaterial.php
diff --git a/src/block/ActivatorRail.php b/src/block/ActivatorRail.php
index dcd0ef93b..da15eb1e8 100644
--- a/src/block/ActivatorRail.php
+++ b/src/block/ActivatorRail.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\RailPoweredByRedstoneTrait;
-class ActivatorRail extends StraightOnlyRail{
+class ActivatorRail extends StraightOnlyRail implements PoweredByRedstone{
use RailPoweredByRedstoneTrait;
//TODO
diff --git a/src/block/AmethystCluster.php b/src/block/AmethystCluster.php
index 639490456..8a750e974 100644
--- a/src/block/AmethystCluster.php
+++ b/src/block/AmethystCluster.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AmethystTrait;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\FortuneDropHelper;
use pocketmine\block\utils\SupportType;
@@ -38,7 +39,7 @@ use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
-final class AmethystCluster extends Transparent{
+final class AmethystCluster extends Transparent implements AnyFacing{
use AmethystTrait;
use AnyFacingTrait;
diff --git a/src/block/Anvil.php b/src/block/Anvil.php
index 2c48f9a7c..fcb4d045c 100644
--- a/src/block/Anvil.php
+++ b/src/block/Anvil.php
@@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\inventory\AnvilInventory;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -41,7 +42,7 @@ use pocketmine\world\sound\AnvilFallSound;
use pocketmine\world\sound\Sound;
use function round;
-class Anvil extends Transparent implements Fallable{
+class Anvil extends Transparent implements Fallable, HorizontalFacing{
use FallableTrait;
use HorizontalFacingTrait;
diff --git a/src/block/Barrel.php b/src/block/Barrel.php
index 0f0499ab9..7b2ea356e 100644
--- a/src/block/Barrel.php
+++ b/src/block/Barrel.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Barrel as TileBarrel;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -33,7 +34,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function abs;
-class Barrel extends Opaque{
+class Barrel extends Opaque implements AnyFacing{
use AnyFacingTrait;
protected bool $open = false;
diff --git a/src/block/BaseBanner.php b/src/block/BaseBanner.php
index b56323453..376f1f9dc 100644
--- a/src/block/BaseBanner.php
+++ b/src/block/BaseBanner.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Banner as TileBanner;
use pocketmine\block\utils\BannerPatternLayer;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Banner as ItemBanner;
@@ -36,7 +37,7 @@ use pocketmine\world\BlockTransaction;
use function assert;
use function count;
-abstract class BaseBanner extends Transparent{
+abstract class BaseBanner extends Transparent implements Colored{
use ColoredTrait;
/**
diff --git a/src/block/BaseBigDripleaf.php b/src/block/BaseBigDripleaf.php
index f0ff59cf0..94e2c12a2 100644
--- a/src/block/BaseBigDripleaf.php
+++ b/src/block/BaseBigDripleaf.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\StructureGrowEvent;
@@ -33,7 +34,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-abstract class BaseBigDripleaf extends Transparent{
+abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
abstract protected function isHead() : bool;
diff --git a/src/block/BaseCoral.php b/src/block/BaseCoral.php
index b9c595a97..c1cc9bb25 100644
--- a/src/block/BaseCoral.php
+++ b/src/block/BaseCoral.php
@@ -24,12 +24,13 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
+use pocketmine\block\utils\CoralMaterial;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use function mt_rand;
-abstract class BaseCoral extends Transparent{
+abstract class BaseCoral extends Transparent implements CoralMaterial{
use CoralTypeTrait;
public function onNearbyBlockChange() : void{
diff --git a/src/block/BaseSign.php b/src/block/BaseSign.php
index 0f5d77d58..0efaa603c 100644
--- a/src/block/BaseSign.php
+++ b/src/block/BaseSign.php
@@ -27,6 +27,7 @@ use pocketmine\block\tile\Sign as TileSign;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SignText;
use pocketmine\block\utils\SupportType;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodType;
use pocketmine\block\utils\WoodTypeTrait;
use pocketmine\color\Color;
@@ -44,7 +45,7 @@ use function array_map;
use function assert;
use function strlen;
-abstract class BaseSign extends Transparent{
+abstract class BaseSign extends Transparent implements WoodMaterial{
use WoodTypeTrait;
protected SignText $text;
diff --git a/src/block/Bed.php b/src/block/Bed.php
index 133c4a9cc..21bd3a172 100644
--- a/src/block/Bed.php
+++ b/src/block/Bed.php
@@ -24,8 +24,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Bed as TileBed;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -41,7 +43,7 @@ use pocketmine\utils\TextFormat;
use pocketmine\world\BlockTransaction;
use pocketmine\world\World;
-class Bed extends Transparent{
+class Bed extends Transparent implements Colored, HorizontalFacing{
use ColoredTrait;
use HorizontalFacingTrait;
diff --git a/src/block/Bell.php b/src/block/Bell.php
index 53a6fc7fb..258abc628 100644
--- a/src/block/Bell.php
+++ b/src/block/Bell.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Bell as TileBell;
use pocketmine\block\utils\BellAttachmentType;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -38,7 +39,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound;
-final class Bell extends Transparent{
+final class Bell extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
private BellAttachmentType $attachmentType = BellAttachmentType::FLOOR;
diff --git a/src/block/BoneBlock.php b/src/block/BoneBlock.php
index 247bdb748..465d96033 100644
--- a/src/block/BoneBlock.php
+++ b/src/block/BoneBlock.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\PillarRotationTrait;
-class BoneBlock extends Opaque{
+class BoneBlock extends Opaque implements PillarRotation{
use PillarRotationTrait;
}
diff --git a/src/block/Button.php b/src/block/Button.php
index 73bd1d556..4d1f1bbc5 100644
--- a/src/block/Button.php
+++ b/src/block/Button.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -33,7 +34,7 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\RedstonePowerOffSound;
use pocketmine\world\sound\RedstonePowerOnSound;
-abstract class Button extends Flowable{
+abstract class Button extends Flowable implements AnyFacing{
use AnyFacingTrait;
protected bool $pressed = false;
diff --git a/src/block/Cactus.php b/src/block/Cactus.php
index 67b15b946..51c98786b 100644
--- a/src/block/Cactus.php
+++ b/src/block/Cactus.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\StaticSupportTrait;
@@ -33,7 +34,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
-class Cactus extends Transparent{
+class Cactus extends Transparent implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/CakeWithCandle.php b/src/block/CakeWithCandle.php
index 546843d6c..1462776c2 100644
--- a/src/block/CakeWithCandle.php
+++ b/src/block/CakeWithCandle.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CandleTrait;
+use pocketmine\block\utils\Lightable;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@@ -31,7 +32,7 @@ use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
-class CakeWithCandle extends BaseCake{
+class CakeWithCandle extends BaseCake implements Lightable{
use CandleTrait {
onInteract as onInteractCandle;
}
diff --git a/src/block/CakeWithDyedCandle.php b/src/block/CakeWithDyedCandle.php
index 0dff358e1..04ab0c6eb 100644
--- a/src/block/CakeWithDyedCandle.php
+++ b/src/block/CakeWithDyedCandle.php
@@ -23,10 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
-class CakeWithDyedCandle extends CakeWithCandle{
+class CakeWithDyedCandle extends CakeWithCandle implements Colored{
use ColoredTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
diff --git a/src/block/Campfire.php b/src/block/Campfire.php
index 9f4c42a9c..edfc87ecb 100644
--- a/src/block/Campfire.php
+++ b/src/block/Campfire.php
@@ -25,7 +25,9 @@ namespace pocketmine\block;
use pocketmine\block\inventory\CampfireInventory;
use pocketmine\block\tile\Campfire as TileCampfire;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\crafting\FurnaceRecipe;
@@ -59,7 +61,7 @@ use function count;
use function min;
use function mt_rand;
-class Campfire extends Transparent{
+class Campfire extends Transparent implements Lightable, HorizontalFacing{
use HorizontalFacingTrait{
HorizontalFacingTrait::describeBlockOnlyState as encodeFacingState;
}
diff --git a/src/block/Candle.php b/src/block/Candle.php
index 7f22641e1..977f13a09 100644
--- a/src/block/Candle.php
+++ b/src/block/Candle.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CandleTrait;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -35,7 +36,7 @@ use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
-class Candle extends Transparent{
+class Candle extends Transparent implements Lightable{
use CandleTrait {
describeBlockOnlyState as encodeLitState;
getLightLevel as getBaseLightLevel;
diff --git a/src/block/Carpet.php b/src/block/Carpet.php
index 2d8e7ea47..fd8b42a09 100644
--- a/src/block/Carpet.php
+++ b/src/block/Carpet.php
@@ -23,12 +23,13 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
-class Carpet extends Flowable{
+class Carpet extends Flowable implements Colored{
use ColoredTrait;
use StaticSupportTrait;
diff --git a/src/block/CarvedPumpkin.php b/src/block/CarvedPumpkin.php
index 98f3c2307..cfdb8d49d 100644
--- a/src/block/CarvedPumpkin.php
+++ b/src/block/CarvedPumpkin.php
@@ -24,7 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
-class CarvedPumpkin extends Opaque{
+class CarvedPumpkin extends Opaque implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
}
diff --git a/src/block/CaveVines.php b/src/block/CaveVines.php
index daa973507..84d7d3169 100644
--- a/src/block/CaveVines.php
+++ b/src/block/CaveVines.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\StaticSupportTrait;
@@ -39,7 +40,7 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\GlowBerriesPickSound;
use function mt_rand;
-class CaveVines extends Flowable{
+class CaveVines extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/Chain.php b/src/block/Chain.php
index e9cc2c9be..5ec3b1e2a 100644
--- a/src/block/Chain.php
+++ b/src/block/Chain.php
@@ -23,13 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\PillarRotationTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
-final class Chain extends Transparent{
+final class Chain extends Transparent implements PillarRotation{
use PillarRotationTrait;
public function getSupportType(int $facing) : SupportType{
diff --git a/src/block/ChemistryTable.php b/src/block/ChemistryTable.php
index 058e40288..9b5e78f92 100644
--- a/src/block/ChemistryTable.php
+++ b/src/block/ChemistryTable.php
@@ -24,11 +24,12 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
-final class ChemistryTable extends Opaque{
+final class ChemistryTable extends Opaque implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
diff --git a/src/block/Chest.php b/src/block/Chest.php
index 7d2650007..c0dc09d9e 100644
--- a/src/block/Chest.php
+++ b/src/block/Chest.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Chest as TileChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\ChestPairEvent;
use pocketmine\item\Item;
@@ -33,7 +34,7 @@ use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
-class Chest extends Transparent{
+class Chest extends Transparent implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
protected function recalculateCollisionBoxes() : array{
diff --git a/src/block/ChiseledBookshelf.php b/src/block/ChiseledBookshelf.php
index 73c4861bf..be49c7a91 100644
--- a/src/block/ChiseledBookshelf.php
+++ b/src/block/ChiseledBookshelf.php
@@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\ChiseledBookshelf as TileChiseledBookshelf;
use pocketmine\block\utils\ChiseledBookshelfSlot;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Book;
@@ -38,7 +39,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function spl_object_id;
-class ChiseledBookshelf extends Opaque{
+class ChiseledBookshelf extends Opaque implements HorizontalFacing{
use HorizontalFacingTrait;
use FacesOppositePlacingPlayerTrait;
diff --git a/src/block/ChorusFlower.php b/src/block/ChorusFlower.php
index cc3c606d9..ef48d5a89 100644
--- a/src/block/ChorusFlower.php
+++ b/src/block/ChorusFlower.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\entity\projectile\Projectile;
@@ -40,7 +41,7 @@ use function array_rand;
use function min;
use function mt_rand;
-final class ChorusFlower extends Flowable{
+final class ChorusFlower extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/CocoaBlock.php b/src/block/CocoaBlock.php
index 83e1de34b..ae09ccb0a 100644
--- a/src/block/CocoaBlock.php
+++ b/src/block/CocoaBlock.php
@@ -23,8 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\WoodType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -39,7 +41,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function mt_rand;
-class CocoaBlock extends Flowable{
+class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
use HorizontalFacingTrait;
use AgeableTrait;
diff --git a/src/block/Concrete.php b/src/block/Concrete.php
index fae6f8e2f..6cad11193 100644
--- a/src/block/Concrete.php
+++ b/src/block/Concrete.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-class Concrete extends Opaque{
+class Concrete extends Opaque implements Colored{
use ColoredTrait;
}
diff --git a/src/block/ConcretePowder.php b/src/block/ConcretePowder.php
index 59f14bc72..89b53053b 100644
--- a/src/block/ConcretePowder.php
+++ b/src/block/ConcretePowder.php
@@ -24,12 +24,13 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\math\Facing;
-class ConcretePowder extends Opaque implements Fallable{
+class ConcretePowder extends Opaque implements Fallable, Colored{
use ColoredTrait;
use FallableTrait {
onNearbyBlockChange as protected startFalling;
diff --git a/src/block/CopperBulb.php b/src/block/CopperBulb.php
index 97fc209fe..d0bdedf3c 100644
--- a/src/block/CopperBulb.php
+++ b/src/block/CopperBulb.php
@@ -26,11 +26,13 @@ namespace pocketmine\block;
use pocketmine\block\utils\CopperMaterial;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\CopperTrait;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
-class CopperBulb extends Opaque implements CopperMaterial{
+class CopperBulb extends Opaque implements CopperMaterial, Lightable, PoweredByRedstone{
use CopperTrait;
use PoweredByRedstoneTrait;
use LightableTrait{
diff --git a/src/block/CoralBlock.php b/src/block/CoralBlock.php
index 3e7ca8224..c21209998 100644
--- a/src/block/CoralBlock.php
+++ b/src/block/CoralBlock.php
@@ -24,11 +24,12 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
+use pocketmine\block\utils\CoralMaterial;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\item\Item;
use function mt_rand;
-final class CoralBlock extends Opaque{
+final class CoralBlock extends Opaque implements CoralMaterial{
use CoralTypeTrait;
public function onNearbyBlockChange() : void{
diff --git a/src/block/Crops.php b/src/block/Crops.php
index e90ac6236..b0488d150 100644
--- a/src/block/Crops.php
+++ b/src/block/Crops.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\CropGrowthHelper;
@@ -34,7 +35,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function mt_rand;
-abstract class Crops extends Flowable{
+abstract class Crops extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/DaylightSensor.php b/src/block/DaylightSensor.php
index 5720af529..ed56d2f44 100644
--- a/src/block/DaylightSensor.php
+++ b/src/block/DaylightSensor.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\AnalogRedstoneSignalEmitter;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -36,7 +37,7 @@ use function max;
use function round;
use const M_PI;
-class DaylightSensor extends Transparent{
+class DaylightSensor extends Transparent implements AnalogRedstoneSignalEmitter{
use AnalogRedstoneSignalEmitterTrait;
protected bool $inverted = false;
diff --git a/src/block/Door.php b/src/block/Door.php
index fa88267e1..2ff53645c 100644
--- a/src/block/Door.php
+++ b/src/block/Door.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -34,7 +35,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\DoorSound;
-class Door extends Transparent{
+class Door extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
protected bool $top = false;
diff --git a/src/block/DoublePitcherCrop.php b/src/block/DoublePitcherCrop.php
index 1233ed05d..89d9e98b5 100644
--- a/src/block/DoublePitcherCrop.php
+++ b/src/block/DoublePitcherCrop.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\CropGrowthHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -37,7 +38,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class DoublePitcherCrop extends DoublePlant{
+final class DoublePitcherCrop extends DoublePlant implements Ageable{
use AgeableTrait {
describeBlockOnlyState as describeAge;
}
diff --git a/src/block/DyedCandle.php b/src/block/DyedCandle.php
index a495e8d00..57a8b5923 100644
--- a/src/block/DyedCandle.php
+++ b/src/block/DyedCandle.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-class DyedCandle extends Candle{
+class DyedCandle extends Candle implements Colored{
use ColoredTrait;
protected function getCandleIfCompatibleType(Block $block) : ?Candle{
diff --git a/src/block/DyedShulkerBox.php b/src/block/DyedShulkerBox.php
index 5eae9237e..8be2718a2 100644
--- a/src/block/DyedShulkerBox.php
+++ b/src/block/DyedShulkerBox.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-final class DyedShulkerBox extends ShulkerBox{
+final class DyedShulkerBox extends ShulkerBox implements Colored{
use ColoredTrait;
}
diff --git a/src/block/EndPortalFrame.php b/src/block/EndPortalFrame.php
index ed5b77433..6c4865fdd 100644
--- a/src/block/EndPortalFrame.php
+++ b/src/block/EndPortalFrame.php
@@ -24,11 +24,12 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
-class EndPortalFrame extends Opaque{
+class EndPortalFrame extends Opaque implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
protected bool $eye = false;
diff --git a/src/block/EndRod.php b/src/block/EndRod.php
index a6770f370..e3d439f6a 100644
--- a/src/block/EndRod.php
+++ b/src/block/EndRod.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
@@ -32,7 +33,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class EndRod extends Flowable{
+class EndRod extends Flowable implements AnyFacing{
use AnyFacingTrait;
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
diff --git a/src/block/EnderChest.php b/src/block/EnderChest.php
index 6a8cf108c..5dec4f3af 100644
--- a/src/block/EnderChest.php
+++ b/src/block/EnderChest.php
@@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\inventory\EnderChestInventory;
use pocketmine\block\tile\EnderChest as TileEnderChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@@ -33,7 +34,7 @@ use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
-class EnderChest extends Transparent{
+class EnderChest extends Transparent implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
public function getLightLevel() : int{
diff --git a/src/block/FenceGate.php b/src/block/FenceGate.php
index 2bbfdf892..d8cdfe4e2 100644
--- a/src/block/FenceGate.php
+++ b/src/block/FenceGate.php
@@ -23,8 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -35,7 +37,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\DoorSound;
-class FenceGate extends Transparent{
+class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
use WoodTypeTrait;
use HorizontalFacingTrait;
diff --git a/src/block/Fire.php b/src/block/Fire.php
index 35a7a696c..62809fb9d 100644
--- a/src/block/Fire.php
+++ b/src/block/Fire.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\SupportType;
@@ -35,7 +36,7 @@ use function max;
use function min;
use function mt_rand;
-class Fire extends BaseFire{
+class Fire extends BaseFire implements Ageable{
use AgeableTrait;
public const MAX_AGE = 15;
diff --git a/src/block/FloorBanner.php b/src/block/FloorBanner.php
index 73bc45787..ba089b6c0 100644
--- a/src/block/FloorBanner.php
+++ b/src/block/FloorBanner.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
@@ -30,7 +31,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class FloorBanner extends BaseBanner{
+final class FloorBanner extends BaseBanner implements SignLikeRotation{
use SignLikeRotationTrait;
protected function getSupportingFace() : int{
diff --git a/src/block/FloorSign.php b/src/block/FloorSign.php
index 5615d15d8..94e51ffe8 100644
--- a/src/block/FloorSign.php
+++ b/src/block/FloorSign.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
@@ -30,7 +31,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class FloorSign extends BaseSign{
+final class FloorSign extends BaseSign implements SignLikeRotation{
use SignLikeRotationTrait;
protected function getSupportingFace() : int{
diff --git a/src/block/FrostedIce.php b/src/block/FrostedIce.php
index 3e8592306..046d75811 100644
--- a/src/block/FrostedIce.php
+++ b/src/block/FrostedIce.php
@@ -23,11 +23,12 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use function mt_rand;
-class FrostedIce extends Ice{
+class FrostedIce extends Ice implements Ageable{
use AgeableTrait;
public const MAX_AGE = 3;
diff --git a/src/block/Furnace.php b/src/block/Furnace.php
index 7a64e3cd3..54480e62c 100644
--- a/src/block/Furnace.php
+++ b/src/block/Furnace.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Furnace as TileFurnace;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\crafting\FurnaceType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -33,7 +34,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function mt_rand;
-class Furnace extends Opaque{
+class Furnace extends Opaque implements Lightable{
use FacesOppositePlacingPlayerTrait;
use LightableTrait;
diff --git a/src/block/GlazedTerracotta.php b/src/block/GlazedTerracotta.php
index 15b3254e5..ccb928875 100644
--- a/src/block/GlazedTerracotta.php
+++ b/src/block/GlazedTerracotta.php
@@ -23,10 +23,12 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
-class GlazedTerracotta extends Opaque{
+class GlazedTerracotta extends Opaque implements Colored, HorizontalFacing{
use ColoredTrait;
use FacesOppositePlacingPlayerTrait;
}
diff --git a/src/block/GlowLichen.php b/src/block/GlowLichen.php
index a44c4d035..6ad8d3748 100644
--- a/src/block/GlowLichen.php
+++ b/src/block/GlowLichen.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\MultiAnySupportTrait;
+use pocketmine\block\utils\MultiFacing;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
@@ -35,7 +36,7 @@ use pocketmine\world\World;
use function count;
use function shuffle;
-class GlowLichen extends Transparent{
+class GlowLichen extends Transparent implements MultiFacing{
use MultiAnySupportTrait;
public function getLightLevel() : int{
diff --git a/src/block/HayBale.php b/src/block/HayBale.php
index 6fdd2cb63..dacfe92fa 100644
--- a/src/block/HayBale.php
+++ b/src/block/HayBale.php
@@ -23,10 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\PillarRotationTrait;
use pocketmine\entity\Entity;
-class HayBale extends Opaque{
+class HayBale extends Opaque implements PillarRotation{
use PillarRotationTrait;
public function getFlameEncouragement() : int{
diff --git a/src/block/Hopper.php b/src/block/Hopper.php
index 0d823674b..4956b668f 100644
--- a/src/block/Hopper.php
+++ b/src/block/Hopper.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Hopper as TileHopper;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -34,7 +35,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class Hopper extends Transparent{
+class Hopper extends Transparent implements PoweredByRedstone{
use PoweredByRedstoneTrait;
private int $facing = Facing::DOWN;
diff --git a/src/block/ItemFrame.php b/src/block/ItemFrame.php
index c03806a3b..0fda77758 100644
--- a/src/block/ItemFrame.php
+++ b/src/block/ItemFrame.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\ItemFrame as TileItemFrame;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -39,7 +40,7 @@ use pocketmine\world\sound\ItemFrameRotateItemSound;
use function is_infinite;
use function is_nan;
-class ItemFrame extends Flowable{
+class ItemFrame extends Flowable implements AnyFacing{
use AnyFacingTrait;
public const ROTATIONS = 8;
diff --git a/src/block/Ladder.php b/src/block/Ladder.php
index 09c0b8f6b..6edaebbf2 100644
--- a/src/block/Ladder.php
+++ b/src/block/Ladder.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\Entity;
@@ -35,7 +36,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class Ladder extends Transparent{
+class Ladder extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
public function hasEntityCollision() : bool{
diff --git a/src/block/Lectern.php b/src/block/Lectern.php
index 03880b3c5..9ba01c1c5 100644
--- a/src/block/Lectern.php
+++ b/src/block/Lectern.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Lectern as TileLectern;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -36,7 +37,7 @@ use pocketmine\player\Player;
use pocketmine\world\sound\LecternPlaceBookSound;
use function count;
-class Lectern extends Transparent{
+class Lectern extends Transparent implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
protected int $viewedPage = 0;
diff --git a/src/block/LightningRod.php b/src/block/LightningRod.php
index a0dd50542..9c1971229 100644
--- a/src/block/LightningRod.php
+++ b/src/block/LightningRod.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
@@ -32,7 +33,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class LightningRod extends Transparent{
+final class LightningRod extends Transparent implements AnyFacing{
use AnyFacingTrait;
protected function recalculateCollisionBoxes() : array{
diff --git a/src/block/Loom.php b/src/block/Loom.php
index d3dd4f3c7..a2b9fc235 100644
--- a/src/block/Loom.php
+++ b/src/block/Loom.php
@@ -25,11 +25,12 @@ namespace pocketmine\block;
use pocketmine\block\inventory\LoomInventory;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
-final class Loom extends Opaque{
+final class Loom extends Opaque implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
diff --git a/src/block/NetherVines.php b/src/block/NetherVines.php
index e8729c00f..67a0b6f94 100644
--- a/src/block/NetherVines.php
+++ b/src/block/NetherVines.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\FortuneDropHelper;
use pocketmine\block\utils\StaticSupportTrait;
@@ -41,7 +42,7 @@ use function mt_rand;
/**
* This class is used for Weeping & Twisting vines, because they have same behaviour
*/
-class NetherVines extends Flowable{
+class NetherVines extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/NetherWartPlant.php b/src/block/NetherWartPlant.php
index 34e6fd57e..df0609754 100644
--- a/src/block/NetherWartPlant.php
+++ b/src/block/NetherWartPlant.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\FortuneDropHelper;
@@ -31,7 +32,7 @@ use pocketmine\item\Item;
use pocketmine\math\Facing;
use function mt_rand;
-class NetherWartPlant extends Flowable{
+class NetherWartPlant extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/PinkPetals.php b/src/block/PinkPetals.php
index 17bc4c50a..b8b6e248c 100644
--- a/src/block/PinkPetals.php
+++ b/src/block/PinkPetals.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -34,7 +35,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class PinkPetals extends Flowable{
+class PinkPetals extends Flowable implements HorizontalFacing{
use HorizontalFacingTrait;
use StaticSupportTrait {
canBePlacedAt as supportedWhenPlacedAt;
diff --git a/src/block/PitcherCrop.php b/src/block/PitcherCrop.php
index d41aed284..1c771bb8a 100644
--- a/src/block/PitcherCrop.php
+++ b/src/block/PitcherCrop.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\CropGrowthHelper;
@@ -38,7 +39,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class PitcherCrop extends Flowable{
+final class PitcherCrop extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/Planks.php b/src/block/Planks.php
index 1074f8adf..ad7956361 100644
--- a/src/block/Planks.php
+++ b/src/block/Planks.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class Planks extends Opaque{
+class Planks extends Opaque implements WoodMaterial{
use WoodTypeTrait;
public function getFuelTime() : int{
diff --git a/src/block/PoweredRail.php b/src/block/PoweredRail.php
index 25d6dc9e3..321b19a46 100644
--- a/src/block/PoweredRail.php
+++ b/src/block/PoweredRail.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\RailPoweredByRedstoneTrait;
-class PoweredRail extends StraightOnlyRail{
+class PoweredRail extends StraightOnlyRail implements PoweredByRedstone{
use RailPoweredByRedstoneTrait;
}
diff --git a/src/block/RedstoneComparator.php b/src/block/RedstoneComparator.php
index 40e1ef510..88050b85a 100644
--- a/src/block/RedstoneComparator.php
+++ b/src/block/RedstoneComparator.php
@@ -24,8 +24,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Comparator;
+use pocketmine\block\utils\AnalogRedstoneSignalEmitter;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\block\utils\SupportType;
@@ -38,7 +41,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function assert;
-class RedstoneComparator extends Flowable{
+class RedstoneComparator extends Flowable implements AnalogRedstoneSignalEmitter, PoweredByRedstone, HorizontalFacing{
use HorizontalFacingTrait;
use AnalogRedstoneSignalEmitterTrait;
use PoweredByRedstoneTrait;
diff --git a/src/block/RedstoneLamp.php b/src/block/RedstoneLamp.php
index 58098c395..33a97801d 100644
--- a/src/block/RedstoneLamp.php
+++ b/src/block/RedstoneLamp.php
@@ -23,10 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
-class RedstoneLamp extends Opaque{
+class RedstoneLamp extends Opaque implements PoweredByRedstone{
use PoweredByRedstoneTrait;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
diff --git a/src/block/RedstoneOre.php b/src/block/RedstoneOre.php
index 10e701a6f..3477a3519 100644
--- a/src/block/RedstoneOre.php
+++ b/src/block/RedstoneOre.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\FortuneDropHelper;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
@@ -31,7 +32,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function mt_rand;
-class RedstoneOre extends Opaque{
+class RedstoneOre extends Opaque implements Lightable{
use LightableTrait;
public function getLightLevel() : int{
diff --git a/src/block/RedstoneRepeater.php b/src/block/RedstoneRepeater.php
index bf9d0c5da..4059ff1cc 100644
--- a/src/block/RedstoneRepeater.php
+++ b/src/block/RedstoneRepeater.php
@@ -23,7 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
+use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\block\utils\SupportType;
@@ -35,7 +37,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class RedstoneRepeater extends Flowable{
+class RedstoneRepeater extends Flowable implements PoweredByRedstone, HorizontalFacing{
use HorizontalFacingTrait;
use PoweredByRedstoneTrait;
use StaticSupportTrait;
diff --git a/src/block/RedstoneTorch.php b/src/block/RedstoneTorch.php
index 26c86038b..f73076ccc 100644
--- a/src/block/RedstoneTorch.php
+++ b/src/block/RedstoneTorch.php
@@ -23,10 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
-class RedstoneTorch extends Torch{
+class RedstoneTorch extends Torch implements Lightable{
use LightableTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
diff --git a/src/block/RedstoneWire.php b/src/block/RedstoneWire.php
index a2d293fca..6be27bcb4 100644
--- a/src/block/RedstoneWire.php
+++ b/src/block/RedstoneWire.php
@@ -23,13 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\AnalogRedstoneSignalEmitter;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
-class RedstoneWire extends Flowable{
+class RedstoneWire extends Flowable implements AnalogRedstoneSignalEmitter{
use AnalogRedstoneSignalEmitterTrait;
use StaticSupportTrait;
diff --git a/src/block/ResinClump.php b/src/block/ResinClump.php
index 75126edf3..2855a7cc3 100644
--- a/src/block/ResinClump.php
+++ b/src/block/ResinClump.php
@@ -24,9 +24,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\MultiAnySupportTrait;
+use pocketmine\block\utils\MultiFacing;
use pocketmine\block\utils\SupportType;
-final class ResinClump extends Transparent{
+final class ResinClump extends Transparent implements MultiFacing{
use MultiAnySupportTrait;
public function isSolid() : bool{
diff --git a/src/block/ShulkerBox.php b/src/block/ShulkerBox.php
index d557401ee..52a3b83cd 100644
--- a/src/block/ShulkerBox.php
+++ b/src/block/ShulkerBox.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\ShulkerBox as TileShulkerBox;
+use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -32,7 +33,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class ShulkerBox extends Opaque{
+class ShulkerBox extends Opaque implements AnyFacing{
use AnyFacingTrait;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
diff --git a/src/block/SimplePillar.php b/src/block/SimplePillar.php
index 98c89f89c..6a7af96ed 100644
--- a/src/block/SimplePillar.php
+++ b/src/block/SimplePillar.php
@@ -23,12 +23,13 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\PillarRotationTrait;
/**
* @internal This class provides a general base for pillar-like blocks. It **should not** be used for contract binding
* in APIs, because not all pillar-like blocks extend this class.
*/
-class SimplePillar extends Opaque{
+class SimplePillar extends Opaque implements PillarRotation{
use PillarRotationTrait;
}
diff --git a/src/block/SmallDripleaf.php b/src/block/SmallDripleaf.php
index d192e43db..846be5c93 100644
--- a/src/block/SmallDripleaf.php
+++ b/src/block/SmallDripleaf.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -36,7 +37,7 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\Position;
use function mt_rand;
-class SmallDripleaf extends Transparent{
+class SmallDripleaf extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
protected bool $top = false;
diff --git a/src/block/StainedGlass.php b/src/block/StainedGlass.php
index bc0d84877..baf4755bb 100644
--- a/src/block/StainedGlass.php
+++ b/src/block/StainedGlass.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-final class StainedGlass extends Glass{
+final class StainedGlass extends Glass implements Colored{
use ColoredTrait;
}
diff --git a/src/block/StainedGlassPane.php b/src/block/StainedGlassPane.php
index 18ecfdee0..897c291c7 100644
--- a/src/block/StainedGlassPane.php
+++ b/src/block/StainedGlassPane.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-final class StainedGlassPane extends GlassPane{
+final class StainedGlassPane extends GlassPane implements Colored{
use ColoredTrait;
}
diff --git a/src/block/StainedHardenedClay.php b/src/block/StainedHardenedClay.php
index 2c2c01ba3..765e97e4f 100644
--- a/src/block/StainedHardenedClay.php
+++ b/src/block/StainedHardenedClay.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-final class StainedHardenedClay extends HardenedClay{
+final class StainedHardenedClay extends HardenedClay implements Colored{
use ColoredTrait;
}
diff --git a/src/block/StainedHardenedGlass.php b/src/block/StainedHardenedGlass.php
index cc609a49a..c3a794e4d 100644
--- a/src/block/StainedHardenedGlass.php
+++ b/src/block/StainedHardenedGlass.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-final class StainedHardenedGlass extends HardenedGlass{
+final class StainedHardenedGlass extends HardenedGlass implements Colored{
use ColoredTrait;
}
diff --git a/src/block/StainedHardenedGlassPane.php b/src/block/StainedHardenedGlassPane.php
index 63dbe1f77..9631ff5a9 100644
--- a/src/block/StainedHardenedGlassPane.php
+++ b/src/block/StainedHardenedGlassPane.php
@@ -23,8 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-final class StainedHardenedGlassPane extends HardenedGlassPane{
+final class StainedHardenedGlassPane extends HardenedGlassPane implements Colored{
use ColoredTrait;
}
diff --git a/src/block/Stair.php b/src/block/Stair.php
index d66a9ce5c..56101de13 100644
--- a/src/block/Stair.php
+++ b/src/block/Stair.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\StairShape;
use pocketmine\block\utils\SupportType;
@@ -35,7 +36,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class Stair extends Transparent{
+class Stair extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
protected bool $upsideDown = false;
diff --git a/src/block/Stonecutter.php b/src/block/Stonecutter.php
index 30c19d25d..0fd259326 100644
--- a/src/block/Stonecutter.php
+++ b/src/block/Stonecutter.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\inventory\StonecutterInventory;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@@ -32,7 +33,7 @@ use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
-class Stonecutter extends Transparent{
+class Stonecutter extends Transparent implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
diff --git a/src/block/Sugarcane.php b/src/block/Sugarcane.php
index 2da2dc9b9..0874413c5 100644
--- a/src/block/Sugarcane.php
+++ b/src/block/Sugarcane.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\StaticSupportTrait;
@@ -34,7 +35,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\Position;
-class Sugarcane extends Flowable{
+class Sugarcane extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait {
onNearbyBlockChange as onSupportBlockChange;
diff --git a/src/block/SweetBerryBush.php b/src/block/SweetBerryBush.php
index eabdde118..881b7359f 100644
--- a/src/block/SweetBerryBush.php
+++ b/src/block/SweetBerryBush.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\FortuneDropHelper;
@@ -39,7 +40,7 @@ use pocketmine\player\Player;
use pocketmine\world\sound\SweetBerriesPickSound;
use function mt_rand;
-class SweetBerryBush extends Flowable{
+class SweetBerryBush extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
diff --git a/src/block/Trapdoor.php b/src/block/Trapdoor.php
index a903e1b5e..5e8a7dc3f 100644
--- a/src/block/Trapdoor.php
+++ b/src/block/Trapdoor.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@@ -34,7 +35,7 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\DoorSound;
-class Trapdoor extends Transparent{
+class Trapdoor extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
protected bool $open = false;
diff --git a/src/block/TripwireHook.php b/src/block/TripwireHook.php
index 325819825..4e40cf62e 100644
--- a/src/block/TripwireHook.php
+++ b/src/block/TripwireHook.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -32,7 +33,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-class TripwireHook extends Flowable{
+class TripwireHook extends Flowable implements HorizontalFacing{
use HorizontalFacingTrait;
protected bool $connected = false;
diff --git a/src/block/WallBanner.php b/src/block/WallBanner.php
index 5182fe9f8..ddb157cda 100644
--- a/src/block/WallBanner.php
+++ b/src/block/WallBanner.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
@@ -31,7 +32,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class WallBanner extends BaseBanner{
+final class WallBanner extends BaseBanner implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
diff --git a/src/block/WallCoralFan.php b/src/block/WallCoralFan.php
index f9dece1cd..67745a537 100644
--- a/src/block/WallCoralFan.php
+++ b/src/block/WallCoralFan.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@@ -33,7 +34,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class WallCoralFan extends BaseCoral{
+final class WallCoralFan extends BaseCoral implements HorizontalFacing{
use HorizontalFacingTrait;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
diff --git a/src/block/WallSign.php b/src/block/WallSign.php
index 07826eae7..c6b42608d 100644
--- a/src/block/WallSign.php
+++ b/src/block/WallSign.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
@@ -31,7 +32,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
-final class WallSign extends BaseSign{
+final class WallSign extends BaseSign implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
diff --git a/src/block/WeightedPressurePlate.php b/src/block/WeightedPressurePlate.php
index 726b31f6b..065f8b2c8 100644
--- a/src/block/WeightedPressurePlate.php
+++ b/src/block/WeightedPressurePlate.php
@@ -23,13 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\AnalogRedstoneSignalEmitter;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
use function ceil;
use function count;
use function max;
use function min;
-class WeightedPressurePlate extends PressurePlate{
+class WeightedPressurePlate extends PressurePlate implements AnalogRedstoneSignalEmitter{
use AnalogRedstoneSignalEmitterTrait;
private readonly float $signalStrengthFactor;
diff --git a/src/block/Wood.php b/src/block/Wood.php
index 127533b98..7aa667bc8 100644
--- a/src/block/Wood.php
+++ b/src/block/Wood.php
@@ -23,7 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\PillarRotationTrait;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Axe;
@@ -32,7 +34,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\ItemUseOnBlockSound;
-class Wood extends Opaque{
+class Wood extends Opaque implements PillarRotation, WoodMaterial{
use PillarRotationTrait;
use WoodTypeTrait;
diff --git a/src/block/WoodenButton.php b/src/block/WoodenButton.php
index 7ba8a7af0..4eed3a50e 100644
--- a/src/block/WoodenButton.php
+++ b/src/block/WoodenButton.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenButton extends Button{
+class WoodenButton extends Button implements WoodMaterial{
use WoodTypeTrait;
protected function getActivationTime() : int{
diff --git a/src/block/WoodenDoor.php b/src/block/WoodenDoor.php
index 96f349e49..b7918a820 100644
--- a/src/block/WoodenDoor.php
+++ b/src/block/WoodenDoor.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenDoor extends Door{
+class WoodenDoor extends Door implements WoodMaterial{
use WoodTypeTrait;
public function getFuelTime() : int{
diff --git a/src/block/WoodenFence.php b/src/block/WoodenFence.php
index c12043a86..73c8da44d 100644
--- a/src/block/WoodenFence.php
+++ b/src/block/WoodenFence.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenFence extends Fence{
+class WoodenFence extends Fence implements WoodMaterial{
use WoodTypeTrait;
public function getFuelTime() : int{
diff --git a/src/block/WoodenPressurePlate.php b/src/block/WoodenPressurePlate.php
index a629c2f1c..6d638788b 100644
--- a/src/block/WoodenPressurePlate.php
+++ b/src/block/WoodenPressurePlate.php
@@ -23,10 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodType;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenPressurePlate extends SimplePressurePlate{
+class WoodenPressurePlate extends SimplePressurePlate implements WoodMaterial{
use WoodTypeTrait;
public function __construct(
diff --git a/src/block/WoodenSlab.php b/src/block/WoodenSlab.php
index b388a36ea..3ed606c64 100644
--- a/src/block/WoodenSlab.php
+++ b/src/block/WoodenSlab.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenSlab extends Slab{
+class WoodenSlab extends Slab implements WoodMaterial{
use WoodTypeTrait;
public function getFuelTime() : int{
diff --git a/src/block/WoodenStairs.php b/src/block/WoodenStairs.php
index 0d9ba62ce..8da3fceb6 100644
--- a/src/block/WoodenStairs.php
+++ b/src/block/WoodenStairs.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenStairs extends Stair{
+class WoodenStairs extends Stair implements WoodMaterial{
use WoodTypeTrait;
public function getFuelTime() : int{
diff --git a/src/block/WoodenTrapdoor.php b/src/block/WoodenTrapdoor.php
index c0a6623a1..2b796df52 100644
--- a/src/block/WoodenTrapdoor.php
+++ b/src/block/WoodenTrapdoor.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\WoodMaterial;
use pocketmine\block\utils\WoodTypeTrait;
-class WoodenTrapdoor extends Trapdoor{
+class WoodenTrapdoor extends Trapdoor implements WoodMaterial{
use WoodTypeTrait;
public function getFuelTime() : int{
diff --git a/src/block/Wool.php b/src/block/Wool.php
index 0b008ac04..d47c27d27 100644
--- a/src/block/Wool.php
+++ b/src/block/Wool.php
@@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
-class Wool extends Opaque{
+class Wool extends Opaque implements Colored{
use ColoredTrait;
public function getFlameEncouragement() : int{
diff --git a/src/block/utils/Ageable.php b/src/block/utils/Ageable.php
new file mode 100644
index 000000000..31fe3f459
--- /dev/null
+++ b/src/block/utils/Ageable.php
@@ -0,0 +1,34 @@
+
Date: Sun, 3 Aug 2025 15:47:12 +0100
Subject: [PATCH 083/140] BlockStateUpgrader: All but removed dependency on
BlockStateData
---
.../block/upgrade/BlockStateUpgrader.php | 83 +++++++++----------
1 file changed, 37 insertions(+), 46 deletions(-)
diff --git a/src/data/bedrock/block/upgrade/BlockStateUpgrader.php b/src/data/bedrock/block/upgrade/BlockStateUpgrader.php
index 2dce762b8..a3e72807e 100644
--- a/src/data/bedrock/block/upgrade/BlockStateUpgrader.php
+++ b/src/data/bedrock/block/upgrade/BlockStateUpgrader.php
@@ -75,6 +75,8 @@ final class BlockStateUpgrader{
public function upgrade(BlockStateData $blockStateData) : BlockStateData{
$version = $blockStateData->getVersion();
+ $name = $blockStateData->getName();
+ $states = $blockStateData->getStates();
foreach($this->upgradeSchemas as $resultVersion => $schemaList){
/*
* Sometimes Mojang made changes without bumping the version ID.
@@ -91,57 +93,54 @@ final class BlockStateUpgrader{
}
foreach($schemaList as $schema){
- $blockStateData = $this->applySchema($schema, $blockStateData);
+ [$name, $states] = $this->applySchema($schema, $name, $states);
}
}
- if($this->outputVersion > $version){
- //always update the version number of the blockstate, even if it didn't change - this is needed for
- //external tools
- $blockStateData = new BlockStateData($blockStateData->getName(), $blockStateData->getStates(), $this->outputVersion);
- }
- return $blockStateData;
+ return new BlockStateData($name, $states, $this->outputVersion);
}
- private function applySchema(BlockStateUpgradeSchema $schema, BlockStateData $blockStateData) : BlockStateData{
- $newStateData = $this->applyStateRemapped($schema, $blockStateData);
- if($newStateData !== null){
- return $newStateData;
+ /**
+ * @param Tag[] $states
+ * @phpstan-param array $states
+ *
+ * @return (string|Tag[])[]
+ * @phpstan-return array{0: string, 1: array}
+ */
+ private function applySchema(BlockStateUpgradeSchema $schema, string $oldName, array $states) : array{
+ $remapped = $this->applyStateRemapped($schema, $oldName, $states);
+ if($remapped !== null){
+ return $remapped;
}
- $oldName = $blockStateData->getName();
- $states = $blockStateData->getStates();
-
if(isset($schema->renamedIds[$oldName]) && isset($schema->flattenedProperties[$oldName])){
//TODO: this probably ought to be validated when the schema is constructed
throw new AssumptionFailedError("Both renamedIds and flattenedProperties are set for the same block ID \"$oldName\" - don't know what to do");
}
if(isset($schema->renamedIds[$oldName])){
- $newName = $schema->renamedIds[$oldName] ?? null;
+ $newName = $schema->renamedIds[$oldName];
}elseif(isset($schema->flattenedProperties[$oldName])){
[$newName, $states] = $this->applyPropertyFlattened($schema->flattenedProperties[$oldName], $oldName, $states);
}else{
- $newName = null;
+ $newName = $oldName;
}
- $stateChanges = 0;
+ $states = $this->applyPropertyAdded($schema, $oldName, $states);
+ $states = $this->applyPropertyRemoved($schema, $oldName, $states);
+ $states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states);
+ $states = $this->applyPropertyValueChanged($schema, $oldName, $states);
- $states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges);
- $states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges);
- $states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges);
- $states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges);
-
- if($newName !== null || $stateChanges > 0){
- return new BlockStateData($newName ?? $oldName, $states, $schema->getVersionId());
- }
-
- return $blockStateData;
+ return [$newName, $states];
}
- private function applyStateRemapped(BlockStateUpgradeSchema $schema, BlockStateData $blockStateData) : ?BlockStateData{
- $oldName = $blockStateData->getName();
- $oldState = $blockStateData->getStates();
-
+ /**
+ * @param Tag[] $oldState
+ * @phpstan-param array $oldState
+ *
+ * @return (string|Tag[])[]|null
+ * @phpstan-return array{0: string, 1: array}|null
+ */
+ private function applyStateRemapped(BlockStateUpgradeSchema $schema, string $oldName, array $oldState) : ?array{
if(isset($schema->remappedStates[$oldName])){
foreach($schema->remappedStates[$oldName] as $remap){
if(count($remap->oldState) > count($oldState)){
@@ -168,7 +167,7 @@ final class BlockStateUpgrader{
}
}
- return new BlockStateData($newName, $newState, $schema->getVersionId());
+ return [$newName, $newState];
}
}
@@ -182,11 +181,10 @@ final class BlockStateUpgrader{
* @return Tag[]
* @phpstan-return array
*/
- private function applyPropertyAdded(BlockStateUpgradeSchema $schema, string $oldName, array $states, int &$stateChanges) : array{
+ private function applyPropertyAdded(BlockStateUpgradeSchema $schema, string $oldName, array $states) : array{
if(isset($schema->addedProperties[$oldName])){
foreach(Utils::stringifyKeys($schema->addedProperties[$oldName]) as $propertyName => $value){
if(!isset($states[$propertyName])){
- $stateChanges++;
$states[$propertyName] = $value;
}
}
@@ -202,13 +200,10 @@ final class BlockStateUpgrader{
* @return Tag[]
* @phpstan-return array
*/
- private function applyPropertyRemoved(BlockStateUpgradeSchema $schema, string $oldName, array $states, int &$stateChanges) : array{
+ private function applyPropertyRemoved(BlockStateUpgradeSchema $schema, string $oldName, array $states) : array{
if(isset($schema->removedProperties[$oldName])){
foreach($schema->removedProperties[$oldName] as $propertyName){
- if(isset($states[$propertyName])){
- $stateChanges++;
- unset($states[$propertyName]);
- }
+ unset($states[$propertyName]);
}
}
@@ -234,12 +229,11 @@ final class BlockStateUpgrader{
* @return Tag[]
* @phpstan-return array
*/
- private function applyPropertyRenamedOrValueChanged(BlockStateUpgradeSchema $schema, string $oldName, array $states, int &$stateChanges) : array{
+ private function applyPropertyRenamedOrValueChanged(BlockStateUpgradeSchema $schema, string $oldName, array $states) : array{
if(isset($schema->renamedProperties[$oldName])){
foreach(Utils::stringifyKeys($schema->renamedProperties[$oldName]) as $oldPropertyName => $newPropertyName){
$oldValue = $states[$oldPropertyName] ?? null;
if($oldValue !== null){
- $stateChanges++;
unset($states[$oldPropertyName]);
//If a value remap is needed, we need to do it here, since we won't be able to locate the property
@@ -260,16 +254,13 @@ final class BlockStateUpgrader{
* @return Tag[]
* @phpstan-return array
*/
- private function applyPropertyValueChanged(BlockStateUpgradeSchema $schema, string $oldName, array $states, int &$stateChanges) : array{
+ private function applyPropertyValueChanged(BlockStateUpgradeSchema $schema, string $oldName, array $states) : array{
if(isset($schema->remappedPropertyValues[$oldName])){
foreach(Utils::stringifyKeys($schema->remappedPropertyValues[$oldName]) as $oldPropertyName => $remappedValues){
$oldValue = $states[$oldPropertyName] ?? null;
if($oldValue !== null){
$newValue = $this->locateNewPropertyValue($schema, $oldName, $oldPropertyName, $oldValue);
- if($newValue !== $oldValue){
- $stateChanges++;
- $states[$oldPropertyName] = $newValue;
- }
+ $states[$oldPropertyName] = $newValue;
}
}
}
From 89d18f929ffdd31d7da0cedb24e120bd33170355 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 6 Aug 2025 15:48:29 +0100
Subject: [PATCH 084/140] RakLibServer: fixed deadlock on thread crash
synchronized block -> getCrashInfo -> join -> synchronized on the same
context on the child thread -> deadlock
instead we check for isTerminated and then get the crash info outside
of the synchronized block.
---
src/network/mcpe/raklib/RakLibServer.php | 16 ++++++++--------
src/thread/CommonThreadPartsTrait.php | 2 ++
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/network/mcpe/raklib/RakLibServer.php b/src/network/mcpe/raklib/RakLibServer.php
index d5e825bee..f66734ee5 100644
--- a/src/network/mcpe/raklib/RakLibServer.php
+++ b/src/network/mcpe/raklib/RakLibServer.php
@@ -68,17 +68,17 @@ class RakLibServer extends Thread{
public function startAndWait(int $options = NativeThread::INHERIT_NONE) : void{
$this->start($options);
$this->synchronized(function() : void{
- while(!$this->ready && $this->getCrashInfo() === null){
+ while(!$this->ready && !$this->isTerminated()){
$this->wait();
}
- $crashInfo = $this->getCrashInfo();
- if($crashInfo !== null){
- if($crashInfo->getType() === SocketException::class){
- throw new SocketException($crashInfo->getMessage());
- }
- throw new ThreadCrashException("RakLib failed to start", $crashInfo);
- }
});
+ $crashInfo = $this->getCrashInfo();
+ if($crashInfo !== null){
+ if($crashInfo->getType() === SocketException::class){
+ throw new SocketException($crashInfo->getMessage());
+ }
+ throw new ThreadCrashException("RakLib failed to start", $crashInfo);
+ }
}
protected function onRun() : void{
diff --git a/src/thread/CommonThreadPartsTrait.php b/src/thread/CommonThreadPartsTrait.php
index de606a7b2..d7d51d40f 100644
--- a/src/thread/CommonThreadPartsTrait.php
+++ b/src/thread/CommonThreadPartsTrait.php
@@ -100,6 +100,8 @@ trait CommonThreadPartsTrait{
//*before* the shutdown handler is invoked, so we might land here before the crash info has been set.
//In the future this should probably be fixed by running the shutdown handlers before setting isTerminated,
//but this workaround should be good enough for now.
+ //WARNING: Do not call this inside a synchronized block on this thread's context. Because the shutdown handler
+ //runs in a synchronized block, this will result in a deadlock.
if($this->isTerminated() && !$this->isJoined()){
$this->join();
}
From 173b685b022d40de3c8fbe5de6a1435a81a148af Mon Sep 17 00:00:00 2001
From: Dries C <15795262+dries-c@users.noreply.github.com>
Date: Wed, 6 Aug 2025 17:41:44 +0200
Subject: [PATCH 085/140] Bedrock 1.21.100 (#6760)
---------
Co-authored-by: Dylan T.
---
changelogs/5.32.md | 17 +++++++
composer.json | 6 +--
composer.lock | 44 +++++++++----------
src/VersionInfo.php | 4 +-
src/data/bedrock/WorldDataVersions.php | 6 +--
src/data/bedrock/block/BlockTypeNames.php | 8 ++++
src/data/bedrock/item/ItemTypeNames.php | 11 +++++
.../mcpe/handler/PreSpawnPacketHandler.php | 1 +
.../biome/model/BiomeDefinitionEntryData.php | 2 +-
9 files changed, 68 insertions(+), 31 deletions(-)
create mode 100644 changelogs/5.32.md
diff --git a/changelogs/5.32.md b/changelogs/5.32.md
new file mode 100644
index 000000000..16b9aaff4
--- /dev/null
+++ b/changelogs/5.32.md
@@ -0,0 +1,17 @@
+# 5.32.0
+Released 6th August 2025.
+
+This is a support release for Minecraft: Bedrock Edition 1.21.100.
+
+**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.21.100.
+- Removed support for earlier versions.
+
+## Fixes
+- Fixed deadlock on RakLib thread crash (e.g. due to port binding failure).
diff --git a/composer.json b/composer.json
index ce4994d4f..e66269b40 100644
--- a/composer.json
+++ b/composer.json
@@ -34,9 +34,9 @@
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
- "pocketmine/bedrock-data": "~5.2.0+bedrock-1.21.93",
- "pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
- "pocketmine/bedrock-protocol": "~39.1.0+bedrock-1.21.93",
+ "pocketmine/bedrock-data": "~5.3.0+bedrock-1.21.100",
+ "pocketmine/bedrock-item-upgrade-schema": "~1.15.0+bedrock-1.21.100",
+ "pocketmine/bedrock-protocol": "~40.0.0+bedrock-1.21.100",
"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 2e5e83a94..9a69e6e14 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": "4dc5ea726d881d8c52d1b5299485d940",
+ "content-hash": "402ad5667b1e636a8ec6acf2f1b5f055",
"packages": [
{
"name": "adhocore/json-comment",
@@ -204,16 +204,16 @@
},
{
"name": "pocketmine/bedrock-data",
- "version": "5.2.0+bedrock-1.21.93",
+ "version": "5.3.0+bedrock-1.21.100",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
- "reference": "740e18e490c6a102b774518ff2224a06762bcaf8"
+ "reference": "5279e76261df158d5af187cfaafc1618c1da9e3f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/740e18e490c6a102b774518ff2224a06762bcaf8",
- "reference": "740e18e490c6a102b774518ff2224a06762bcaf8",
+ "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/5279e76261df158d5af187cfaafc1618c1da9e3f",
+ "reference": "5279e76261df158d5af187cfaafc1618c1da9e3f",
"shasum": ""
},
"type": "library",
@@ -224,22 +224,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.21.93"
+ "source": "https://github.com/pmmp/BedrockData/tree/5.3.0+bedrock-1.21.100"
},
- "time": "2025-07-08T12:30:28+00:00"
+ "time": "2025-07-30T22:07:56+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
- "version": "1.14.0",
+ "version": "1.15.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
- "reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb"
+ "reference": "09e0dbe9743f21a76b1fe04b2b4136785775f52b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
- "reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
+ "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/09e0dbe9743f21a76b1fe04b2b4136785775f52b",
+ "reference": "09e0dbe9743f21a76b1fe04b2b4136785775f52b",
"shasum": ""
},
"type": "library",
@@ -250,22 +250,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.14.0"
+ "source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.15.0"
},
- "time": "2024-12-04T12:22:49+00:00"
+ "time": "2025-08-06T15:08:48+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
- "version": "39.1.0+bedrock-1.21.93",
+ "version": "40.0.0+bedrock-1.21.100",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
- "reference": "e9bc5fb691d18dab229a158462c13f0c6fea79c8"
+ "reference": "5e95cab3a6e6c24920e0c25ca4aaf887ed4b70ca"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/e9bc5fb691d18dab229a158462c13f0c6fea79c8",
- "reference": "e9bc5fb691d18dab229a158462c13f0c6fea79c8",
+ "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5e95cab3a6e6c24920e0c25ca4aaf887ed4b70ca",
+ "reference": "5e95cab3a6e6c24920e0c25ca4aaf887ed4b70ca",
"shasum": ""
},
"require": {
@@ -296,9 +296,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/39.1.0+bedrock-1.21.93"
+ "source": "https://github.com/pmmp/BedrockProtocol/tree/40.0.0+bedrock-1.21.100"
},
- "time": "2025-07-08T12:31:39+00:00"
+ "time": "2025-08-06T15:13:45+00:00"
},
{
"name": "pocketmine/binaryutils",
@@ -2756,7 +2756,7 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@@ -2787,9 +2787,9 @@
"ext-zlib": ">=1.2.11",
"composer-runtime-api": "^2.0"
},
- "platform-dev": [],
+ "platform-dev": {},
"platform-overrides": {
"php": "8.1.0"
},
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index aeb4d9ff8..b0a533298 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.31.1";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const BASE_VERSION = "5.32.0";
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
diff --git a/src/data/bedrock/WorldDataVersions.php b/src/data/bedrock/WorldDataVersions.php
index ca36795fa..e682eb43a 100644
--- a/src/data/bedrock/WorldDataVersions.php
+++ b/src/data/bedrock/WorldDataVersions.php
@@ -54,13 +54,13 @@ final class WorldDataVersions{
* This may be lower than the current protocol version if PocketMine-MP does not yet support features of the newer
* version. This allows the protocol to be updated independently of world format support.
*/
- public const NETWORK = 818;
+ public const NETWORK = 827;
public const LAST_OPENED_IN = [
1, //major
21, //minor
- 90, //patch
- 3, //revision
+ 100, //patch
+ 23, //revision
0 //is beta
];
}
diff --git a/src/data/bedrock/block/BlockTypeNames.php b/src/data/bedrock/block/BlockTypeNames.php
index 527a01345..71402c74a 100644
--- a/src/data/bedrock/block/BlockTypeNames.php
+++ b/src/data/bedrock/block/BlockTypeNames.php
@@ -255,6 +255,7 @@ final class BlockTypeNames{
public const CONDUIT = "minecraft:conduit";
public const COPPER_BLOCK = "minecraft:copper_block";
public const COPPER_BULB = "minecraft:copper_bulb";
+ public const COPPER_CHEST = "minecraft:copper_chest";
public const COPPER_DOOR = "minecraft:copper_door";
public const COPPER_GRATE = "minecraft:copper_grate";
public const COPPER_ORE = "minecraft:copper_ore";
@@ -533,6 +534,7 @@ final class BlockTypeNames{
public const EXPOSED_CHISELED_COPPER = "minecraft:exposed_chiseled_copper";
public const EXPOSED_COPPER = "minecraft:exposed_copper";
public const EXPOSED_COPPER_BULB = "minecraft:exposed_copper_bulb";
+ public const EXPOSED_COPPER_CHEST = "minecraft:exposed_copper_chest";
public const EXPOSED_COPPER_DOOR = "minecraft:exposed_copper_door";
public const EXPOSED_COPPER_GRATE = "minecraft:exposed_copper_grate";
public const EXPOSED_COPPER_TRAPDOOR = "minecraft:exposed_copper_trapdoor";
@@ -857,6 +859,7 @@ final class BlockTypeNames{
public const OXIDIZED_CHISELED_COPPER = "minecraft:oxidized_chiseled_copper";
public const OXIDIZED_COPPER = "minecraft:oxidized_copper";
public const OXIDIZED_COPPER_BULB = "minecraft:oxidized_copper_bulb";
+ public const OXIDIZED_COPPER_CHEST = "minecraft:oxidized_copper_chest";
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
public const OXIDIZED_COPPER_GRATE = "minecraft:oxidized_copper_grate";
public const OXIDIZED_COPPER_TRAPDOOR = "minecraft:oxidized_copper_trapdoor";
@@ -1211,6 +1214,7 @@ final class BlockTypeNames{
public const WAXED_CHISELED_COPPER = "minecraft:waxed_chiseled_copper";
public const WAXED_COPPER = "minecraft:waxed_copper";
public const WAXED_COPPER_BULB = "minecraft:waxed_copper_bulb";
+ public const WAXED_COPPER_CHEST = "minecraft:waxed_copper_chest";
public const WAXED_COPPER_DOOR = "minecraft:waxed_copper_door";
public const WAXED_COPPER_GRATE = "minecraft:waxed_copper_grate";
public const WAXED_COPPER_TRAPDOOR = "minecraft:waxed_copper_trapdoor";
@@ -1221,6 +1225,7 @@ final class BlockTypeNames{
public const WAXED_EXPOSED_CHISELED_COPPER = "minecraft:waxed_exposed_chiseled_copper";
public const WAXED_EXPOSED_COPPER = "minecraft:waxed_exposed_copper";
public const WAXED_EXPOSED_COPPER_BULB = "minecraft:waxed_exposed_copper_bulb";
+ public const WAXED_EXPOSED_COPPER_CHEST = "minecraft:waxed_exposed_copper_chest";
public const WAXED_EXPOSED_COPPER_DOOR = "minecraft:waxed_exposed_copper_door";
public const WAXED_EXPOSED_COPPER_GRATE = "minecraft:waxed_exposed_copper_grate";
public const WAXED_EXPOSED_COPPER_TRAPDOOR = "minecraft:waxed_exposed_copper_trapdoor";
@@ -1231,6 +1236,7 @@ final class BlockTypeNames{
public const WAXED_OXIDIZED_CHISELED_COPPER = "minecraft:waxed_oxidized_chiseled_copper";
public const WAXED_OXIDIZED_COPPER = "minecraft:waxed_oxidized_copper";
public const WAXED_OXIDIZED_COPPER_BULB = "minecraft:waxed_oxidized_copper_bulb";
+ public const WAXED_OXIDIZED_COPPER_CHEST = "minecraft:waxed_oxidized_copper_chest";
public const WAXED_OXIDIZED_COPPER_DOOR = "minecraft:waxed_oxidized_copper_door";
public const WAXED_OXIDIZED_COPPER_GRATE = "minecraft:waxed_oxidized_copper_grate";
public const WAXED_OXIDIZED_COPPER_TRAPDOOR = "minecraft:waxed_oxidized_copper_trapdoor";
@@ -1241,6 +1247,7 @@ final class BlockTypeNames{
public const WAXED_WEATHERED_CHISELED_COPPER = "minecraft:waxed_weathered_chiseled_copper";
public const WAXED_WEATHERED_COPPER = "minecraft:waxed_weathered_copper";
public const WAXED_WEATHERED_COPPER_BULB = "minecraft:waxed_weathered_copper_bulb";
+ public const WAXED_WEATHERED_COPPER_CHEST = "minecraft:waxed_weathered_copper_chest";
public const WAXED_WEATHERED_COPPER_DOOR = "minecraft:waxed_weathered_copper_door";
public const WAXED_WEATHERED_COPPER_GRATE = "minecraft:waxed_weathered_copper_grate";
public const WAXED_WEATHERED_COPPER_TRAPDOOR = "minecraft:waxed_weathered_copper_trapdoor";
@@ -1251,6 +1258,7 @@ final class BlockTypeNames{
public const WEATHERED_CHISELED_COPPER = "minecraft:weathered_chiseled_copper";
public const WEATHERED_COPPER = "minecraft:weathered_copper";
public const WEATHERED_COPPER_BULB = "minecraft:weathered_copper_bulb";
+ public const WEATHERED_COPPER_CHEST = "minecraft:weathered_copper_chest";
public const WEATHERED_COPPER_DOOR = "minecraft:weathered_copper_door";
public const WEATHERED_COPPER_GRATE = "minecraft:weathered_copper_grate";
public const WEATHERED_COPPER_TRAPDOOR = "minecraft:weathered_copper_trapdoor";
diff --git a/src/data/bedrock/item/ItemTypeNames.php b/src/data/bedrock/item/ItemTypeNames.php
index 3178386ca..5c648ff38 100644
--- a/src/data/bedrock/item/ItemTypeNames.php
+++ b/src/data/bedrock/item/ItemTypeNames.php
@@ -153,8 +153,19 @@ final class ItemTypeNames{
public const COOKED_RABBIT = "minecraft:cooked_rabbit";
public const COOKED_SALMON = "minecraft:cooked_salmon";
public const COOKIE = "minecraft:cookie";
+ public const COPPER_AXE = "minecraft:copper_axe";
+ public const COPPER_BOOTS = "minecraft:copper_boots";
+ public const COPPER_CHESTPLATE = "minecraft:copper_chestplate";
public const COPPER_DOOR = "minecraft:copper_door";
+ public const COPPER_GOLEM_SPAWN_EGG = "minecraft:copper_golem_spawn_egg";
+ public const COPPER_HELMET = "minecraft:copper_helmet";
+ public const COPPER_HOE = "minecraft:copper_hoe";
public const COPPER_INGOT = "minecraft:copper_ingot";
+ public const COPPER_LEGGINGS = "minecraft:copper_leggings";
+ public const COPPER_NUGGET = "minecraft:copper_nugget";
+ public const COPPER_PICKAXE = "minecraft:copper_pickaxe";
+ public const COPPER_SHOVEL = "minecraft:copper_shovel";
+ public const COPPER_SWORD = "minecraft:copper_sword";
public const CORAL = "minecraft:coral";
public const CORAL_BLOCK = "minecraft:coral_block";
public const CORAL_FAN = "minecraft:coral_fan";
diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php
index 99f65e78f..4aa8be227 100644
--- a/src/network/mcpe/handler/PreSpawnPacketHandler.php
+++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php
@@ -108,6 +108,7 @@ class PreSpawnPacketHandler extends PacketHandler{
Uuid::fromString(Uuid::NIL),
false,
false,
+ false,
new NetworkPermissions(disableClientSounds: true),
[],
0,
diff --git a/src/world/biome/model/BiomeDefinitionEntryData.php b/src/world/biome/model/BiomeDefinitionEntryData.php
index 8a5c3d354..bb63b36e1 100644
--- a/src/world/biome/model/BiomeDefinitionEntryData.php
+++ b/src/world/biome/model/BiomeDefinitionEntryData.php
@@ -28,7 +28,7 @@ namespace pocketmine\world\biome\model;
*/
final class BiomeDefinitionEntryData{
/** @required */
- public ?int $id;
+ public int $id;
/** @required */
public float $temperature;
From 275fdc4280bcbcf48556e4f5c282ab73f82cf56c Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Wed, 6 Aug 2025 15:42:50 +0000
Subject: [PATCH 086/140] 5.32.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/16781699267
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index b0a533298..f28239816 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.32.0";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.32.1";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From 0b9e680753270ba8ccc4f724c89b14df1b7ae2fe Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 6 Aug 2025 17:15:21 +0100
Subject: [PATCH 087/140] Fix GitHub release trigger actions borked
https://github.com/actions/runner/issues/2788
---
.github/workflows/build-docker-image.yml | 31 +++++++++++++++-----
.github/workflows/discord-release-notify.yml | 17 +++++++++--
.github/workflows/update-updater-api.yml | 17 +++++++++--
3 files changed, 54 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
index a3921f820..9319f9e2f 100644
--- a/.github/workflows/build-docker-image.yml
+++ b/.github/workflows/build-docker-image.yml
@@ -4,6 +4,11 @@ on:
release:
types:
- published
+ workflow_dispatch:
+ inputs:
+ release:
+ description: 'Tag name to build'
+ required: true
jobs:
build:
@@ -33,11 +38,23 @@ jobs:
repository: pmmp/PocketMine-Docker
fetch-depth: 1
- - name: Get tag names
+
+ - name: Get tag name
id: tag-name
run: |
- VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
- echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT
+ if [[ "${{ github.event_name }}" == "release" ]]; then
+ echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
+ elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
+ echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
+ else
+ echo "Unsupported event type: ${{ github.event_name }}"
+ exit 1
+ fi
+
+ - name: Parse version
+ id: version
+ run: |
+ VERSION="${{ steps.tag-name.outputs.TAG_NAME }}"
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
@@ -71,8 +88,8 @@ jobs:
push: true
context: ./pocketmine-mp
tags: |
- ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
- ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
+ ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
+ ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
@@ -84,8 +101,8 @@ jobs:
push: true
context: ./pocketmine-mp
tags: |
- ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
- ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
+ ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
+ ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
diff --git a/.github/workflows/discord-release-notify.yml b/.github/workflows/discord-release-notify.yml
index 906f227ea..697b6358b 100644
--- a/.github/workflows/discord-release-notify.yml
+++ b/.github/workflows/discord-release-notify.yml
@@ -4,6 +4,11 @@ on:
release:
types:
- published
+ workflow_dispatch:
+ inputs:
+ release:
+ description: 'Release to make notification for'
+ required: true
jobs:
build:
@@ -30,9 +35,17 @@ jobs:
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- - name: Get actual tag name
+ - name: Get tag name
id: tag-name
- run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
+ run: |
+ if [[ "${{ github.event_name }}" == "release" ]]; then
+ echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
+ elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
+ echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
+ else
+ echo "Unsupported event type: ${{ github.event_name }}"
+ exit 1
+ fi
- name: Run webhook post script
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}
diff --git a/.github/workflows/update-updater-api.yml b/.github/workflows/update-updater-api.yml
index 3f42062fd..031950ba8 100644
--- a/.github/workflows/update-updater-api.yml
+++ b/.github/workflows/update-updater-api.yml
@@ -4,6 +4,11 @@ on:
release:
types:
- published
+ workflow_dispatch:
+ inputs:
+ release:
+ description: 'Release to publish info for'
+ required: true
jobs:
build:
@@ -19,9 +24,17 @@ jobs:
repository: ${{ github.repository_owner }}/update.pmmp.io
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
- - name: Get actual tag name
+ - name: Get tag name
id: tag-name
- run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
+ run: |
+ if [[ "${{ github.event_name }}" == "release" ]]; then
+ echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
+ elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
+ echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
+ else
+ echo "Unsupported event type: ${{ github.event_name }}"
+ exit 1
+ fi
- name: Download new release information
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
From 11612ed0e2a554ed94f654a625656e5f6b9a14b3 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Mon, 11 Aug 2025 00:49:37 +0100
Subject: [PATCH 088/140] Fixed content log warning about recipe with missing
ID
---
src/network/mcpe/cache/CraftingDataCache.php | 16 ++++++++++++----
.../mcpe/handler/ItemStackRequestExecutor.php | 6 ++++--
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/network/mcpe/cache/CraftingDataCache.php b/src/network/mcpe/cache/CraftingDataCache.php
index 14523f74c..da0f37c44 100644
--- a/src/network/mcpe/cache/CraftingDataCache.php
+++ b/src/network/mcpe/cache/CraftingDataCache.php
@@ -56,6 +56,12 @@ final class CraftingDataCache{
*/
private array $caches = [];
+ /**
+ * The client doesn't like recipes with ID 0 (as of 1.21.100) and complains about them in the content log
+ * This doesn't actually affect the function of the recipe, but it is annoying, so this offset fixes it
+ */
+ public const RECIPE_ID_OFFSET = 1;
+
public function getCache(CraftingManager $manager) : CraftingDataPacket{
$id = spl_object_id($manager);
if(!isset($this->caches[$id])){
@@ -82,6 +88,8 @@ final class CraftingDataCache{
$noUnlockingRequirement = new RecipeUnlockingRequirement(null);
foreach($manager->getCraftingRecipeIndex() as $index => $recipe){
+ //the client doesn't like recipes with an ID of 0, so we need to offset them
+ $recipeNetId = $index + self::RECIPE_ID_OFFSET;
if($recipe instanceof ShapelessRecipe){
$typeTag = match($recipe->getType()){
ShapelessRecipeType::CRAFTING => CraftingRecipeBlockName::CRAFTING_TABLE,
@@ -91,14 +99,14 @@ final class CraftingDataCache{
};
$recipesWithTypeIds[] = new ProtocolShapelessRecipe(
CraftingDataPacket::ENTRY_SHAPELESS,
- Binary::writeInt($index),
+ Binary::writeInt($recipeNetId),
array_map($converter->coreRecipeIngredientToNet(...), $recipe->getIngredientList()),
array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
$nullUUID,
$typeTag,
50,
$noUnlockingRequirement,
- $index
+ $recipeNetId
);
}elseif($recipe instanceof ShapedRecipe){
$inputs = [];
@@ -110,7 +118,7 @@ final class CraftingDataCache{
}
$recipesWithTypeIds[] = $r = new ProtocolShapedRecipe(
CraftingDataPacket::ENTRY_SHAPED,
- Binary::writeInt($index),
+ Binary::writeInt($recipeNetId),
$inputs,
array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
$nullUUID,
@@ -118,7 +126,7 @@ final class CraftingDataCache{
50,
true,
$noUnlockingRequirement,
- $index,
+ $recipeNetId,
);
}else{
//TODO: probably special recipe types
diff --git a/src/network/mcpe/handler/ItemStackRequestExecutor.php b/src/network/mcpe/handler/ItemStackRequestExecutor.php
index d71a1c6bf..4eddf3100 100644
--- a/src/network/mcpe/handler/ItemStackRequestExecutor.php
+++ b/src/network/mcpe/handler/ItemStackRequestExecutor.php
@@ -35,6 +35,7 @@ use pocketmine\inventory\transaction\TransactionBuilder;
use pocketmine\inventory\transaction\TransactionBuilderInventory;
use pocketmine\item\Durable;
use pocketmine\item\Item;
+use pocketmine\network\mcpe\cache\CraftingDataCache;
use pocketmine\network\mcpe\InventoryManager;
use pocketmine\network\mcpe\protocol\types\inventory\ContainerUIIds;
use pocketmine\network\mcpe\protocol\types\inventory\FullContainerName;
@@ -238,9 +239,10 @@ class ItemStackRequestExecutor{
throw new ItemStackRequestProcessException("Cannot craft a recipe more than 256 times");
}
$craftingManager = $this->player->getServer()->getCraftingManager();
- $recipe = $craftingManager->getCraftingRecipeFromIndex($recipeId);
+ $recipeIndex = $recipeId - CraftingDataCache::RECIPE_ID_OFFSET;
+ $recipe = $craftingManager->getCraftingRecipeFromIndex($recipeIndex);
if($recipe === null){
- throw new ItemStackRequestProcessException("No such crafting recipe index: $recipeId");
+ throw new ItemStackRequestProcessException("No such crafting recipe index: $recipeIndex");
}
$this->specialTransaction = new CraftingTransaction($this->player, $craftingManager, [], $recipe, $repetitions);
From c417ecd30d20520227b15e09eda87db492ab0a6a Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Tue, 12 Aug 2025 18:38:24 +0100
Subject: [PATCH 089/140] NetworkSession: Abort packet processing if handling
triggered a disconnection this shows up when requesting invalid data during
resource pack handling, for example
---
src/network/mcpe/NetworkSession.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php
index bea3f8131..234ad4765 100644
--- a/src/network/mcpe/NetworkSession.php
+++ b/src/network/mcpe/NetworkSession.php
@@ -415,6 +415,11 @@ class NetworkSession{
$this->logger->debug($packet->getName() . ": " . base64_encode($buffer));
throw PacketHandlingException::wrap($e, "Error processing " . $packet->getName());
}
+ if(!$this->isConnected()){
+ //handling this packet may have caused a disconnection
+ $this->logger->debug("Aborting batch processing due to server-side disconnection");
+ break;
+ }
}
}catch(PacketDecodeException|BinaryDataException $e){
$this->logger->logException($e);
From e375437439df51f7862b6b98318394643fcd6724 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Tue, 12 Aug 2025 20:11:35 +0100
Subject: [PATCH 090/140] ResourcePacksPacketHandler: harden checks for client
responses
---
.../handler/ResourcePacksPacketHandler.php | 30 ++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/src/network/mcpe/handler/ResourcePacksPacketHandler.php b/src/network/mcpe/handler/ResourcePacksPacketHandler.php
index a9ffae6f7..d98d8e9ad 100644
--- a/src/network/mcpe/handler/ResourcePacksPacketHandler.php
+++ b/src/network/mcpe/handler/ResourcePacksPacketHandler.php
@@ -36,6 +36,7 @@ use pocketmine\network\mcpe\protocol\types\Experiments;
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackInfoEntry;
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackStackEntry;
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackType;
+use pocketmine\network\PacketHandlingException;
use pocketmine\resourcepacks\ResourcePack;
use Ramsey\Uuid\Uuid;
use function array_keys;
@@ -43,6 +44,7 @@ use function array_map;
use function ceil;
use function count;
use function implode;
+use function sprintf;
use function strpos;
use function strtolower;
use function substr;
@@ -66,6 +68,9 @@ class ResourcePacksPacketHandler extends PacketHandler{
*/
private array $resourcePacksById = [];
+ private bool $requestedMetadata = false;
+ private bool $requestedStack = false;
+
/** @var bool[][] uuid => [chunk index => hasSent] */
private array $downloadedChunks = [];
@@ -140,6 +145,21 @@ class ResourcePacksPacketHandler extends PacketHandler{
$this->session->disconnect("Refused resource packs", "You must accept resource packs to join this server.", true);
break;
case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
+ if($this->requestedMetadata){
+ throw new PacketHandlingException("Cannot request resource pack metadata multiple times");
+ }
+ $this->requestedMetadata = true;
+
+ if($this->requestedStack){
+ //client already told us that they have all the packs, they shouldn't be asking for more
+ throw new PacketHandlingException("Cannot request resource pack metadata after resource pack stack");
+ }
+
+ if(count($packet->packIds) > count($this->resourcePacksById)){
+ throw new PacketHandlingException(sprintf("Requested metadata for more resource packs (%d) than available on the server (%d)", count($packet->packIds), count($this->resourcePacksById)));
+ }
+
+ $seen = [];
foreach($packet->packIds as $uuid){
//dirty hack for mojang's dirty hack for versions
$splitPos = strpos($uuid, "_");
@@ -153,6 +173,9 @@ class ResourcePacksPacketHandler extends PacketHandler{
$this->disconnectWithError("Unknown pack $uuid requested, available packs: " . implode(", ", array_keys($this->resourcePacksById)));
return false;
}
+ if(isset($seen[$pack->getPackId()])){
+ throw new PacketHandlingException("Repeated metadata request for pack $uuid");
+ }
$this->session->sendDataPacket(ResourcePackDataInfoPacket::create(
$pack->getPackId(),
@@ -163,11 +186,16 @@ class ResourcePacksPacketHandler extends PacketHandler{
false,
ResourcePackType::RESOURCES //TODO: this might be an addon (not behaviour pack), needed to properly support client-side custom items
));
+ $seen[$pack->getPackId()] = true;
}
$this->session->getLogger()->debug("Player requested download of " . count($packet->packIds) . " resource packs");
-
break;
case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
+ if($this->requestedStack){
+ throw new PacketHandlingException("Cannot request resource pack stack multiple times");
+ }
+ $this->requestedStack = true;
+
$stack = array_map(static function(ResourcePack $pack) : ResourcePackStackEntry{
return new ResourcePackStackEntry($pack->getPackId(), $pack->getPackVersion(), ""); //TODO: subpacks
}, $this->resourcePackStack);
From 442049d564dbf4af4d4a2c741501793b1a8b600a Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Thu, 14 Aug 2025 11:37:24 +0100
Subject: [PATCH 091/140] Prepare 5.32.1 release (#6766)
---
changelogs/5.32.md | 8 ++++++++
src/VersionInfo.php | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/changelogs/5.32.md b/changelogs/5.32.md
index 16b9aaff4..414330351 100644
--- a/changelogs/5.32.md
+++ b/changelogs/5.32.md
@@ -15,3 +15,11 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
## Fixes
- Fixed deadlock on RakLib thread crash (e.g. due to port binding failure).
+
+# 5.32.1
+Released 14th August 2025.
+
+## Fixes
+- Hardened checks when processing resource pack sending during player logins.
+- Fixed content log warning about crafting recipe with missing ID.
+- Fixed packets in a batch still being processed after one of them caused the session to be terminated.
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index f28239816..77a9a2bee 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -32,7 +32,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.32.1";
- public const IS_DEVELOPMENT_BUILD = true;
+ public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
/**
From f633416f0595e81e4c176fc00bd85652afe3f4bb Mon Sep 17 00:00:00 2001
From: "pmmp-admin-bot[bot]"
<188621379+pmmp-admin-bot[bot]@users.noreply.github.com>
Date: Thu, 14 Aug 2025 10:38:22 +0000
Subject: [PATCH 092/140] 5.32.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/16962847004
---
src/VersionInfo.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/VersionInfo.php b/src/VersionInfo.php
index 77a9a2bee..b3f37677b 100644
--- a/src/VersionInfo.php
+++ b/src/VersionInfo.php
@@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
- public const BASE_VERSION = "5.32.1";
- public const IS_DEVELOPMENT_BUILD = false;
+ public const BASE_VERSION = "5.32.2";
+ public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**
From cb7a562c8b0a8577b40f8689c52bf03b13a3cf8a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 15 Aug 2025 00:17:24 +0000
Subject: [PATCH 093/140] Bump the github-actions group across 1 directory with
2 updates (#6767)
---
.github/workflows/build-docker-image.yml | 2 +-
.github/workflows/copilot-setup-steps.yml | 4 ++--
.github/workflows/discord-release-notify.yml | 4 ++--
.github/workflows/draft-release-pr-check.yml | 6 +++---
.github/workflows/draft-release.yml | 4 ++--
.github/workflows/main-php-matrix.yml | 8 ++++----
.github/workflows/main.yml | 6 +++---
.github/workflows/update-updater-api.yml | 2 +-
8 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
index 9319f9e2f..acfc3d3a7 100644
--- a/.github/workflows/build-docker-image.yml
+++ b/.github/workflows/build-docker-image.yml
@@ -33,7 +33,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: pmmp/PocketMine-Docker
fetch-depth: 1
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index ef0b122e1..c644876e0 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -18,7 +18,7 @@ jobs:
contents: read
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
@@ -41,7 +41,7 @@ jobs:
run: composer install --prefer-dist --no-interaction
- name: Clone extension stubs
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: pmmp/phpstorm-stubs
path: extension-stubs
diff --git a/.github/workflows/discord-release-notify.yml b/.github/workflows/discord-release-notify.yml
index 697b6358b..e15134fdb 100644
--- a/.github/workflows/discord-release-notify.yml
+++ b/.github/workflows/discord-release-notify.yml
@@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP and tools
- uses: shivammathur/setup-php@2.34.1
+ uses: shivammathur/setup-php@2.35.3
with:
php-version: 8.2
diff --git a/.github/workflows/draft-release-pr-check.yml b/.github/workflows/draft-release-pr-check.yml
index b2575f9be..cf6036968 100644
--- a/.github/workflows/draft-release-pr-check.yml
+++ b/.github/workflows/draft-release-pr-check.yml
@@ -30,7 +30,7 @@ jobs:
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Check IS_DEVELOPMENT_BUILD flag
id: validate
@@ -46,10 +46,10 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP
- uses: shivammathur/setup-php@2.34.1
+ uses: shivammathur/setup-php@2.35.3
with:
php-version: 8.2
diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml
index 014ea531c..052635234 100644
--- a/.github/workflows/draft-release.yml
+++ b/.github/workflows/draft-release.yml
@@ -82,12 +82,12 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
with:
submodules: true
- name: Setup PHP
- uses: shivammathur/setup-php@2.34.1
+ uses: shivammathur/setup-php@2.35.3
with:
php-version: ${{ env.PHP_VERSION }}
diff --git a/.github/workflows/main-php-matrix.yml b/.github/workflows/main-php-matrix.yml
index 015a33188..7637a3956 100644
--- a/.github/workflows/main-php-matrix.yml
+++ b/.github/workflows/main-php-matrix.yml
@@ -27,7 +27,7 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
@@ -59,7 +59,7 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
@@ -91,7 +91,7 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
with:
submodules: true
@@ -125,7 +125,7 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 4d020c10b..9d5f282bb 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -25,10 +25,10 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Setup PHP and tools
- uses: shivammathur/setup-php@2.34.1
+ uses: shivammathur/setup-php@2.35.3
with:
php-version: 8.3
tools: php-cs-fixer:3.75
@@ -45,7 +45,7 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0
diff --git a/.github/workflows/update-updater-api.yml b/.github/workflows/update-updater-api.yml
index 031950ba8..841fa7d44 100644
--- a/.github/workflows/update-updater-api.yml
+++ b/.github/workflows/update-updater-api.yml
@@ -19,7 +19,7 @@ jobs:
- name: Install jq
run: sudo apt update && sudo apt install jq -y
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
with:
repository: ${{ github.repository_owner }}/update.pmmp.io
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
From 1e8612cfc895d3884ecbc91f0d60c48edc959ffc Mon Sep 17 00:00:00 2001
From: ShockedPlot7560
Date: Fri, 15 Aug 2025 21:39:13 +0200
Subject: [PATCH 094/140] BlockObjectToStateSerializer: Avoid unnecessary
Writer and Closure (#6759)
---------
Co-authored-by: Dylan K. Taylor
---
.../convert/BlockObjectToStateSerializer.php | 264 +++++++++---------
1 file changed, 132 insertions(+), 132 deletions(-)
diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
index 27d550f13..49f0269ed 100644
--- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
+++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
@@ -195,8 +195,8 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
* These callables actually accept Block, but for the sake of type completeness, it has to be never, since we can't
* describe the bottom type of a type hierarchy only containing Block.
*
- * @var \Closure[]
- * @phpstan-var array
+ * @var (\Closure|BlockStateData)[]
+ * @phpstan-var array
*/
private array $serializers = [];
@@ -233,17 +233,18 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
/**
* @phpstan-template TBlockType of Block
* @phpstan-param TBlockType $block
- * @phpstan-param \Closure(TBlockType) : Writer $serializer
+ * @phpstan-param \Closure(TBlockType) : (Writer|BlockStateData)|Writer|BlockStateData $serializer
*/
- public function map(Block $block, \Closure $serializer) : void{
+ public function map(Block $block, \Closure|Writer|BlockStateData $serializer) : void{
if(isset($this->serializers[$block->getTypeId()])){
throw new \InvalidArgumentException("Block type ID " . $block->getTypeId() . " already has a serializer registered");
}
- $this->serializers[$block->getTypeId()] = $serializer;
+ //writer accepted for convenience only
+ $this->serializers[$block->getTypeId()] = $serializer instanceof Writer ? $serializer->getBlockStateData() : $serializer;
}
public function mapSimple(Block $block, string $id) : void{
- $this->map($block, fn() => Writer::create($id));
+ $this->map($block, BlockStateData::current($id, []));
}
public function mapSlab(Slab $block, string $singleId, string $doubleId) : void{
@@ -272,19 +273,21 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
throw new BlockStateSerializeException("No serializer registered for " . get_class($blockState) . " with type ID $typeId");
}
+ if($locatedSerializer instanceof BlockStateData){ //static data, not dependent on state
+ return $locatedSerializer;
+ }
+
/**
* TODO: there is no guarantee that this type actually matches that of $blockState - a plugin may have stolen
* the type ID of the block (which never makes sense, even in a world where overriding block types is a thing).
* In the future we'll need some way to guarantee that type IDs are never reused (perhaps spl_object_id()?)
*
- * @var \Closure $serializer
- * @phpstan-var \Closure(TBlockType) : Writer $serializer
+ * @var \Closure $locatedSerializer
+ * @phpstan-var \Closure(TBlockType) : (Writer|BlockStateData) $locatedSerializer
*/
- $serializer = $locatedSerializer;
+ $result = $locatedSerializer($blockState);
- /** @var Writer $writer */
- $writer = $serializer($blockState);
- return $writer->getBlockStateData();
+ return $result instanceof Writer ? $result->getBlockStateData() : $result;
}
private function registerCandleSerializers() : void{
@@ -330,7 +333,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
}
public function registerFlatColorBlockSerializers() : void{
- $this->map(Blocks::STAINED_HARDENED_GLASS(), fn(StainedHardenedGlass $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::STAINED_HARDENED_GLASS(), fn(StainedHardenedGlass $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::HARD_BLACK_STAINED_GLASS,
DyeColor::BLUE => Ids::HARD_BLUE_STAINED_GLASS,
DyeColor::BROWN => Ids::HARD_BROWN_STAINED_GLASS,
@@ -347,9 +350,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
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()){
+ $this->map(Blocks::STAINED_HARDENED_GLASS_PANE(), fn(StainedHardenedGlassPane $block) => BlockStateData::current(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,
@@ -366,7 +369,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
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()){
@@ -390,7 +393,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeHorizontalFacing($block->getFacing());
});
- $this->map(Blocks::WOOL(), fn(Wool $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::WOOL(), fn(Wool $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_WOOL,
DyeColor::BLUE => Ids::BLUE_WOOL,
DyeColor::BROWN => Ids::BROWN_WOOL,
@@ -407,9 +410,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_WOOL,
DyeColor::WHITE => Ids::WHITE_WOOL,
DyeColor::YELLOW => Ids::YELLOW_WOOL,
- }));
+ }, []));
- $this->map(Blocks::CARPET(), fn(Carpet $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::CARPET(), fn(Carpet $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_CARPET,
DyeColor::BLUE => Ids::BLUE_CARPET,
DyeColor::BROWN => Ids::BROWN_CARPET,
@@ -426,9 +429,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_CARPET,
DyeColor::WHITE => Ids::WHITE_CARPET,
DyeColor::YELLOW => Ids::YELLOW_CARPET,
- }));
+ }, []));
- $this->map(Blocks::DYED_SHULKER_BOX(), fn(DyedShulkerBox $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::DYED_SHULKER_BOX(), fn(DyedShulkerBox $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_SHULKER_BOX,
DyeColor::BLUE => Ids::BLUE_SHULKER_BOX,
DyeColor::BROWN => Ids::BROWN_SHULKER_BOX,
@@ -445,9 +448,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_SHULKER_BOX,
DyeColor::WHITE => Ids::WHITE_SHULKER_BOX,
DyeColor::YELLOW => Ids::YELLOW_SHULKER_BOX,
- }));
+ }, []));
- $this->map(Blocks::CONCRETE(), fn(Concrete $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::CONCRETE(), fn(Concrete $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_CONCRETE,
DyeColor::BLUE => Ids::BLUE_CONCRETE,
DyeColor::BROWN => Ids::BROWN_CONCRETE,
@@ -464,9 +467,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_CONCRETE,
DyeColor::WHITE => Ids::WHITE_CONCRETE,
DyeColor::YELLOW => Ids::YELLOW_CONCRETE,
- }));
+ }, []));
- $this->map(Blocks::CONCRETE_POWDER(), fn(ConcretePowder $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::CONCRETE_POWDER(), fn(ConcretePowder $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_CONCRETE_POWDER,
DyeColor::BLUE => Ids::BLUE_CONCRETE_POWDER,
DyeColor::BROWN => Ids::BROWN_CONCRETE_POWDER,
@@ -483,9 +486,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_CONCRETE_POWDER,
DyeColor::WHITE => Ids::WHITE_CONCRETE_POWDER,
DyeColor::YELLOW => Ids::YELLOW_CONCRETE_POWDER,
- }));
+ }, []));
- $this->map(Blocks::STAINED_CLAY(), fn(StainedHardenedClay $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::STAINED_CLAY(), fn(StainedHardenedClay $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_TERRACOTTA,
DyeColor::BLUE => Ids::BLUE_TERRACOTTA,
DyeColor::BROWN => Ids::BROWN_TERRACOTTA,
@@ -502,9 +505,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_TERRACOTTA,
DyeColor::WHITE => Ids::WHITE_TERRACOTTA,
DyeColor::YELLOW => Ids::YELLOW_TERRACOTTA,
- }));
+ }, []));
- $this->map(Blocks::STAINED_GLASS(), fn(StainedGlass $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::STAINED_GLASS(), fn(StainedGlass $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_STAINED_GLASS,
DyeColor::BLUE => Ids::BLUE_STAINED_GLASS,
DyeColor::BROWN => Ids::BROWN_STAINED_GLASS,
@@ -521,9 +524,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_STAINED_GLASS,
DyeColor::WHITE => Ids::WHITE_STAINED_GLASS,
DyeColor::YELLOW => Ids::YELLOW_STAINED_GLASS,
- }));
+ }, []));
- $this->map(Blocks::STAINED_GLASS_PANE(), fn(StainedGlassPane $block) => Writer::create(match($block->getColor()){
+ $this->map(Blocks::STAINED_GLASS_PANE(), fn(StainedGlassPane $block) => BlockStateData::current(match($block->getColor()){
DyeColor::BLACK => Ids::BLACK_STAINED_GLASS_PANE,
DyeColor::BLUE => Ids::BLUE_STAINED_GLASS_PANE,
DyeColor::BROWN => Ids::BROWN_STAINED_GLASS_PANE,
@@ -540,19 +543,17 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::RED => Ids::RED_STAINED_GLASS_PANE,
DyeColor::WHITE => Ids::WHITE_STAINED_GLASS_PANE,
DyeColor::YELLOW => Ids::YELLOW_STAINED_GLASS_PANE,
- }));
+ }, []));
}
private function registerFlatCoralSerializers() : void{
- $this->map(Blocks::CORAL(), fn(Coral $block) => Writer::create(
- match($block->getCoralType()){
- CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL : Ids::BRAIN_CORAL,
- CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL : Ids::BUBBLE_CORAL,
- CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL : Ids::FIRE_CORAL,
- CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL : Ids::HORN_CORAL,
- CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL : Ids::TUBE_CORAL,
- }
- ));
+ $this->map(Blocks::CORAL(), fn(Coral $block) => BlockStateData::current(match($block->getCoralType()){
+ CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL : Ids::BRAIN_CORAL,
+ CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL : Ids::BUBBLE_CORAL,
+ CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL : Ids::FIRE_CORAL,
+ CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL : Ids::HORN_CORAL,
+ CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL : Ids::TUBE_CORAL,
+ }, []));
$this->map(Blocks::CORAL_FAN(), fn(FloorCoralFan $block) => Writer::create(
match($block->getCoralType()){
@@ -568,15 +569,13 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
default => throw new BlockStateSerializeException("Invalid axis {$axis}"),
}));
- $this->map(Blocks::CORAL_BLOCK(), fn(CoralBlock $block) => Writer::create(
- match($block->getCoralType()){
- CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_BLOCK : Ids::BRAIN_CORAL_BLOCK,
- CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_BLOCK : Ids::BUBBLE_CORAL_BLOCK,
- CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_BLOCK : Ids::FIRE_CORAL_BLOCK,
- CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_BLOCK : Ids::HORN_CORAL_BLOCK,
- CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_BLOCK : Ids::TUBE_CORAL_BLOCK,
- }
- ));
+ $this->map(Blocks::CORAL_BLOCK(), fn(CoralBlock $block) => BlockStateData::current(match($block->getCoralType()){
+ CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_BLOCK : Ids::BRAIN_CORAL_BLOCK,
+ CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_BLOCK : Ids::BUBBLE_CORAL_BLOCK,
+ CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_BLOCK : Ids::FIRE_CORAL_BLOCK,
+ CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_BLOCK : Ids::HORN_CORAL_BLOCK,
+ CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_BLOCK : Ids::TUBE_CORAL_BLOCK,
+ }, []));
$this->map(Blocks::WALL_CORAL_FAN(), fn(WallCoralFan $block) => Writer::create(
match($block->getCoralType()){
@@ -591,7 +590,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
}
private function registerCauldronSerializers() : void{
- $this->map(Blocks::CAULDRON(), fn() => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, 0));
+ $this->map(Blocks::CAULDRON(), Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, 0));
$this->map(Blocks::LAVA_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_LAVA, $b->getFillLevel()));
//potion cauldrons store their real information in the block actor data
$this->map(Blocks::POTION_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel()));
@@ -798,52 +797,60 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
}
private function registerCopperSerializers() : void{
- $this->map(Blocks::COPPER(), function(Copper $block) : Writer{
+ $this->map(Blocks::COPPER(), function(Copper $block) : BlockStateData{
$oxidation = $block->getOxidation();
- return new Writer($block->isWaxed() ?
- Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
- Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
+ return BlockStateData::current(
+ $block->isWaxed() ?
+ Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
+ Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER),
+ []
);
});
- $this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
+ $this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : BlockStateData{
$oxidation = $block->getOxidation();
- return new Writer($block->isWaxed() ?
- Helper::selectCopperId($oxidation,
- Ids::WAXED_CHISELED_COPPER,
- Ids::WAXED_EXPOSED_CHISELED_COPPER,
- Ids::WAXED_WEATHERED_CHISELED_COPPER,
- Ids::WAXED_OXIDIZED_CHISELED_COPPER
- ) :
- Helper::selectCopperId($oxidation,
- Ids::CHISELED_COPPER,
- Ids::EXPOSED_CHISELED_COPPER,
- Ids::WEATHERED_CHISELED_COPPER,
- Ids::OXIDIZED_CHISELED_COPPER
- )
+ return BlockStateData::current(
+ $block->isWaxed() ?
+ Helper::selectCopperId($oxidation,
+ Ids::WAXED_CHISELED_COPPER,
+ Ids::WAXED_EXPOSED_CHISELED_COPPER,
+ Ids::WAXED_WEATHERED_CHISELED_COPPER,
+ Ids::WAXED_OXIDIZED_CHISELED_COPPER
+ ) :
+ Helper::selectCopperId($oxidation,
+ Ids::CHISELED_COPPER,
+ Ids::EXPOSED_CHISELED_COPPER,
+ Ids::WEATHERED_CHISELED_COPPER,
+ Ids::OXIDIZED_CHISELED_COPPER
+ ),
+ []
);
});
- $this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
+ $this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : BlockStateData{
$oxidation = $block->getOxidation();
- return new Writer($block->isWaxed() ?
- Helper::selectCopperId($oxidation,
- Ids::WAXED_COPPER_GRATE,
- Ids::WAXED_EXPOSED_COPPER_GRATE,
- Ids::WAXED_WEATHERED_COPPER_GRATE,
- Ids::WAXED_OXIDIZED_COPPER_GRATE
- ) :
- Helper::selectCopperId($oxidation,
- Ids::COPPER_GRATE,
- Ids::EXPOSED_COPPER_GRATE,
- Ids::WEATHERED_COPPER_GRATE,
- Ids::OXIDIZED_COPPER_GRATE
- )
+ return BlockStateData::current(
+ $block->isWaxed() ?
+ Helper::selectCopperId($oxidation,
+ Ids::WAXED_COPPER_GRATE,
+ Ids::WAXED_EXPOSED_COPPER_GRATE,
+ Ids::WAXED_WEATHERED_COPPER_GRATE,
+ Ids::WAXED_OXIDIZED_COPPER_GRATE
+ ) :
+ Helper::selectCopperId($oxidation,
+ Ids::COPPER_GRATE,
+ Ids::EXPOSED_COPPER_GRATE,
+ Ids::WEATHERED_COPPER_GRATE,
+ Ids::OXIDIZED_COPPER_GRATE
+ ),
+ []
);
});
- $this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
+ $this->map(Blocks::CUT_COPPER(), function(Copper $block) : BlockStateData{
$oxidation = $block->getOxidation();
- return new Writer($block->isWaxed() ?
- Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
- Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
+ return BlockStateData::current(
+ $block->isWaxed() ?
+ Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
+ Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER),
+ []
);
});
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
@@ -1279,7 +1286,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered())
->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
});
- $this->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), fn() => Writer::create(Ids::MUSHROOM_STEM)
+ $this->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM)
->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM));
$this->map(Blocks::AMETHYST_CLUSTER(), fn(AmethystCluster $block) => Writer::create(
match($stage = $block->getStage()){
@@ -1476,13 +1483,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSlab(Blocks::DIORITE_SLAB(), Ids::DIORITE_SLAB, Ids::DIORITE_DOUBLE_SLAB);
$this->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS);
$this->map(Blocks::DIORITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::DIORITE_WALL)));
- $this->map(Blocks::DIRT(), function(Dirt $block) : Writer{
- return Writer::create(match($block->getDirtType()){
- DirtType::NORMAL => Ids::DIRT,
- DirtType::COARSE => Ids::COARSE_DIRT,
- DirtType::ROOTED => Ids::DIRT_WITH_ROOTS,
- });
- });
+ $this->map(Blocks::DIRT(), fn(Dirt $block) => BlockStateData::current(match($block->getDirtType()){
+ DirtType::NORMAL => Ids::DIRT,
+ DirtType::COARSE => Ids::COARSE_DIRT,
+ DirtType::ROOTED => Ids::DIRT_WITH_ROOTS,
+ }, []));
$this->map(Blocks::DOUBLE_TALLGRASS(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::TALL_GRASS)));
$this->map(Blocks::ELEMENT_CONSTRUCTOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::ELEMENT_CONSTRUCTOR)));
$this->map(Blocks::ENDER_CHEST(), function(EnderChest $block) : Writer{
@@ -1510,10 +1515,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::FIRE)
->writeInt(StateNames::AGE, $block->getAge());
});
- $this->map(Blocks::FLOWER_POT(), function() : Writer{
- return Writer::create(Ids::FLOWER_POT)
- ->writeBool(StateNames::UPDATE_BIT, false); //to keep MCPE happy
- });
+ $this->map(Blocks::FLOWER_POT(), Writer::create(Ids::FLOWER_POT)
+ ->writeBool(StateNames::UPDATE_BIT, false) //to keep MCPE happy
+ );
$this->map(Blocks::FROGLIGHT(), function(Froglight $block){
return Writer::create(match($block->getFroglightType()){
FroglightType::OCHRE => Ids::OCHRE_FROGLIGHT,
@@ -1579,27 +1583,25 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
LeverFacing::EAST => StringValues::LEVER_DIRECTION_EAST,
});
});
- $this->map(Blocks::LIGHT(), function(Light $block) : Writer{
- return Writer::create(match($block->getLightLevel()){
- 0 => Ids::LIGHT_BLOCK_0,
- 1 => Ids::LIGHT_BLOCK_1,
- 2 => Ids::LIGHT_BLOCK_2,
- 3 => Ids::LIGHT_BLOCK_3,
- 4 => Ids::LIGHT_BLOCK_4,
- 5 => Ids::LIGHT_BLOCK_5,
- 6 => Ids::LIGHT_BLOCK_6,
- 7 => Ids::LIGHT_BLOCK_7,
- 8 => Ids::LIGHT_BLOCK_8,
- 9 => Ids::LIGHT_BLOCK_9,
- 10 => Ids::LIGHT_BLOCK_10,
- 11 => Ids::LIGHT_BLOCK_11,
- 12 => Ids::LIGHT_BLOCK_12,
- 13 => Ids::LIGHT_BLOCK_13,
- 14 => Ids::LIGHT_BLOCK_14,
- 15 => Ids::LIGHT_BLOCK_15,
- default => throw new BlockStateSerializeException("Invalid light level " . $block->getLightLevel()),
- });
- });
+ $this->map(Blocks::LIGHT(), fn(Light $block) => BlockStateData::current(match($block->getLightLevel()){
+ 0 => Ids::LIGHT_BLOCK_0,
+ 1 => Ids::LIGHT_BLOCK_1,
+ 2 => Ids::LIGHT_BLOCK_2,
+ 3 => Ids::LIGHT_BLOCK_3,
+ 4 => Ids::LIGHT_BLOCK_4,
+ 5 => Ids::LIGHT_BLOCK_5,
+ 6 => Ids::LIGHT_BLOCK_6,
+ 7 => Ids::LIGHT_BLOCK_7,
+ 8 => Ids::LIGHT_BLOCK_8,
+ 9 => Ids::LIGHT_BLOCK_9,
+ 10 => Ids::LIGHT_BLOCK_10,
+ 11 => Ids::LIGHT_BLOCK_11,
+ 12 => Ids::LIGHT_BLOCK_12,
+ 13 => Ids::LIGHT_BLOCK_13,
+ 14 => Ids::LIGHT_BLOCK_14,
+ 15 => Ids::LIGHT_BLOCK_15,
+ default => throw new BlockStateSerializeException("Invalid light level " . $block->getLightLevel()),
+ }, []));
$this->map(Blocks::LIGHTNING_ROD(), function(LightningRod $block) : Writer{
return Writer::create(Ids::LIGHTNING_ROD)
->writeFacingDirection($block->getFacing());
@@ -1626,7 +1628,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::MUD_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::MUD_BRICK_WALL)));
$this->map(Blocks::MUDDY_MANGROVE_ROOTS(), fn(SimplePillar $block) => Writer::create(Ids::MUDDY_MANGROVE_ROOTS)
->writePillarAxis($block->getAxis()));
- $this->map(Blocks::MUSHROOM_STEM(), fn() => Writer::create(Ids::MUSHROOM_STEM)
+ $this->map(Blocks::MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM)
->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_STEM));
$this->mapSlab(Blocks::NETHER_BRICK_SLAB(), Ids::NETHER_BRICK_SLAB, Ids::NETHER_BRICK_DOUBLE_SLAB);
$this->mapStairs(Blocks::NETHER_BRICK_STAIRS(), Ids::NETHER_BRICK_STAIRS);
@@ -1698,12 +1700,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSlab(Blocks::PRISMARINE_SLAB(), Ids::PRISMARINE_SLAB, Ids::PRISMARINE_DOUBLE_SLAB);
$this->mapStairs(Blocks::PRISMARINE_STAIRS(), Ids::PRISMARINE_STAIRS);
$this->map(Blocks::PRISMARINE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::PRISMARINE_WALL)));
- $this->map(Blocks::PUMPKIN(), function() : Writer{
- return Writer::create(Ids::PUMPKIN)
- ->writeCardinalHorizontalFacing(Facing::SOUTH); //no longer used
- });
+ $this->map(Blocks::PUMPKIN(), Writer::create(Ids::PUMPKIN)
+ ->writeCardinalHorizontalFacing(Facing::SOUTH) //no longer used
+ );
$this->map(Blocks::PUMPKIN_STEM(), fn(PumpkinStem $block) => Helper::encodeStem($block, new Writer(Ids::PUMPKIN_STEM)));
- $this->map(Blocks::PURPUR(), fn() => Writer::create(Ids::PURPUR_BLOCK)->writePillarAxis(Axis::Y));
+ $this->map(Blocks::PURPUR(), Writer::create(Ids::PURPUR_BLOCK)->writePillarAxis(Axis::Y));
$this->map(Blocks::PURPLE_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_PURPLE)));
$this->map(Blocks::PURPUR_PILLAR(), function(SimplePillar $block) : Writer{
return Writer::create(Ids::PURPUR_PILLAR)
@@ -1711,7 +1712,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->mapSlab(Blocks::PURPUR_SLAB(), Ids::PURPUR_SLAB, Ids::PURPUR_DOUBLE_SLAB);
$this->mapStairs(Blocks::PURPUR_STAIRS(), Ids::PURPUR_STAIRS);
- $this->map(Blocks::QUARTZ(), fn() => Helper::encodeQuartz(Axis::Y, Writer::create(Ids::QUARTZ_BLOCK)));
+ $this->map(Blocks::QUARTZ(), Helper::encodeQuartz(Axis::Y, Writer::create(Ids::QUARTZ_BLOCK)));
$this->map(Blocks::QUARTZ_PILLAR(), fn(SimplePillar $block) => Helper::encodeQuartz($block->getAxis(), Writer::create(Ids::QUARTZ_PILLAR)));
$this->mapSlab(Blocks::QUARTZ_SLAB(), Ids::QUARTZ_SLAB, Ids::QUARTZ_DOUBLE_SLAB);
$this->mapStairs(Blocks::QUARTZ_STAIRS(), Ids::QUARTZ_STAIRS);
@@ -1774,7 +1775,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
});
$this->map(Blocks::SMOKER(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::SMOKER, Ids::LIT_SMOKER));
- $this->map(Blocks::SMOOTH_QUARTZ(), fn() => Helper::encodeQuartz(Axis::Y, Writer::create(Ids::SMOOTH_QUARTZ)));
+ $this->map(Blocks::SMOOTH_QUARTZ(), Helper::encodeQuartz(Axis::Y, Writer::create(Ids::SMOOTH_QUARTZ)));
$this->mapSlab(Blocks::SMOOTH_QUARTZ_SLAB(), Ids::SMOOTH_QUARTZ_SLAB, Ids::SMOOTH_QUARTZ_DOUBLE_SLAB);
$this->mapStairs(Blocks::SMOOTH_QUARTZ_STAIRS(), Ids::SMOOTH_QUARTZ_STAIRS);
$this->mapSlab(Blocks::SMOOTH_RED_SANDSTONE_SLAB(), Ids::SMOOTH_RED_SANDSTONE_SLAB, Ids::SMOOTH_RED_SANDSTONE_DOUBLE_SLAB);
@@ -1792,10 +1793,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(StateNames::EXTINGUISHED, !$block->isLit());
});
- $this->map(Blocks::SOUL_FIRE(), function() : Writer{
- return Writer::create(Ids::SOUL_FIRE)
- ->writeInt(StateNames::AGE, 0); //useless for soul fire, we don't track it
- });
+ $this->map(Blocks::SOUL_FIRE(), Writer::create(Ids::SOUL_FIRE)
+ ->writeInt(StateNames::AGE, 0) //useless for soul fire, we don't track it
+ );
$this->map(Blocks::SOUL_LANTERN(), function(Lantern $block) : Writer{
return Writer::create(Ids::SOUL_LANTERN)
->writeBool(StateNames::HANGING, $block->isHanging());
From e89523ce66729f79ef63c2edce676e0c1e1261bd Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Fri, 15 Aug 2025 22:02:12 +0100
Subject: [PATCH 095/140] First look at flattened ID specialisation for block
serializers
in the future we should be able to unify these, similarly to simple mappings.
unifying blocks with states will, however, be considerably more work.
only color benefits from this so far
---
.../convert/BlockObjectToStateSerializer.php | 334 ++++++------------
.../BlockStateToObjectDeserializer.php | 330 ++++++-----------
.../bedrock/block/convert/StringEnumMap.php | 78 ++++
.../bedrock/block/convert/ValueMappings.php | 83 +++++
4 files changed, 377 insertions(+), 448 deletions(-)
create mode 100644 src/data/bedrock/block/convert/StringEnumMap.php
create mode 100644 src/data/bedrock/block/convert/ValueMappings.php
diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
index 49f0269ed..6b545bd01 100644
--- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
+++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
@@ -290,86 +290,72 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return $result instanceof Writer ? $result->getBlockStateData() : $result;
}
+ /**
+ * @phpstan-template TBlock of Block
+ * @phpstan-template TEnum of \UnitEnum
+ *
+ * @phpstan-param TBlock $block
+ * @phpstan-param StringEnumMap $mapProperty
+ * @phpstan-param \Closure(TBlock) : TEnum $getProperty
+ * @phpstan-param ?\Closure(TBlock, Writer) : Writer $extra
+ */
+ public function mapFlattenedEnum(
+ Block $block,
+ StringEnumMap $mapProperty,
+ string $prefix,
+ string $suffix,
+ \Closure $getProperty,
+ ?\Closure $extra = null
+ ) : void{
+ $this->map($block, function(Block $block) use ($getProperty, $mapProperty, $prefix, $suffix, $extra) : Writer{
+ $property = $getProperty($block);
+ $infix = $mapProperty->enumToValue($property);
+ $id = $prefix . $infix . $suffix;
+ $writer = new Writer($id);
+ if($extra !== null){
+ $extra($block, $writer);
+ }
+ return $writer;
+ });
+ }
+
private function registerCandleSerializers() : void{
$this->map(Blocks::CANDLE(), fn(Candle $block) => Helper::encodeCandle($block, new Writer(Ids::CANDLE)));
- $this->map(Blocks::DYED_CANDLE(), fn(DyedCandle $block) => Helper::encodeCandle($block, new Writer(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_CANDLE,
- DyeColor::BLUE => Ids::BLUE_CANDLE,
- DyeColor::BROWN => Ids::BROWN_CANDLE,
- DyeColor::CYAN => Ids::CYAN_CANDLE,
- DyeColor::GRAY => Ids::GRAY_CANDLE,
- DyeColor::GREEN => Ids::GREEN_CANDLE,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_CANDLE,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_CANDLE,
- DyeColor::LIME => Ids::LIME_CANDLE,
- DyeColor::MAGENTA => Ids::MAGENTA_CANDLE,
- DyeColor::ORANGE => Ids::ORANGE_CANDLE,
- DyeColor::PINK => Ids::PINK_CANDLE,
- DyeColor::PURPLE => Ids::PURPLE_CANDLE,
- DyeColor::RED => Ids::RED_CANDLE,
- DyeColor::WHITE => Ids::WHITE_CANDLE,
- DyeColor::YELLOW => Ids::YELLOW_CANDLE,
- })));
+ $this->mapFlattenedEnum(
+ Blocks::DYED_CANDLE(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_candle",
+ fn(DyedCandle $block) => $block->getColor(),
+ Helper::encodeCandle(...)
+ );
$this->map(Blocks::CAKE_WITH_CANDLE(), fn(CakeWithCandle $block) => Writer::create(Ids::CANDLE_CAKE)
->writeBool(StateNames::LIT, $block->isLit()));
- $this->map(Blocks::CAKE_WITH_DYED_CANDLE(), fn(CakeWithDyedCandle $block) => Writer::create(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_CANDLE_CAKE,
- DyeColor::BLUE => Ids::BLUE_CANDLE_CAKE,
- DyeColor::BROWN => Ids::BROWN_CANDLE_CAKE,
- DyeColor::CYAN => Ids::CYAN_CANDLE_CAKE,
- DyeColor::GRAY => Ids::GRAY_CANDLE_CAKE,
- DyeColor::GREEN => Ids::GREEN_CANDLE_CAKE,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_CANDLE_CAKE,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_CANDLE_CAKE,
- DyeColor::LIME => Ids::LIME_CANDLE_CAKE,
- DyeColor::MAGENTA => Ids::MAGENTA_CANDLE_CAKE,
- DyeColor::ORANGE => Ids::ORANGE_CANDLE_CAKE,
- DyeColor::PINK => Ids::PINK_CANDLE_CAKE,
- DyeColor::PURPLE => Ids::PURPLE_CANDLE_CAKE,
- DyeColor::RED => Ids::RED_CANDLE_CAKE,
- DyeColor::WHITE => Ids::WHITE_CANDLE_CAKE,
- DyeColor::YELLOW => Ids::YELLOW_CANDLE_CAKE,
- })->writeBool(StateNames::LIT, $block->isLit()));
+ $this->mapFlattenedEnum(
+ Blocks::CAKE_WITH_DYED_CANDLE(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_candle_cake",
+ fn(CakeWithDyedCandle $block) => $block->getColor(),
+ fn(CakeWithDyedCandle $block, Writer $writer) => $writer->writeBool(StateNames::LIT, $block->isLit())
+ );
}
public function registerFlatColorBlockSerializers() : void{
- $this->map(Blocks::STAINED_HARDENED_GLASS(), fn(StainedHardenedGlass $block) => BlockStateData::current(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) => BlockStateData::current(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->mapFlattenedEnum(
+ Blocks::STAINED_HARDENED_GLASS(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:hard_",
+ "_stained_glass",
+ fn(StainedHardenedGlass $block) => $block->getColor()
+ );
+ $this->mapFlattenedEnum(
+ Blocks::STAINED_HARDENED_GLASS_PANE(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:hard_",
+ "_stained_glass_pane",
+ fn(StainedHardenedGlassPane $block) => $block->getColor(),
+ );
$this->map(Blocks::GLAZED_TERRACOTTA(), function(GlazedTerracotta $block) : Writer{
return Writer::create(match($block->getColor()){
@@ -393,157 +379,67 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeHorizontalFacing($block->getFacing());
});
- $this->map(Blocks::WOOL(), fn(Wool $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_WOOL,
- DyeColor::BLUE => Ids::BLUE_WOOL,
- DyeColor::BROWN => Ids::BROWN_WOOL,
- DyeColor::CYAN => Ids::CYAN_WOOL,
- DyeColor::GRAY => Ids::GRAY_WOOL,
- DyeColor::GREEN => Ids::GREEN_WOOL,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_WOOL,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_WOOL,
- DyeColor::LIME => Ids::LIME_WOOL,
- DyeColor::MAGENTA => Ids::MAGENTA_WOOL,
- DyeColor::ORANGE => Ids::ORANGE_WOOL,
- DyeColor::PINK => Ids::PINK_WOOL,
- DyeColor::PURPLE => Ids::PURPLE_WOOL,
- DyeColor::RED => Ids::RED_WOOL,
- DyeColor::WHITE => Ids::WHITE_WOOL,
- DyeColor::YELLOW => Ids::YELLOW_WOOL,
- }, []));
+ $this->mapFlattenedEnum(
+ Blocks::WOOL(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_wool",
+ fn(Wool $block) => $block->getColor()
+ );
- $this->map(Blocks::CARPET(), fn(Carpet $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_CARPET,
- DyeColor::BLUE => Ids::BLUE_CARPET,
- DyeColor::BROWN => Ids::BROWN_CARPET,
- DyeColor::CYAN => Ids::CYAN_CARPET,
- DyeColor::GRAY => Ids::GRAY_CARPET,
- DyeColor::GREEN => Ids::GREEN_CARPET,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_CARPET,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_CARPET,
- DyeColor::LIME => Ids::LIME_CARPET,
- DyeColor::MAGENTA => Ids::MAGENTA_CARPET,
- DyeColor::ORANGE => Ids::ORANGE_CARPET,
- DyeColor::PINK => Ids::PINK_CARPET,
- DyeColor::PURPLE => Ids::PURPLE_CARPET,
- DyeColor::RED => Ids::RED_CARPET,
- DyeColor::WHITE => Ids::WHITE_CARPET,
- DyeColor::YELLOW => Ids::YELLOW_CARPET,
- }, []));
+ $this->mapFlattenedEnum(
+ Blocks::CARPET(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_carpet",
+ fn(Carpet $block) => $block->getColor()
+ );
- $this->map(Blocks::DYED_SHULKER_BOX(), fn(DyedShulkerBox $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_SHULKER_BOX,
- DyeColor::BLUE => Ids::BLUE_SHULKER_BOX,
- DyeColor::BROWN => Ids::BROWN_SHULKER_BOX,
- DyeColor::CYAN => Ids::CYAN_SHULKER_BOX,
- DyeColor::GRAY => Ids::GRAY_SHULKER_BOX,
- DyeColor::GREEN => Ids::GREEN_SHULKER_BOX,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_SHULKER_BOX,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_SHULKER_BOX,
- DyeColor::LIME => Ids::LIME_SHULKER_BOX,
- DyeColor::MAGENTA => Ids::MAGENTA_SHULKER_BOX,
- DyeColor::ORANGE => Ids::ORANGE_SHULKER_BOX,
- DyeColor::PINK => Ids::PINK_SHULKER_BOX,
- DyeColor::PURPLE => Ids::PURPLE_SHULKER_BOX,
- DyeColor::RED => Ids::RED_SHULKER_BOX,
- DyeColor::WHITE => Ids::WHITE_SHULKER_BOX,
- DyeColor::YELLOW => Ids::YELLOW_SHULKER_BOX,
- }, []));
+ $this->mapFlattenedEnum(
+ Blocks::DYED_SHULKER_BOX(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_shulker_box",
+ fn(DyedShulkerBox $block) => $block->getColor()
+ );
- $this->map(Blocks::CONCRETE(), fn(Concrete $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_CONCRETE,
- DyeColor::BLUE => Ids::BLUE_CONCRETE,
- DyeColor::BROWN => Ids::BROWN_CONCRETE,
- DyeColor::CYAN => Ids::CYAN_CONCRETE,
- DyeColor::GRAY => Ids::GRAY_CONCRETE,
- DyeColor::GREEN => Ids::GREEN_CONCRETE,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_CONCRETE,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_CONCRETE,
- DyeColor::LIME => Ids::LIME_CONCRETE,
- DyeColor::MAGENTA => Ids::MAGENTA_CONCRETE,
- DyeColor::ORANGE => Ids::ORANGE_CONCRETE,
- DyeColor::PINK => Ids::PINK_CONCRETE,
- DyeColor::PURPLE => Ids::PURPLE_CONCRETE,
- DyeColor::RED => Ids::RED_CONCRETE,
- DyeColor::WHITE => Ids::WHITE_CONCRETE,
- DyeColor::YELLOW => Ids::YELLOW_CONCRETE,
- }, []));
+ $this->mapFlattenedEnum(
+ Blocks::CONCRETE(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_concrete",
+ fn(Concrete $block) => $block->getColor()
+ );
+ $this->mapFlattenedEnum(
+ Blocks::CONCRETE_POWDER(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_concrete_powder",
+ fn(ConcretePowder $block) => $block->getColor()
+ );
- $this->map(Blocks::CONCRETE_POWDER(), fn(ConcretePowder $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_CONCRETE_POWDER,
- DyeColor::BLUE => Ids::BLUE_CONCRETE_POWDER,
- DyeColor::BROWN => Ids::BROWN_CONCRETE_POWDER,
- DyeColor::CYAN => Ids::CYAN_CONCRETE_POWDER,
- DyeColor::GRAY => Ids::GRAY_CONCRETE_POWDER,
- DyeColor::GREEN => Ids::GREEN_CONCRETE_POWDER,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_CONCRETE_POWDER,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_CONCRETE_POWDER,
- DyeColor::LIME => Ids::LIME_CONCRETE_POWDER,
- DyeColor::MAGENTA => Ids::MAGENTA_CONCRETE_POWDER,
- DyeColor::ORANGE => Ids::ORANGE_CONCRETE_POWDER,
- DyeColor::PINK => Ids::PINK_CONCRETE_POWDER,
- DyeColor::PURPLE => Ids::PURPLE_CONCRETE_POWDER,
- DyeColor::RED => Ids::RED_CONCRETE_POWDER,
- DyeColor::WHITE => Ids::WHITE_CONCRETE_POWDER,
- DyeColor::YELLOW => Ids::YELLOW_CONCRETE_POWDER,
- }, []));
+ $this->mapFlattenedEnum(
+ Blocks::STAINED_CLAY(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_terracotta",
+ fn(StainedHardenedClay $block) => $block->getColor()
+ );
- $this->map(Blocks::STAINED_CLAY(), fn(StainedHardenedClay $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_TERRACOTTA,
- DyeColor::BLUE => Ids::BLUE_TERRACOTTA,
- DyeColor::BROWN => Ids::BROWN_TERRACOTTA,
- DyeColor::CYAN => Ids::CYAN_TERRACOTTA,
- DyeColor::GRAY => Ids::GRAY_TERRACOTTA,
- DyeColor::GREEN => Ids::GREEN_TERRACOTTA,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_TERRACOTTA,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_TERRACOTTA,
- DyeColor::LIME => Ids::LIME_TERRACOTTA,
- DyeColor::MAGENTA => Ids::MAGENTA_TERRACOTTA,
- DyeColor::ORANGE => Ids::ORANGE_TERRACOTTA,
- DyeColor::PINK => Ids::PINK_TERRACOTTA,
- DyeColor::PURPLE => Ids::PURPLE_TERRACOTTA,
- DyeColor::RED => Ids::RED_TERRACOTTA,
- DyeColor::WHITE => Ids::WHITE_TERRACOTTA,
- DyeColor::YELLOW => Ids::YELLOW_TERRACOTTA,
- }, []));
-
- $this->map(Blocks::STAINED_GLASS(), fn(StainedGlass $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_STAINED_GLASS,
- DyeColor::BLUE => Ids::BLUE_STAINED_GLASS,
- DyeColor::BROWN => Ids::BROWN_STAINED_GLASS,
- DyeColor::CYAN => Ids::CYAN_STAINED_GLASS,
- DyeColor::GRAY => Ids::GRAY_STAINED_GLASS,
- DyeColor::GREEN => Ids::GREEN_STAINED_GLASS,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_STAINED_GLASS,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_STAINED_GLASS,
- DyeColor::LIME => Ids::LIME_STAINED_GLASS,
- DyeColor::MAGENTA => Ids::MAGENTA_STAINED_GLASS,
- DyeColor::ORANGE => Ids::ORANGE_STAINED_GLASS,
- DyeColor::PINK => Ids::PINK_STAINED_GLASS,
- DyeColor::PURPLE => Ids::PURPLE_STAINED_GLASS,
- DyeColor::RED => Ids::RED_STAINED_GLASS,
- DyeColor::WHITE => Ids::WHITE_STAINED_GLASS,
- DyeColor::YELLOW => Ids::YELLOW_STAINED_GLASS,
- }, []));
-
- $this->map(Blocks::STAINED_GLASS_PANE(), fn(StainedGlassPane $block) => BlockStateData::current(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_STAINED_GLASS_PANE,
- DyeColor::BLUE => Ids::BLUE_STAINED_GLASS_PANE,
- DyeColor::BROWN => Ids::BROWN_STAINED_GLASS_PANE,
- DyeColor::CYAN => Ids::CYAN_STAINED_GLASS_PANE,
- DyeColor::GRAY => Ids::GRAY_STAINED_GLASS_PANE,
- DyeColor::GREEN => Ids::GREEN_STAINED_GLASS_PANE,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_STAINED_GLASS_PANE,
- DyeColor::LIGHT_GRAY => Ids::LIGHT_GRAY_STAINED_GLASS_PANE,
- DyeColor::LIME => Ids::LIME_STAINED_GLASS_PANE,
- DyeColor::MAGENTA => Ids::MAGENTA_STAINED_GLASS_PANE,
- DyeColor::ORANGE => Ids::ORANGE_STAINED_GLASS_PANE,
- DyeColor::PINK => Ids::PINK_STAINED_GLASS_PANE,
- DyeColor::PURPLE => Ids::PURPLE_STAINED_GLASS_PANE,
- DyeColor::RED => Ids::RED_STAINED_GLASS_PANE,
- DyeColor::WHITE => Ids::WHITE_STAINED_GLASS_PANE,
- DyeColor::YELLOW => Ids::YELLOW_STAINED_GLASS_PANE,
- }, []));
+ $this->mapFlattenedEnum(
+ Blocks::STAINED_GLASS(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_stained_glass",
+ fn(StainedGlass $block) => $block->getColor()
+ );
+ $this->mapFlattenedEnum(
+ Blocks::STAINED_GLASS_PANE(),
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_stained_glass_pane",
+ fn(StainedGlassPane $block) => $block->getColor()
+ );
}
private function registerFlatCoralSerializers() : void{
diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
index c55fde77a..cbeadc819 100644
--- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
+++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
@@ -27,6 +27,7 @@ use pocketmine\block\AmethystCluster;
use pocketmine\block\Anvil;
use pocketmine\block\Bamboo;
use pocketmine\block\Block;
+use pocketmine\block\CakeWithDyedCandle;
use pocketmine\block\CaveVines;
use pocketmine\block\ChorusFlower;
use pocketmine\block\DoublePitcherCrop;
@@ -157,97 +158,68 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map($strippedId, fn(Reader $in) => Helper::decodeLog($getBlock(), true, $in));
}
- private function registerCandleDeserializers() : void{
- $this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in));
- foreach([
- Ids::BLACK_CANDLE => DyeColor::BLACK,
- Ids::BLUE_CANDLE => DyeColor::BLUE,
- Ids::BROWN_CANDLE => DyeColor::BROWN,
- Ids::CYAN_CANDLE => DyeColor::CYAN,
- Ids::GRAY_CANDLE => DyeColor::GRAY,
- Ids::GREEN_CANDLE => DyeColor::GREEN,
- Ids::LIGHT_BLUE_CANDLE => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_CANDLE => DyeColor::LIGHT_GRAY,
- Ids::LIME_CANDLE => DyeColor::LIME,
- Ids::MAGENTA_CANDLE => DyeColor::MAGENTA,
- Ids::ORANGE_CANDLE => DyeColor::ORANGE,
- Ids::PINK_CANDLE => DyeColor::PINK,
- Ids::PURPLE_CANDLE => DyeColor::PURPLE,
- Ids::RED_CANDLE => DyeColor::RED,
- Ids::WHITE_CANDLE => DyeColor::WHITE,
- Ids::YELLOW_CANDLE => DyeColor::YELLOW,
- ] as $id => $color){
- $this->map($id, fn(Reader $in) => Helper::decodeCandle(Blocks::DYED_CANDLE()->setColor($color), $in));
- }
-
- $this->map(Ids::CANDLE_CAKE, fn(Reader $in) => Blocks::CAKE_WITH_CANDLE()->setLit($in->readBool(StateNames::LIT)));
- foreach([
- Ids::BLACK_CANDLE_CAKE => DyeColor::BLACK,
- Ids::BLUE_CANDLE_CAKE => DyeColor::BLUE,
- Ids::BROWN_CANDLE_CAKE => DyeColor::BROWN,
- Ids::CYAN_CANDLE_CAKE => DyeColor::CYAN,
- Ids::GRAY_CANDLE_CAKE => DyeColor::GRAY,
- Ids::GREEN_CANDLE_CAKE => DyeColor::GREEN,
- Ids::LIGHT_BLUE_CANDLE_CAKE => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_CANDLE_CAKE => DyeColor::LIGHT_GRAY,
- Ids::LIME_CANDLE_CAKE => DyeColor::LIME,
- Ids::MAGENTA_CANDLE_CAKE => DyeColor::MAGENTA,
- Ids::ORANGE_CANDLE_CAKE => DyeColor::ORANGE,
- Ids::PINK_CANDLE_CAKE => DyeColor::PINK,
- Ids::PURPLE_CANDLE_CAKE => DyeColor::PURPLE,
- Ids::RED_CANDLE_CAKE => DyeColor::RED,
- Ids::WHITE_CANDLE_CAKE => DyeColor::WHITE,
- Ids::YELLOW_CANDLE_CAKE => DyeColor::YELLOW,
- ] as $id => $color){
- $this->map($id, fn(Reader $in) => Blocks::CAKE_WITH_DYED_CANDLE()
- ->setColor($color)
- ->setLit($in->readBool(StateNames::LIT))
- );
+ /**
+ * @phpstan-template TBlock of Block
+ * @phpstan-template TEnum of \UnitEnum
+ *
+ * @phpstan-param StringEnumMap $mapProperty
+ * @phpstan-param \Closure(TEnum) : TBlock $getBlock
+ * @phpstan-param ?\Closure(TBlock, Reader) : TBlock $extra
+ */
+ public function mapFlattenedEnum(
+ StringEnumMap $mapProperty,
+ string $prefix,
+ string $suffix,
+ \Closure $getBlock,
+ ?\Closure $extra = null
+ ) : void{
+ foreach(Utils::stringifyKeys($mapProperty->getValueToEnum()) as $infix => $enumCase){
+ $id = $prefix . $infix . $suffix;
+ if($extra === null){
+ $this->map($id, fn() => $getBlock($enumCase));
+ }else{
+ $this->map($id, function(Reader $in) use ($enumCase, $getBlock, $extra) : Block{
+ $block = $getBlock($enumCase);
+ $extra($block, $in);
+ return $block;
+ });
+ }
}
}
- 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));
- }
+ private function registerCandleDeserializers() : void{
+ $this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in));
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_candle",
+ fn(DyeColor $color) => Blocks::DYED_CANDLE()->setColor($color),
+ Helper::decodeCandle(...)
+ );
- 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));
- }
+ $this->map(Ids::CANDLE_CAKE, fn(Reader $in) => Blocks::CAKE_WITH_CANDLE()->setLit($in->readBool(StateNames::LIT)));
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_candle_cake",
+ fn(DyeColor $color) => Blocks::CAKE_WITH_DYED_CANDLE()->setColor($color),
+ fn(CakeWithDyedCandle $block, Reader $in) => $block->setLit($in->readBool(StateNames::LIT))
+ );
+ }
+
+ private function registerFlatColorBlockDeserializers() : void{
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:hard_",
+ "_stained_glass",
+ fn(DyeColor $color) => Blocks::STAINED_HARDENED_GLASS()->setColor($color)
+ );
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:hard_",
+ "_stained_glass_pane",
+ fn(DyeColor $color) => Blocks::STAINED_HARDENED_GLASS_PANE()->setColor($color)
+ );
foreach([
Ids::BLACK_GLAZED_TERRACOTTA => DyeColor::BLACK,
@@ -273,110 +245,38 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
);
}
- foreach([
- Ids::BLACK_WOOL => DyeColor::BLACK,
- Ids::BLUE_WOOL => DyeColor::BLUE,
- Ids::BROWN_WOOL => DyeColor::BROWN,
- Ids::CYAN_WOOL => DyeColor::CYAN,
- Ids::GRAY_WOOL => DyeColor::GRAY,
- Ids::GREEN_WOOL => DyeColor::GREEN,
- Ids::LIGHT_BLUE_WOOL => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_WOOL => DyeColor::LIGHT_GRAY,
- Ids::LIME_WOOL => DyeColor::LIME,
- Ids::MAGENTA_WOOL => DyeColor::MAGENTA,
- Ids::ORANGE_WOOL => DyeColor::ORANGE,
- Ids::PINK_WOOL => DyeColor::PINK,
- Ids::PURPLE_WOOL => DyeColor::PURPLE,
- Ids::RED_WOOL => DyeColor::RED,
- Ids::WHITE_WOOL => DyeColor::WHITE,
- Ids::YELLOW_WOOL => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::WOOL()->setColor($color));
- }
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_wool",
+ fn(DyeColor $color) => Blocks::WOOL()->setColor($color)
+ );
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_carpet",
+ fn(DyeColor $color) => Blocks::CARPET()->setColor($color)
+ );
- foreach([
- Ids::BLACK_CARPET => DyeColor::BLACK,
- Ids::BLUE_CARPET => DyeColor::BLUE,
- Ids::BROWN_CARPET => DyeColor::BROWN,
- Ids::CYAN_CARPET => DyeColor::CYAN,
- Ids::GRAY_CARPET => DyeColor::GRAY,
- Ids::GREEN_CARPET => DyeColor::GREEN,
- Ids::LIGHT_BLUE_CARPET => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_CARPET => DyeColor::LIGHT_GRAY,
- Ids::LIME_CARPET => DyeColor::LIME,
- Ids::MAGENTA_CARPET => DyeColor::MAGENTA,
- Ids::ORANGE_CARPET => DyeColor::ORANGE,
- Ids::PINK_CARPET => DyeColor::PINK,
- Ids::PURPLE_CARPET => DyeColor::PURPLE,
- Ids::RED_CARPET => DyeColor::RED,
- Ids::WHITE_CARPET => DyeColor::WHITE,
- Ids::YELLOW_CARPET => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::CARPET()->setColor($color));
- }
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_shulker_box",
+ fn(DyeColor $color) => Blocks::DYED_SHULKER_BOX()->setColor($color)
+ );
- foreach([
- Ids::BLACK_SHULKER_BOX => DyeColor::BLACK,
- Ids::BLUE_SHULKER_BOX => DyeColor::BLUE,
- Ids::BROWN_SHULKER_BOX => DyeColor::BROWN,
- Ids::CYAN_SHULKER_BOX => DyeColor::CYAN,
- Ids::GRAY_SHULKER_BOX => DyeColor::GRAY,
- Ids::GREEN_SHULKER_BOX => DyeColor::GREEN,
- Ids::LIGHT_BLUE_SHULKER_BOX => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_SHULKER_BOX => DyeColor::LIGHT_GRAY,
- Ids::LIME_SHULKER_BOX => DyeColor::LIME,
- Ids::MAGENTA_SHULKER_BOX => DyeColor::MAGENTA,
- Ids::ORANGE_SHULKER_BOX => DyeColor::ORANGE,
- Ids::PINK_SHULKER_BOX => DyeColor::PINK,
- Ids::PURPLE_SHULKER_BOX => DyeColor::PURPLE,
- Ids::RED_SHULKER_BOX => DyeColor::RED,
- Ids::WHITE_SHULKER_BOX => DyeColor::WHITE,
- Ids::YELLOW_SHULKER_BOX => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::DYED_SHULKER_BOX()->setColor($color));
- }
-
- foreach([
- Ids::BLACK_CONCRETE => DyeColor::BLACK,
- Ids::BLUE_CONCRETE => DyeColor::BLUE,
- Ids::BROWN_CONCRETE => DyeColor::BROWN,
- Ids::CYAN_CONCRETE => DyeColor::CYAN,
- Ids::GRAY_CONCRETE => DyeColor::GRAY,
- Ids::GREEN_CONCRETE => DyeColor::GREEN,
- Ids::LIGHT_BLUE_CONCRETE => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_CONCRETE => DyeColor::LIGHT_GRAY,
- Ids::LIME_CONCRETE => DyeColor::LIME,
- Ids::MAGENTA_CONCRETE => DyeColor::MAGENTA,
- Ids::ORANGE_CONCRETE => DyeColor::ORANGE,
- Ids::PINK_CONCRETE => DyeColor::PINK,
- Ids::PURPLE_CONCRETE => DyeColor::PURPLE,
- Ids::RED_CONCRETE => DyeColor::RED,
- Ids::WHITE_CONCRETE => DyeColor::WHITE,
- Ids::YELLOW_CONCRETE => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::CONCRETE()->setColor($color));
- }
-
- foreach([
- Ids::BLACK_CONCRETE_POWDER => DyeColor::BLACK,
- Ids::BLUE_CONCRETE_POWDER => DyeColor::BLUE,
- Ids::BROWN_CONCRETE_POWDER => DyeColor::BROWN,
- Ids::CYAN_CONCRETE_POWDER => DyeColor::CYAN,
- Ids::GRAY_CONCRETE_POWDER => DyeColor::GRAY,
- Ids::GREEN_CONCRETE_POWDER => DyeColor::GREEN,
- Ids::LIGHT_BLUE_CONCRETE_POWDER => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_CONCRETE_POWDER => DyeColor::LIGHT_GRAY,
- Ids::LIME_CONCRETE_POWDER => DyeColor::LIME,
- Ids::MAGENTA_CONCRETE_POWDER => DyeColor::MAGENTA,
- Ids::ORANGE_CONCRETE_POWDER => DyeColor::ORANGE,
- Ids::PINK_CONCRETE_POWDER => DyeColor::PINK,
- Ids::PURPLE_CONCRETE_POWDER => DyeColor::PURPLE,
- Ids::RED_CONCRETE_POWDER => DyeColor::RED,
- Ids::WHITE_CONCRETE_POWDER => DyeColor::WHITE,
- Ids::YELLOW_CONCRETE_POWDER => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::CONCRETE_POWDER()->setColor($color));
- }
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_concrete",
+ fn(DyeColor $color) => Blocks::CONCRETE()->setColor($color)
+ );
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_concrete_powder",
+ fn(DyeColor $color) => Blocks::CONCRETE_POWDER()->setColor($color)
+ );
foreach([
Ids::BLACK_TERRACOTTA => DyeColor::BLACK,
@@ -399,47 +299,19 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple($id, fn() => Blocks::STAINED_CLAY()->setColor($color));
}
- foreach([
- Ids::BLACK_STAINED_GLASS => DyeColor::BLACK,
- Ids::BLUE_STAINED_GLASS => DyeColor::BLUE,
- Ids::BROWN_STAINED_GLASS => DyeColor::BROWN,
- Ids::CYAN_STAINED_GLASS => DyeColor::CYAN,
- Ids::GRAY_STAINED_GLASS => DyeColor::GRAY,
- Ids::GREEN_STAINED_GLASS => DyeColor::GREEN,
- Ids::LIGHT_BLUE_STAINED_GLASS => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_STAINED_GLASS => DyeColor::LIGHT_GRAY,
- Ids::LIME_STAINED_GLASS => DyeColor::LIME,
- Ids::MAGENTA_STAINED_GLASS => DyeColor::MAGENTA,
- Ids::ORANGE_STAINED_GLASS => DyeColor::ORANGE,
- Ids::PINK_STAINED_GLASS => DyeColor::PINK,
- Ids::PURPLE_STAINED_GLASS => DyeColor::PURPLE,
- Ids::RED_STAINED_GLASS => DyeColor::RED,
- Ids::WHITE_STAINED_GLASS => DyeColor::WHITE,
- Ids::YELLOW_STAINED_GLASS => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::STAINED_GLASS()->setColor($color));
- }
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_stained_glass",
+ fn(DyeColor $color) => Blocks::STAINED_GLASS()->setColor($color)
+ );
- foreach([
- Ids::BLACK_STAINED_GLASS_PANE => DyeColor::BLACK,
- Ids::BLUE_STAINED_GLASS_PANE => DyeColor::BLUE,
- Ids::BROWN_STAINED_GLASS_PANE => DyeColor::BROWN,
- Ids::CYAN_STAINED_GLASS_PANE => DyeColor::CYAN,
- Ids::GRAY_STAINED_GLASS_PANE => DyeColor::GRAY,
- Ids::GREEN_STAINED_GLASS_PANE => DyeColor::GREEN,
- Ids::LIGHT_BLUE_STAINED_GLASS_PANE => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_STAINED_GLASS_PANE => DyeColor::LIGHT_GRAY,
- Ids::LIME_STAINED_GLASS_PANE => DyeColor::LIME,
- Ids::MAGENTA_STAINED_GLASS_PANE => DyeColor::MAGENTA,
- Ids::ORANGE_STAINED_GLASS_PANE => DyeColor::ORANGE,
- Ids::PINK_STAINED_GLASS_PANE => DyeColor::PINK,
- Ids::PURPLE_STAINED_GLASS_PANE => DyeColor::PURPLE,
- Ids::RED_STAINED_GLASS_PANE => DyeColor::RED,
- Ids::WHITE_STAINED_GLASS_PANE => DyeColor::WHITE,
- Ids::YELLOW_STAINED_GLASS_PANE => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::STAINED_GLASS_PANE()->setColor($color));
- }
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_stained_glass_pane",
+ fn(DyeColor $color) => Blocks::STAINED_GLASS_PANE()->setColor($color)
+ );
}
private function registerFlatCoralDeserializers() : void{
diff --git a/src/data/bedrock/block/convert/StringEnumMap.php b/src/data/bedrock/block/convert/StringEnumMap.php
new file mode 100644
index 000000000..6171c0e71
--- /dev/null
+++ b/src/data/bedrock/block/convert/StringEnumMap.php
@@ -0,0 +1,78 @@
+
+ */
+ private array $enumToValue = [];
+
+ /**
+ * @var \UnitEnum[]
+ * @phpstan-var array
+ */
+ private array $valueToEnum = [];
+
+ /**
+ * @phpstan-param class-string $class
+ * @phpstan-param \Closure(TEnum) : string $mapper
+ */
+ public function __construct(
+ private string $class,
+ \Closure $mapper
+ ){
+ foreach($class::cases() as $case){
+ $string = $mapper($case);
+ $this->valueToEnum[$string] = $case;
+ $this->enumToValue[spl_object_id($case)] = $string;
+ }
+ }
+
+ /**
+ * @phpstan-param TEnum $enum
+ */
+ public function enumToValue(\UnitEnum $enum) : string{
+ return $this->enumToValue[spl_object_id($enum)];
+ }
+
+ public function valueToEnum(string $string) : ?\UnitEnum{
+ return $this->valueToEnum[$string] ?? throw new BlockStateDeserializeException("No $this->class enum mapping for \"$string\"");
+ }
+
+ /**
+ * @return \UnitEnum[]
+ * @phpstan-return array
+ */
+ public function getValueToEnum() : array{
+ return $this->valueToEnum;
+ }
+}
diff --git a/src/data/bedrock/block/convert/ValueMappings.php b/src/data/bedrock/block/convert/ValueMappings.php
new file mode 100644
index 000000000..df57d6f53
--- /dev/null
+++ b/src/data/bedrock/block/convert/ValueMappings.php
@@ -0,0 +1,83 @@
+, StringEnumMap>
+ */
+ private array $enumMappings = [];
+
+ public function __construct(){
+ $this->addEnum(DyeColor::class, fn(DyeColor $case) => match ($case) {
+ DyeColor::BLACK => "black",
+ DyeColor::BLUE => "blue",
+ DyeColor::BROWN => "brown",
+ DyeColor::CYAN => "cyan",
+ DyeColor::GRAY => "gray",
+ DyeColor::GREEN => "green",
+ DyeColor::LIGHT_BLUE => "light_blue",
+ DyeColor::LIGHT_GRAY => "light_gray",
+ DyeColor::LIME => "lime",
+ DyeColor::MAGENTA => "magenta",
+ DyeColor::ORANGE => "orange",
+ DyeColor::PINK => "pink",
+ DyeColor::PURPLE => "purple",
+ DyeColor::RED => "red",
+ DyeColor::WHITE => "white",
+ DyeColor::YELLOW => "yellow"
+ });
+ }
+
+ /**
+ * @phpstan-template TEnum of \UnitEnum
+ * @phpstan-param class-string $class
+ * @phpstan-param \Closure(TEnum): string $mapper
+ */
+ private function addEnum(string $class, \Closure $mapper) : void{
+ $this->enumMappings[$class] = new StringEnumMap($class, $mapper);
+ }
+
+ /**
+ * @phpstan-template TEnum of \UnitEnum
+ * @phpstan-param class-string $class
+ * @phpstan-return StringEnumMap
+ */
+ public function getEnumMap(string $class) : StringEnumMap{
+ if(!isset($this->enumMappings[$class])){
+ throw new \InvalidArgumentException("No enum mapping found for class: $class");
+ }
+ /**
+ * @phpstan-var StringEnumMap $map
+ */
+ $map = $this->enumMappings[$class];
+ return $map;
+ }
+}
From c0fad353a2667046a073fb14f8a5a65a9f65ed7b Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Fri, 15 Aug 2025 22:09:54 +0100
Subject: [PATCH 096/140] missed one
sadly glazed_terracotta had to be special
---
.../BlockStateToObjectDeserializer.php | 26 +++++--------------
1 file changed, 6 insertions(+), 20 deletions(-)
diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
index cbeadc819..0f6d4930b 100644
--- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
+++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
@@ -278,26 +278,12 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
fn(DyeColor $color) => Blocks::CONCRETE_POWDER()->setColor($color)
);
- foreach([
- Ids::BLACK_TERRACOTTA => DyeColor::BLACK,
- Ids::BLUE_TERRACOTTA => DyeColor::BLUE,
- Ids::BROWN_TERRACOTTA => DyeColor::BROWN,
- Ids::CYAN_TERRACOTTA => DyeColor::CYAN,
- Ids::GRAY_TERRACOTTA => DyeColor::GRAY,
- Ids::GREEN_TERRACOTTA => DyeColor::GREEN,
- Ids::LIGHT_BLUE_TERRACOTTA => DyeColor::LIGHT_BLUE,
- Ids::LIGHT_GRAY_TERRACOTTA => DyeColor::LIGHT_GRAY,
- Ids::LIME_TERRACOTTA => DyeColor::LIME,
- Ids::MAGENTA_TERRACOTTA => DyeColor::MAGENTA,
- Ids::ORANGE_TERRACOTTA => DyeColor::ORANGE,
- Ids::PINK_TERRACOTTA => DyeColor::PINK,
- Ids::PURPLE_TERRACOTTA => DyeColor::PURPLE,
- Ids::RED_TERRACOTTA => DyeColor::RED,
- Ids::WHITE_TERRACOTTA => DyeColor::WHITE,
- Ids::YELLOW_TERRACOTTA => DyeColor::YELLOW,
- ] as $id => $color){
- $this->mapSimple($id, fn() => Blocks::STAINED_CLAY()->setColor($color));
- }
+ $this->mapFlattenedEnum(
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ "minecraft:",
+ "_terracotta",
+ fn(DyeColor $color) => Blocks::STAINED_CLAY()->setColor($color)
+ );
$this->mapFlattenedEnum(
ValueMappings::getInstance()->getEnumMap(DyeColor::class),
From 431790a3195ffe13859a040fa5e2b6a8dd1a5974 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Fri, 15 Aug 2025 22:24:27 +0100
Subject: [PATCH 097/140] Additional specialisation for colored blocks this
reduces boilerplate even further
---
.../convert/BlockObjectToStateSerializer.php | 130 +++++-------------
.../convert/BlockStateDeserializerHelper.php | 8 +-
.../BlockStateToObjectDeserializer.php | 106 +++++---------
3 files changed, 76 insertions(+), 168 deletions(-)
diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
index 6b545bd01..1a3467fe9 100644
--- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
+++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
@@ -45,7 +45,6 @@ use pocketmine\block\CakeWithCandle;
use pocketmine\block\CakeWithDyedCandle;
use pocketmine\block\Campfire;
use pocketmine\block\Candle;
-use pocketmine\block\Carpet;
use pocketmine\block\Carrot;
use pocketmine\block\CarvedPumpkin;
use pocketmine\block\CaveVines;
@@ -55,8 +54,6 @@ use pocketmine\block\Chest;
use pocketmine\block\ChiseledBookshelf;
use pocketmine\block\ChorusFlower;
use pocketmine\block\CocoaBlock;
-use pocketmine\block\Concrete;
-use pocketmine\block\ConcretePowder;
use pocketmine\block\Copper;
use pocketmine\block\CopperBulb;
use pocketmine\block\CopperDoor;
@@ -73,8 +70,6 @@ use pocketmine\block\Door;
use pocketmine\block\DoublePitcherCrop;
use pocketmine\block\DoublePlant;
use pocketmine\block\DoubleTallGrass;
-use pocketmine\block\DyedCandle;
-use pocketmine\block\DyedShulkerBox;
use pocketmine\block\EnderChest;
use pocketmine\block\EndPortalFrame;
use pocketmine\block\EndRod;
@@ -133,11 +128,6 @@ use pocketmine\block\SmallDripleaf;
use pocketmine\block\SnowLayer;
use pocketmine\block\SoulCampfire;
use pocketmine\block\Sponge;
-use pocketmine\block\StainedGlass;
-use pocketmine\block\StainedGlassPane;
-use pocketmine\block\StainedHardenedClay;
-use pocketmine\block\StainedHardenedGlass;
-use pocketmine\block\StainedHardenedGlassPane;
use pocketmine\block\Stair;
use pocketmine\block\StoneButton;
use pocketmine\block\Stonecutter;
@@ -153,6 +143,7 @@ use pocketmine\block\Tripwire;
use pocketmine\block\TripwireHook;
use pocketmine\block\UnderwaterTorch;
use pocketmine\block\utils\BrewingStandSlot;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\DirtType;
use pocketmine\block\utils\DripleafState;
@@ -176,7 +167,6 @@ use pocketmine\block\WoodenDoor;
use pocketmine\block\WoodenPressurePlate;
use pocketmine\block\WoodenStairs;
use pocketmine\block\WoodenTrapdoor;
-use pocketmine\block\Wool;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
@@ -319,43 +309,57 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
}
+ /**
+ * @phpstan-template TBlock of Block&Colored
+ * @phpstan-param TBlock $block
+ * @phpstan-param ?\Closure(TBlock, Writer) : Writer $extra
+ */
+ public function mapColored(
+ Block $block,
+ string $prefix,
+ string $suffix,
+ ?\Closure $extra = null
+ ) : void{
+ $this->mapFlattenedEnum(
+ $block,
+ ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ $prefix,
+ $suffix,
+ fn(Colored $block) => $block->getColor(),
+ $extra
+ );
+ }
+
private function registerCandleSerializers() : void{
$this->map(Blocks::CANDLE(), fn(Candle $block) => Helper::encodeCandle($block, new Writer(Ids::CANDLE)));
- $this->mapFlattenedEnum(
+ $this->mapColored(
Blocks::DYED_CANDLE(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
"minecraft:",
"_candle",
- fn(DyedCandle $block) => $block->getColor(),
Helper::encodeCandle(...)
);
$this->map(Blocks::CAKE_WITH_CANDLE(), fn(CakeWithCandle $block) => Writer::create(Ids::CANDLE_CAKE)
->writeBool(StateNames::LIT, $block->isLit()));
- $this->mapFlattenedEnum(
+ $this->mapColored(
Blocks::CAKE_WITH_DYED_CANDLE(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
"minecraft:",
"_candle_cake",
- fn(CakeWithDyedCandle $block) => $block->getColor(),
fn(CakeWithDyedCandle $block, Writer $writer) => $writer->writeBool(StateNames::LIT, $block->isLit())
);
}
public function registerFlatColorBlockSerializers() : void{
- $this->mapFlattenedEnum(
- Blocks::STAINED_HARDENED_GLASS(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:hard_",
- "_stained_glass",
- fn(StainedHardenedGlass $block) => $block->getColor()
- );
- $this->mapFlattenedEnum(
- Blocks::STAINED_HARDENED_GLASS_PANE(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:hard_",
- "_stained_glass_pane",
- fn(StainedHardenedGlassPane $block) => $block->getColor(),
- );
+ $this->mapColored(Blocks::STAINED_HARDENED_GLASS(), "minecraft:hard_", "_stained_glass");
+ $this->mapColored(Blocks::STAINED_HARDENED_GLASS_PANE(), "minecraft:hard_", "_stained_glass_pane");
+
+ $this->mapColored(Blocks::CARPET(), "minecraft:", "_carpet");
+ $this->mapColored(Blocks::CONCRETE(), "minecraft:", "_concrete");
+ $this->mapColored(Blocks::CONCRETE_POWDER(), "minecraft:", "_concrete_powder");
+ $this->mapColored(Blocks::DYED_SHULKER_BOX(), "minecraft:", "_shulker_box");
+ $this->mapColored(Blocks::STAINED_CLAY(), "minecraft:", "_terracotta");
+ $this->mapColored(Blocks::STAINED_GLASS(), "minecraft:", "_stained_glass");
+ $this->mapColored(Blocks::STAINED_GLASS_PANE(), "minecraft:", "_stained_glass_pane");
+ $this->mapColored(Blocks::WOOL(), "minecraft:", "_wool");
$this->map(Blocks::GLAZED_TERRACOTTA(), function(GlazedTerracotta $block) : Writer{
return Writer::create(match($block->getColor()){
@@ -366,7 +370,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::GRAY => Ids::GRAY_GLAZED_TERRACOTTA,
DyeColor::GREEN => Ids::GREEN_GLAZED_TERRACOTTA,
DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_GLAZED_TERRACOTTA,
- DyeColor::LIGHT_GRAY => Ids::SILVER_GLAZED_TERRACOTTA,
+ DyeColor::LIGHT_GRAY => Ids::SILVER_GLAZED_TERRACOTTA, //minecraft sadness
DyeColor::LIME => Ids::LIME_GLAZED_TERRACOTTA,
DyeColor::MAGENTA => Ids::MAGENTA_GLAZED_TERRACOTTA,
DyeColor::ORANGE => Ids::ORANGE_GLAZED_TERRACOTTA,
@@ -378,68 +382,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
})
->writeHorizontalFacing($block->getFacing());
});
-
- $this->mapFlattenedEnum(
- Blocks::WOOL(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_wool",
- fn(Wool $block) => $block->getColor()
- );
-
- $this->mapFlattenedEnum(
- Blocks::CARPET(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_carpet",
- fn(Carpet $block) => $block->getColor()
- );
-
- $this->mapFlattenedEnum(
- Blocks::DYED_SHULKER_BOX(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_shulker_box",
- fn(DyedShulkerBox $block) => $block->getColor()
- );
-
- $this->mapFlattenedEnum(
- Blocks::CONCRETE(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_concrete",
- fn(Concrete $block) => $block->getColor()
- );
- $this->mapFlattenedEnum(
- Blocks::CONCRETE_POWDER(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_concrete_powder",
- fn(ConcretePowder $block) => $block->getColor()
- );
-
- $this->mapFlattenedEnum(
- Blocks::STAINED_CLAY(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_terracotta",
- fn(StainedHardenedClay $block) => $block->getColor()
- );
-
- $this->mapFlattenedEnum(
- Blocks::STAINED_GLASS(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_stained_glass",
- fn(StainedGlass $block) => $block->getColor()
- );
- $this->mapFlattenedEnum(
- Blocks::STAINED_GLASS_PANE(),
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_stained_glass_pane",
- fn(StainedGlassPane $block) => $block->getColor()
- );
}
private function registerFlatCoralSerializers() : void{
diff --git a/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php b/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php
index 5cf3f7f76..3cf55429e 100644
--- a/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php
+++ b/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php
@@ -70,7 +70,13 @@ final class BlockStateDeserializerHelper{
->setPressed($in->readBool(BlockStateNames::BUTTON_PRESSED_BIT));
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @phpstan-template TCandle of Candle
+ * @phpstan-param TCandle $block
+ * @phpstan-return TCandle
+ *
+ * @throws BlockStateDeserializeException
+ */
public static function decodeCandle(Candle $block, BlockStateReader $in) : Candle{
return $block
->setCount($in->readBoundedInt(StateNames::CANDLES, 0, 3) + 1)
diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
index 0f6d4930b..b21642cb4 100644
--- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
+++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
@@ -40,6 +40,7 @@ use pocketmine\block\Stair;
use pocketmine\block\SweetBerryBush;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\ChiseledBookshelfSlot;
+use pocketmine\block\utils\Colored;
use pocketmine\block\utils\CopperMaterial;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\CoralType;
@@ -187,39 +188,52 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
}
}
- private function registerCandleDeserializers() : void{
- $this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in));
+ /**
+ * @phpstan-template TBlock of Block&Colored
+ * @phpstan-param \Closure() : TBlock $getBlock
+ * @phpstan-param ?\Closure(TBlock, Reader) : TBlock $extra
+ */
+ public function mapColored(string $prefix, string $suffix, \Closure $getBlock, ?\Closure $extra = null) : void{
$this->mapFlattenedEnum(
ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+ $prefix,
+ $suffix,
+ fn(DyeColor $color) => $getBlock()->setColor($color),
+ $extra
+ );
+ }
+
+ private function registerCandleDeserializers() : void{
+ $this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in));
+ $this->mapColored(
"minecraft:",
"_candle",
- fn(DyeColor $color) => Blocks::DYED_CANDLE()->setColor($color),
+ fn() => Blocks::DYED_CANDLE(),
Helper::decodeCandle(...)
);
$this->map(Ids::CANDLE_CAKE, fn(Reader $in) => Blocks::CAKE_WITH_CANDLE()->setLit($in->readBool(StateNames::LIT)));
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
+
+ $this->mapColored(
"minecraft:",
"_candle_cake",
- fn(DyeColor $color) => Blocks::CAKE_WITH_DYED_CANDLE()->setColor($color),
+ fn() => Blocks::CAKE_WITH_DYED_CANDLE(),
fn(CakeWithDyedCandle $block, Reader $in) => $block->setLit($in->readBool(StateNames::LIT))
);
}
private function registerFlatColorBlockDeserializers() : void{
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:hard_",
- "_stained_glass",
- fn(DyeColor $color) => Blocks::STAINED_HARDENED_GLASS()->setColor($color)
- );
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:hard_",
- "_stained_glass_pane",
- fn(DyeColor $color) => Blocks::STAINED_HARDENED_GLASS_PANE()->setColor($color)
- );
+ $this->mapColored("minecraft:hard_", "_stained_glass", fn() => Blocks::STAINED_HARDENED_GLASS());
+ $this->mapColored("minecraft:hard_", "_stained_glass_pane", fn() => Blocks::STAINED_HARDENED_GLASS_PANE());
+
+ $this->mapColored("minecraft:", "_carpet", fn() => Blocks::CARPET());
+ $this->mapColored("minecraft:", "_concrete", fn() => Blocks::CONCRETE());
+ $this->mapColored("minecraft:", "_concrete_powder", fn() => Blocks::CONCRETE_POWDER());
+ $this->mapColored("minecraft:", "_shulker_box", fn() => Blocks::DYED_SHULKER_BOX());
+ $this->mapColored("minecraft:", "_stained_glass", fn() => Blocks::STAINED_GLASS());
+ $this->mapColored("minecraft:", "_stained_glass_pane", fn() => Blocks::STAINED_GLASS_PANE());
+ $this->mapColored("minecraft:", "_terracotta", fn() => Blocks::STAINED_CLAY());
+ $this->mapColored("minecraft:", "_wool", fn() => Blocks::WOOL());
foreach([
Ids::BLACK_GLAZED_TERRACOTTA => DyeColor::BLACK,
@@ -229,7 +243,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
Ids::GRAY_GLAZED_TERRACOTTA => DyeColor::GRAY,
Ids::GREEN_GLAZED_TERRACOTTA => DyeColor::GREEN,
Ids::LIGHT_BLUE_GLAZED_TERRACOTTA => DyeColor::LIGHT_BLUE,
- Ids::SILVER_GLAZED_TERRACOTTA => DyeColor::LIGHT_GRAY,
+ Ids::SILVER_GLAZED_TERRACOTTA => DyeColor::LIGHT_GRAY, //minecraft sadness
Ids::LIME_GLAZED_TERRACOTTA => DyeColor::LIME,
Ids::MAGENTA_GLAZED_TERRACOTTA => DyeColor::MAGENTA,
Ids::ORANGE_GLAZED_TERRACOTTA => DyeColor::ORANGE,
@@ -244,60 +258,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
->setFacing($in->readHorizontalFacing())
);
}
-
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_wool",
- fn(DyeColor $color) => Blocks::WOOL()->setColor($color)
- );
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_carpet",
- fn(DyeColor $color) => Blocks::CARPET()->setColor($color)
- );
-
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_shulker_box",
- fn(DyeColor $color) => Blocks::DYED_SHULKER_BOX()->setColor($color)
- );
-
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_concrete",
- fn(DyeColor $color) => Blocks::CONCRETE()->setColor($color)
- );
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_concrete_powder",
- fn(DyeColor $color) => Blocks::CONCRETE_POWDER()->setColor($color)
- );
-
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_terracotta",
- fn(DyeColor $color) => Blocks::STAINED_CLAY()->setColor($color)
- );
-
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_stained_glass",
- fn(DyeColor $color) => Blocks::STAINED_GLASS()->setColor($color)
- );
-
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- "minecraft:",
- "_stained_glass_pane",
- fn(DyeColor $color) => Blocks::STAINED_GLASS_PANE()->setColor($color)
- );
}
private function registerFlatCoralDeserializers() : void{
From eea4f40138fe3af6a5061ebf5c4ef5a25f85faf0 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Sun, 17 Aug 2025 15:24:40 +0100
Subject: [PATCH 098/140] BlockStateToObjectDeserializer: Remove duplicated
CHISELED_COPPER registration allowing overriding of serializers by the same
method as first registration was a mistake...
---
.../bedrock/block/convert/BlockStateToObjectDeserializer.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
index c55fde77a..12c4bc43c 100644
--- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
+++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
@@ -1355,7 +1355,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
return $block;
});
- $this->map(Ids::CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::NONE));
$this->map(Ids::CHISELED_QUARTZ_BLOCK, function(Reader $in) : Block{
return Blocks::CHISELED_QUARTZ()
->setAxis($in->readPillarAxis());
From 2bb78f2a943c031380a733550409a6524cc918a9 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Wed, 20 Aug 2025 00:58:57 +0100
Subject: [PATCH 099/140] Fixed Furnace not implementing HorizontalFacing looks
like this was missed in #6639 I checked all other uses of
HorizontalFacingTrait and FacesOppositePlacingPlayerTrait and this seems to
be the only one.
---
src/block/Furnace.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/block/Furnace.php b/src/block/Furnace.php
index 54480e62c..43ab463a6 100644
--- a/src/block/Furnace.php
+++ b/src/block/Furnace.php
@@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Furnace as TileFurnace;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
+use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\crafting\FurnaceType;
@@ -34,7 +35,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function mt_rand;
-class Furnace extends Opaque implements Lightable{
+class Furnace extends Opaque implements Lightable, HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
use LightableTrait;
From e824266457c3207bb2565256e2f9a58652d98a51 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Fri, 22 Aug 2025 18:27:06 +0100
Subject: [PATCH 100/140] ChiseledBookshelf: add setSlots()
---
src/block/ChiseledBookshelf.php | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/block/ChiseledBookshelf.php b/src/block/ChiseledBookshelf.php
index be49c7a91..cbe22a94b 100644
--- a/src/block/ChiseledBookshelf.php
+++ b/src/block/ChiseledBookshelf.php
@@ -114,6 +114,18 @@ class ChiseledBookshelf extends Opaque implements HorizontalFacing{
return $this->slots;
}
+ /**
+ * @param ChiseledBookshelfSlot[] $slots
+ * @return $this
+ */
+ public function setSlots(array $slots) : self{
+ $this->slots = [];
+ foreach($slots as $slot){
+ $this->setSlot($slot, true);
+ }
+ return $this;
+ }
+
/**
* Returns the last slot interacted by a player or null if no slot has been interacted with yet.
*/
From 47140cb8d7a956d767423de56410c46526c10468 Mon Sep 17 00:00:00 2001
From: "Dylan K. Taylor"
Date: Fri, 22 Aug 2025 18:27:32 +0100
Subject: [PATCH 101/140] RedstoneLamp: implement Lightable, shimmed to powered
---
src/block/RedstoneLamp.php | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/block/RedstoneLamp.php b/src/block/RedstoneLamp.php
index 33a97801d..530fa2410 100644
--- a/src/block/RedstoneLamp.php
+++ b/src/block/RedstoneLamp.php
@@ -23,11 +23,12 @@ declare(strict_types=1);
namespace pocketmine\block;
+use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
-class RedstoneLamp extends Opaque implements PoweredByRedstone{
+class RedstoneLamp extends Opaque implements PoweredByRedstone, Lightable{
use PoweredByRedstoneTrait;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
@@ -37,4 +38,14 @@ class RedstoneLamp extends Opaque implements PoweredByRedstone{
public function getLightLevel() : int{
return $this->powered ? 15 : 0;
}
+
+ public function isLit() : bool{
+ return $this->powered;
+ }
+
+ /** @return $this */
+ public function setLit(bool $lit = true) : self{
+ $this->powered = $lit;
+ return $this;
+ }
}
From 7c521b456e181fed271b4e050731ed4ebc8faf1f Mon Sep 17 00:00:00 2001
From: "Dylan T."
Date: Sun, 24 Aug 2025 14:12:18 +0100
Subject: [PATCH 102/140] Unify block serializers (#6769)
This has several advantages:
Easier to implement new blocks (one less file to modify)
Easier to adjust serialization of existing blocks
Guaranteed consistency between serializers and deserializers
Potentially, exposes more metadata for programmatic analysis, instead of having everything baked inside opaque Closures
There are some exceptions which still use the old approach: big dripleaf, cauldrons, mushroom stems, and pitcher crops. These all have multiple PM block types for a single ID, with relatively complex logic to select which to use. These weren't worth the effort to unify due to their small number. I may revisit this in the future, but I already spent a lot of brainpower on it.
---
src/data/bedrock/MushroomBlockTypeIdMap.php | 20 +-
.../bedrock/block/BlockLegacyMetadata.php | 2 +
.../convert/BlockObjectToStateSerializer.php | 1619 +----------------
.../BlockSerializerDeserializerRegistrar.php | 237 +++
.../convert/BlockStateDeserializerHelper.php | 52 +-
.../block/convert/BlockStateReader.php | 228 ++-
.../convert/BlockStateSerializerHelper.php | 33 +
.../BlockStateToObjectDeserializer.php | 1593 +---------------
.../block/convert/BlockStateWriter.php | 228 +--
.../block/convert/FlattenedIdModel.php | 107 ++
src/data/bedrock/block/convert/Model.php | 82 +
.../bedrock/block/convert/StringEnumMap.php | 78 -
.../bedrock/block/convert/ValueMappings.php | 83 -
.../block/convert/VanillaBlockMappings.php | 1561 ++++++++++++++++
.../property/BoolFromStringProperty.php | 78 +
.../block/convert/property/BoolProperty.php | 71 +
.../convert/property/CommonProperties.php | 429 +++++
.../block/convert/property/DummyProperty.php | 61 +
.../convert/property/EnumFromRawStateMap.php | 109 ++
.../property/FlattenedCaveVinesVariant.php | 35 +
.../convert/property/IntFromRawStateMap.php | 104 ++
.../block/convert/property/IntProperty.php | 70 +
.../property/OptionSetFromIntProperty.php | 93 +
.../block/convert/property/Property.php | 44 +
.../block/convert/property/StateMap.php | 53 +
.../block/convert/property/StringProperty.php | 50 +
.../convert/property/ValueFromIntProperty.php | 75 +
.../property/ValueFromStringProperty.php | 81 +
.../block/convert/property/ValueMappings.php | 305 ++++
.../property/WallConnectionTypeShim.php | 66 +
.../format/io/GlobalBlockStateHandlers.php | 22 +-
tests/phpstan/configs/actual-problems.neon | 6 +
.../BlockSerializerDeserializerTest.php | 6 +-
33 files changed, 4072 insertions(+), 3609 deletions(-)
create mode 100644 src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php
create mode 100644 src/data/bedrock/block/convert/FlattenedIdModel.php
create mode 100644 src/data/bedrock/block/convert/Model.php
delete mode 100644 src/data/bedrock/block/convert/StringEnumMap.php
delete mode 100644 src/data/bedrock/block/convert/ValueMappings.php
create mode 100644 src/data/bedrock/block/convert/VanillaBlockMappings.php
create mode 100644 src/data/bedrock/block/convert/property/BoolFromStringProperty.php
create mode 100644 src/data/bedrock/block/convert/property/BoolProperty.php
create mode 100644 src/data/bedrock/block/convert/property/CommonProperties.php
create mode 100644 src/data/bedrock/block/convert/property/DummyProperty.php
create mode 100644 src/data/bedrock/block/convert/property/EnumFromRawStateMap.php
create mode 100644 src/data/bedrock/block/convert/property/FlattenedCaveVinesVariant.php
create mode 100644 src/data/bedrock/block/convert/property/IntFromRawStateMap.php
create mode 100644 src/data/bedrock/block/convert/property/IntProperty.php
create mode 100644 src/data/bedrock/block/convert/property/OptionSetFromIntProperty.php
create mode 100644 src/data/bedrock/block/convert/property/Property.php
create mode 100644 src/data/bedrock/block/convert/property/StateMap.php
create mode 100644 src/data/bedrock/block/convert/property/StringProperty.php
create mode 100644 src/data/bedrock/block/convert/property/ValueFromIntProperty.php
create mode 100644 src/data/bedrock/block/convert/property/ValueFromStringProperty.php
create mode 100644 src/data/bedrock/block/convert/property/ValueMappings.php
create mode 100644 src/data/bedrock/block/convert/property/WallConnectionTypeShim.php
diff --git a/src/data/bedrock/MushroomBlockTypeIdMap.php b/src/data/bedrock/MushroomBlockTypeIdMap.php
index a25336d89..6357d3e14 100644
--- a/src/data/bedrock/MushroomBlockTypeIdMap.php
+++ b/src/data/bedrock/MushroomBlockTypeIdMap.php
@@ -24,29 +24,21 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock;
use pocketmine\block\utils\MushroomBlockType;
-use pocketmine\data\bedrock\block\BlockLegacyMetadata as LegacyMeta;
+use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\utils\SingletonTrait;
+/**
+ * @deprecated
+ */
final class MushroomBlockTypeIdMap{
use SingletonTrait;
/** @phpstan-use IntSaveIdMapTrait */
use IntSaveIdMapTrait;
public function __construct(){
+ $newMapping = ValueMappings::getInstance()->mushroomBlockType;
foreach(MushroomBlockType::cases() as $case){
- $this->register(match($case){
- MushroomBlockType::PORES => LegacyMeta::MUSHROOM_BLOCK_ALL_PORES,
- MushroomBlockType::CAP_NORTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER,
- MushroomBlockType::CAP_NORTH => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE,
- MushroomBlockType::CAP_NORTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER,
- MushroomBlockType::CAP_WEST => LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE,
- MushroomBlockType::CAP_MIDDLE => LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY,
- MushroomBlockType::CAP_EAST => LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE,
- MushroomBlockType::CAP_SOUTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER,
- MushroomBlockType::CAP_SOUTH => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE,
- MushroomBlockType::CAP_SOUTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER,
- MushroomBlockType::ALL_CAP => LegacyMeta::MUSHROOM_BLOCK_ALL_CAP,
- }, $case);
+ $this->register($newMapping->valueToRaw($case), $case);
}
}
}
diff --git a/src/data/bedrock/block/BlockLegacyMetadata.php b/src/data/bedrock/block/BlockLegacyMetadata.php
index e094bd3bd..d324a7ccc 100644
--- a/src/data/bedrock/block/BlockLegacyMetadata.php
+++ b/src/data/bedrock/block/BlockLegacyMetadata.php
@@ -38,6 +38,8 @@ final class BlockLegacyMetadata{
public const CORAL_VARIANT_FIRE = 3;
public const CORAL_VARIANT_HORN = 4;
+ public const LIQUID_FALLING_FLAG = 0x08;
+
public const MULTI_FACE_DIRECTION_FLAG_DOWN = 0x01;
public const MULTI_FACE_DIRECTION_FLAG_UP = 0x02;
public const MULTI_FACE_DIRECTION_FLAG_SOUTH = 0x04;
diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
index 1a3467fe9..90f6af97a 100644
--- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
+++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php
@@ -23,161 +23,17 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
-use pocketmine\block\ActivatorRail;
-use pocketmine\block\AmethystCluster;
-use pocketmine\block\Anvil;
-use pocketmine\block\Bamboo;
-use pocketmine\block\BambooSapling;
-use pocketmine\block\Barrel;
-use pocketmine\block\Bed;
-use pocketmine\block\Beetroot;
-use pocketmine\block\Bell;
-use pocketmine\block\BigDripleafHead;
-use pocketmine\block\BigDripleafStem;
use pocketmine\block\Block;
-use pocketmine\block\BoneBlock;
-use pocketmine\block\BrewingStand;
-use pocketmine\block\BrownMushroomBlock;
-use pocketmine\block\Button;
-use pocketmine\block\Cactus;
-use pocketmine\block\Cake;
-use pocketmine\block\CakeWithCandle;
-use pocketmine\block\CakeWithDyedCandle;
-use pocketmine\block\Campfire;
-use pocketmine\block\Candle;
-use pocketmine\block\Carrot;
-use pocketmine\block\CarvedPumpkin;
-use pocketmine\block\CaveVines;
-use pocketmine\block\Chain;
-use pocketmine\block\ChemistryTable;
-use pocketmine\block\Chest;
-use pocketmine\block\ChiseledBookshelf;
-use pocketmine\block\ChorusFlower;
-use pocketmine\block\CocoaBlock;
-use pocketmine\block\Copper;
-use pocketmine\block\CopperBulb;
-use pocketmine\block\CopperDoor;
-use pocketmine\block\CopperGrate;
-use pocketmine\block\CopperSlab;
-use pocketmine\block\CopperStairs;
-use pocketmine\block\CopperTrapdoor;
-use pocketmine\block\Coral;
-use pocketmine\block\CoralBlock;
-use pocketmine\block\DaylightSensor;
-use pocketmine\block\DetectorRail;
-use pocketmine\block\Dirt;
-use pocketmine\block\Door;
-use pocketmine\block\DoublePitcherCrop;
-use pocketmine\block\DoublePlant;
-use pocketmine\block\DoubleTallGrass;
-use pocketmine\block\EnderChest;
-use pocketmine\block\EndPortalFrame;
-use pocketmine\block\EndRod;
-use pocketmine\block\Farmland;
-use pocketmine\block\FenceGate;
-use pocketmine\block\FillableCauldron;
-use pocketmine\block\Fire;
-use pocketmine\block\FloorBanner;
-use pocketmine\block\FloorCoralFan;
-use pocketmine\block\FloorSign;
-use pocketmine\block\Froglight;
-use pocketmine\block\FrostedIce;
-use pocketmine\block\Furnace;
-use pocketmine\block\GlazedTerracotta;
-use pocketmine\block\GlowLichen;
-use pocketmine\block\HayBale;
-use pocketmine\block\Hopper;
-use pocketmine\block\ItemFrame;
-use pocketmine\block\Ladder;
-use pocketmine\block\Lantern;
-use pocketmine\block\Lava;
-use pocketmine\block\Leaves;
-use pocketmine\block\Lectern;
-use pocketmine\block\Lever;
-use pocketmine\block\Light;
-use pocketmine\block\LightningRod;
-use pocketmine\block\LitPumpkin;
-use pocketmine\block\Loom;
-use pocketmine\block\MelonStem;
-use pocketmine\block\MobHead;
-use pocketmine\block\NetherPortal;
-use pocketmine\block\NetherVines;
-use pocketmine\block\NetherWartPlant;
-use pocketmine\block\PinkPetals;
-use pocketmine\block\PitcherCrop;
-use pocketmine\block\Potato;
-use pocketmine\block\PoweredRail;
-use pocketmine\block\PumpkinStem;
-use pocketmine\block\Rail;
-use pocketmine\block\RedMushroomBlock;
-use pocketmine\block\RedstoneComparator;
-use pocketmine\block\RedstoneLamp;
-use pocketmine\block\RedstoneOre;
-use pocketmine\block\RedstoneRepeater;
-use pocketmine\block\RedstoneTorch;
-use pocketmine\block\RedstoneWire;
-use pocketmine\block\ResinClump;
-use pocketmine\block\RespawnAnchor;
use pocketmine\block\RuntimeBlockStateRegistry;
-use pocketmine\block\Sapling;
-use pocketmine\block\SeaPickle;
-use pocketmine\block\SimplePillar;
-use pocketmine\block\SimplePressurePlate;
use pocketmine\block\Slab;
-use pocketmine\block\SmallDripleaf;
-use pocketmine\block\SnowLayer;
-use pocketmine\block\SoulCampfire;
-use pocketmine\block\Sponge;
use pocketmine\block\Stair;
-use pocketmine\block\StoneButton;
-use pocketmine\block\Stonecutter;
-use pocketmine\block\StonePressurePlate;
-use pocketmine\block\Sugarcane;
-use pocketmine\block\SweetBerryBush;
-use pocketmine\block\TNT;
-use pocketmine\block\Torch;
-use pocketmine\block\TorchflowerCrop;
-use pocketmine\block\Trapdoor;
-use pocketmine\block\TrappedChest;
-use pocketmine\block\Tripwire;
-use pocketmine\block\TripwireHook;
-use pocketmine\block\UnderwaterTorch;
-use pocketmine\block\utils\BrewingStandSlot;
-use pocketmine\block\utils\Colored;
-use pocketmine\block\utils\CoralType;
-use pocketmine\block\utils\DirtType;
-use pocketmine\block\utils\DripleafState;
-use pocketmine\block\utils\DyeColor;
-use pocketmine\block\utils\FroglightType;
-use pocketmine\block\utils\LeverFacing;
-use pocketmine\block\utils\MobHeadType;
-use pocketmine\block\VanillaBlocks as Blocks;
-use pocketmine\block\Vine;
-use pocketmine\block\Wall;
-use pocketmine\block\WallBanner;
-use pocketmine\block\WallCoralFan;
-use pocketmine\block\WallSign;
-use pocketmine\block\Water;
-use pocketmine\block\WeightedPressurePlateHeavy;
-use pocketmine\block\WeightedPressurePlateLight;
-use pocketmine\block\Wheat;
use pocketmine\block\Wood;
-use pocketmine\block\WoodenButton;
-use pocketmine\block\WoodenDoor;
-use pocketmine\block\WoodenPressurePlate;
-use pocketmine\block\WoodenStairs;
-use pocketmine\block\WoodenTrapdoor;
-use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateData;
-use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
use pocketmine\data\bedrock\block\BlockStateSerializeException;
use pocketmine\data\bedrock\block\BlockStateSerializer;
-use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
use pocketmine\data\bedrock\block\BlockTypeNames as Ids;
use pocketmine\data\bedrock\block\convert\BlockStateSerializerHelper as Helper;
use pocketmine\data\bedrock\block\convert\BlockStateWriter as Writer;
-use pocketmine\math\Axis;
-use pocketmine\math\Facing;
use function get_class;
final class BlockObjectToStateSerializer implements BlockStateSerializer{
@@ -196,20 +52,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
*/
private array $cache = [];
- public function __construct(){
- $this->registerCandleSerializers();
- $this->registerFlatColorBlockSerializers();
- $this->registerFlatCoralSerializers();
- $this->registerCauldronSerializers();
- $this->registerFlatWoodBlockSerializers();
- $this->registerLeavesSerializers();
- $this->registerSaplingSerializers();
- $this->registerMobHeadSerializers();
- $this->registerCopperSerializers();
- $this->registerSimpleSerializers();
- $this->registerSerializers();
- }
-
public function serialize(int $stateId) : BlockStateData{
//TODO: singleton usage not ideal
//TODO: we may want to deduplicate cache entries to avoid wasting memory
@@ -227,24 +69,36 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
*/
public function map(Block $block, \Closure|Writer|BlockStateData $serializer) : void{
if(isset($this->serializers[$block->getTypeId()])){
- throw new \InvalidArgumentException("Block type ID " . $block->getTypeId() . " already has a serializer registered");
+ throw new \InvalidArgumentException("Block type ID " . $block->getTypeId() . " (" . $block->getName() . ") already has a serializer registered");
}
//writer accepted for convenience only
$this->serializers[$block->getTypeId()] = $serializer instanceof Writer ? $serializer->getBlockStateData() : $serializer;
}
+ /**
+ * @deprecated
+ */
public function mapSimple(Block $block, string $id) : void{
$this->map($block, BlockStateData::current($id, []));
}
+ /**
+ * @deprecated
+ */
public function mapSlab(Slab $block, string $singleId, string $doubleId) : void{
$this->map($block, fn(Slab $block) => Helper::encodeSlab($block, $singleId, $doubleId));
}
+ /**
+ * @deprecated
+ */
public function mapStairs(Stair $block, string $id) : void{
$this->map($block, fn(Stair $block) => Helper::encodeStairs($block, Writer::create($id)));
}
+ /**
+ * @deprecated
+ */
public function mapLog(Wood $block, string $unstrippedId, string $strippedId) : void{
$this->map($block, fn(Wood $block) => Helper::encodeLog($block, $unstrippedId, $strippedId));
}
@@ -279,1451 +133,4 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return $result instanceof Writer ? $result->getBlockStateData() : $result;
}
-
- /**
- * @phpstan-template TBlock of Block
- * @phpstan-template TEnum of \UnitEnum
- *
- * @phpstan-param TBlock $block
- * @phpstan-param StringEnumMap $mapProperty
- * @phpstan-param \Closure(TBlock) : TEnum $getProperty
- * @phpstan-param ?\Closure(TBlock, Writer) : Writer $extra
- */
- public function mapFlattenedEnum(
- Block $block,
- StringEnumMap $mapProperty,
- string $prefix,
- string $suffix,
- \Closure $getProperty,
- ?\Closure $extra = null
- ) : void{
- $this->map($block, function(Block $block) use ($getProperty, $mapProperty, $prefix, $suffix, $extra) : Writer{
- $property = $getProperty($block);
- $infix = $mapProperty->enumToValue($property);
- $id = $prefix . $infix . $suffix;
- $writer = new Writer($id);
- if($extra !== null){
- $extra($block, $writer);
- }
- return $writer;
- });
- }
-
- /**
- * @phpstan-template TBlock of Block&Colored
- * @phpstan-param TBlock $block
- * @phpstan-param ?\Closure(TBlock, Writer) : Writer $extra
- */
- public function mapColored(
- Block $block,
- string $prefix,
- string $suffix,
- ?\Closure $extra = null
- ) : void{
- $this->mapFlattenedEnum(
- $block,
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- $prefix,
- $suffix,
- fn(Colored $block) => $block->getColor(),
- $extra
- );
- }
-
- private function registerCandleSerializers() : void{
- $this->map(Blocks::CANDLE(), fn(Candle $block) => Helper::encodeCandle($block, new Writer(Ids::CANDLE)));
- $this->mapColored(
- Blocks::DYED_CANDLE(),
- "minecraft:",
- "_candle",
- Helper::encodeCandle(...)
- );
- $this->map(Blocks::CAKE_WITH_CANDLE(), fn(CakeWithCandle $block) => Writer::create(Ids::CANDLE_CAKE)
- ->writeBool(StateNames::LIT, $block->isLit()));
- $this->mapColored(
- Blocks::CAKE_WITH_DYED_CANDLE(),
- "minecraft:",
- "_candle_cake",
- fn(CakeWithDyedCandle $block, Writer $writer) => $writer->writeBool(StateNames::LIT, $block->isLit())
- );
- }
-
- public function registerFlatColorBlockSerializers() : void{
- $this->mapColored(Blocks::STAINED_HARDENED_GLASS(), "minecraft:hard_", "_stained_glass");
- $this->mapColored(Blocks::STAINED_HARDENED_GLASS_PANE(), "minecraft:hard_", "_stained_glass_pane");
-
- $this->mapColored(Blocks::CARPET(), "minecraft:", "_carpet");
- $this->mapColored(Blocks::CONCRETE(), "minecraft:", "_concrete");
- $this->mapColored(Blocks::CONCRETE_POWDER(), "minecraft:", "_concrete_powder");
- $this->mapColored(Blocks::DYED_SHULKER_BOX(), "minecraft:", "_shulker_box");
- $this->mapColored(Blocks::STAINED_CLAY(), "minecraft:", "_terracotta");
- $this->mapColored(Blocks::STAINED_GLASS(), "minecraft:", "_stained_glass");
- $this->mapColored(Blocks::STAINED_GLASS_PANE(), "minecraft:", "_stained_glass_pane");
- $this->mapColored(Blocks::WOOL(), "minecraft:", "_wool");
-
- $this->map(Blocks::GLAZED_TERRACOTTA(), function(GlazedTerracotta $block) : Writer{
- return Writer::create(match($block->getColor()){
- DyeColor::BLACK => Ids::BLACK_GLAZED_TERRACOTTA,
- DyeColor::BLUE => Ids::BLUE_GLAZED_TERRACOTTA,
- DyeColor::BROWN => Ids::BROWN_GLAZED_TERRACOTTA,
- DyeColor::CYAN => Ids::CYAN_GLAZED_TERRACOTTA,
- DyeColor::GRAY => Ids::GRAY_GLAZED_TERRACOTTA,
- DyeColor::GREEN => Ids::GREEN_GLAZED_TERRACOTTA,
- DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_GLAZED_TERRACOTTA,
- DyeColor::LIGHT_GRAY => Ids::SILVER_GLAZED_TERRACOTTA, //minecraft sadness
- DyeColor::LIME => Ids::LIME_GLAZED_TERRACOTTA,
- DyeColor::MAGENTA => Ids::MAGENTA_GLAZED_TERRACOTTA,
- DyeColor::ORANGE => Ids::ORANGE_GLAZED_TERRACOTTA,
- DyeColor::PINK => Ids::PINK_GLAZED_TERRACOTTA,
- DyeColor::PURPLE => Ids::PURPLE_GLAZED_TERRACOTTA,
- DyeColor::RED => Ids::RED_GLAZED_TERRACOTTA,
- DyeColor::WHITE => Ids::WHITE_GLAZED_TERRACOTTA,
- DyeColor::YELLOW => Ids::YELLOW_GLAZED_TERRACOTTA,
- })
- ->writeHorizontalFacing($block->getFacing());
- });
- }
-
- private function registerFlatCoralSerializers() : void{
- $this->map(Blocks::CORAL(), fn(Coral $block) => BlockStateData::current(match($block->getCoralType()){
- CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL : Ids::BRAIN_CORAL,
- CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL : Ids::BUBBLE_CORAL,
- CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL : Ids::FIRE_CORAL,
- CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL : Ids::HORN_CORAL,
- CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL : Ids::TUBE_CORAL,
- }, []));
-
- $this->map(Blocks::CORAL_FAN(), fn(FloorCoralFan $block) => Writer::create(
- match($block->getCoralType()){
- CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_FAN : Ids::BRAIN_CORAL_FAN,
- CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_FAN : Ids::BUBBLE_CORAL_FAN,
- CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_FAN : Ids::FIRE_CORAL_FAN,
- CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_FAN : Ids::HORN_CORAL_FAN,
- CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_FAN : Ids::TUBE_CORAL_FAN,
- })
- ->writeInt(StateNames::CORAL_FAN_DIRECTION, match($axis = $block->getAxis()){
- Axis::X => 0,
- Axis::Z => 1,
- default => throw new BlockStateSerializeException("Invalid axis {$axis}"),
- }));
-
- $this->map(Blocks::CORAL_BLOCK(), fn(CoralBlock $block) => BlockStateData::current(match($block->getCoralType()){
- CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_BLOCK : Ids::BRAIN_CORAL_BLOCK,
- CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_BLOCK : Ids::BUBBLE_CORAL_BLOCK,
- CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_BLOCK : Ids::FIRE_CORAL_BLOCK,
- CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_BLOCK : Ids::HORN_CORAL_BLOCK,
- CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_BLOCK : Ids::TUBE_CORAL_BLOCK,
- }, []));
-
- $this->map(Blocks::WALL_CORAL_FAN(), fn(WallCoralFan $block) => Writer::create(
- match($block->getCoralType()){
- CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_WALL_FAN : Ids::TUBE_CORAL_WALL_FAN,
- CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_WALL_FAN : Ids::BRAIN_CORAL_WALL_FAN,
- CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_WALL_FAN : Ids::BUBBLE_CORAL_WALL_FAN,
- CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_WALL_FAN : Ids::FIRE_CORAL_WALL_FAN,
- CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_WALL_FAN : Ids::HORN_CORAL_WALL_FAN,
- })
- ->writeCoralFacing($block->getFacing())
- );
- }
-
- private function registerCauldronSerializers() : void{
- $this->map(Blocks::CAULDRON(), Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, 0));
- $this->map(Blocks::LAVA_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_LAVA, $b->getFillLevel()));
- //potion cauldrons store their real information in the block actor data
- $this->map(Blocks::POTION_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel()));
- $this->map(Blocks::WATER_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel()));
- }
-
- private function registerFlatWoodBlockSerializers() : void{
- $this->map(Blocks::ACACIA_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::ACACIA_BUTTON)));
- $this->map(Blocks::ACACIA_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::ACACIA_DOOR)));
- $this->map(Blocks::ACACIA_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::ACACIA_FENCE_GATE)));
- $this->map(Blocks::ACACIA_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::ACACIA_PRESSURE_PLATE)));
- $this->map(Blocks::ACACIA_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::ACACIA_STANDING_SIGN)));
- $this->map(Blocks::ACACIA_STAIRS(), fn(WoodenStairs $block) => Helper::encodeStairs($block, new Writer(Ids::ACACIA_STAIRS)));
- $this->map(Blocks::ACACIA_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::ACACIA_TRAPDOOR)));
- $this->map(Blocks::ACACIA_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::ACACIA_WALL_SIGN)));
- $this->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG);
- $this->mapLog(Blocks::ACACIA_WOOD(), Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD);
- $this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE);
- $this->mapSimple(Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS);
- $this->mapSlab(Blocks::ACACIA_SLAB(), Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB);
-
- $this->map(Blocks::BIRCH_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::BIRCH_BUTTON)));
- $this->map(Blocks::BIRCH_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::BIRCH_DOOR)));
- $this->map(Blocks::BIRCH_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::BIRCH_FENCE_GATE)));
- $this->map(Blocks::BIRCH_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::BIRCH_PRESSURE_PLATE)));
- $this->map(Blocks::BIRCH_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::BIRCH_STANDING_SIGN)));
- $this->map(Blocks::BIRCH_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::BIRCH_TRAPDOOR)));
- $this->map(Blocks::BIRCH_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::BIRCH_WALL_SIGN)));
- $this->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG);
- $this->mapLog(Blocks::BIRCH_WOOD(), Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD);
- $this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
- $this->mapSimple(Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS);
- $this->mapSlab(Blocks::BIRCH_SLAB(), Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB);
- $this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS);
-
- $this->map(Blocks::CHERRY_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CHERRY_BUTTON)));
- $this->map(Blocks::CHERRY_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CHERRY_DOOR)));
- $this->map(Blocks::CHERRY_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::CHERRY_FENCE_GATE)));
- $this->map(Blocks::CHERRY_LOG(), fn(Wood $block) => Helper::encodeLog($block, Ids::CHERRY_LOG, Ids::STRIPPED_CHERRY_LOG));
- $this->map(Blocks::CHERRY_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::CHERRY_PRESSURE_PLATE)));
- $this->map(Blocks::CHERRY_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::CHERRY_STANDING_SIGN)));
- $this->map(Blocks::CHERRY_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::CHERRY_TRAPDOOR)));
- $this->map(Blocks::CHERRY_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::CHERRY_WALL_SIGN)));
- $this->mapSimple(Blocks::CHERRY_FENCE(), Ids::CHERRY_FENCE);
- $this->mapSimple(Blocks::CHERRY_PLANKS(), Ids::CHERRY_PLANKS);
- $this->mapSlab(Blocks::CHERRY_SLAB(), Ids::CHERRY_SLAB, Ids::CHERRY_DOUBLE_SLAB);
- $this->mapStairs(Blocks::CHERRY_STAIRS(), Ids::CHERRY_STAIRS);
- $this->mapLog(Blocks::CHERRY_WOOD(), Ids::CHERRY_WOOD, Ids::STRIPPED_CHERRY_WOOD);
-
- $this->map(Blocks::CRIMSON_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CRIMSON_BUTTON)));
- $this->map(Blocks::CRIMSON_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CRIMSON_DOOR)));
- $this->map(Blocks::CRIMSON_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::CRIMSON_FENCE_GATE)));
- $this->map(Blocks::CRIMSON_HYPHAE(), fn(Wood $block) => Helper::encodeLog($block, Ids::CRIMSON_HYPHAE, Ids::STRIPPED_CRIMSON_HYPHAE));
- $this->map(Blocks::CRIMSON_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::CRIMSON_PRESSURE_PLATE)));
- $this->map(Blocks::CRIMSON_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::CRIMSON_STANDING_SIGN)));
- $this->map(Blocks::CRIMSON_STEM(), fn(Wood $block) => Helper::encodeLog($block, Ids::CRIMSON_STEM, Ids::STRIPPED_CRIMSON_STEM));
- $this->map(Blocks::CRIMSON_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::CRIMSON_TRAPDOOR)));
- $this->map(Blocks::CRIMSON_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::CRIMSON_WALL_SIGN)));
- $this->mapSimple(Blocks::CRIMSON_FENCE(), Ids::CRIMSON_FENCE);
- $this->mapSimple(Blocks::CRIMSON_PLANKS(), Ids::CRIMSON_PLANKS);
- $this->mapSlab(Blocks::CRIMSON_SLAB(), Ids::CRIMSON_SLAB, Ids::CRIMSON_DOUBLE_SLAB);
- $this->mapStairs(Blocks::CRIMSON_STAIRS(), Ids::CRIMSON_STAIRS);
-
- $this->map(Blocks::DARK_OAK_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::DARK_OAK_BUTTON)));
- $this->map(Blocks::DARK_OAK_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::DARK_OAK_DOOR)));
- $this->map(Blocks::DARK_OAK_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::DARK_OAK_FENCE_GATE)));
- $this->map(Blocks::DARK_OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::DARK_OAK_PRESSURE_PLATE)));
- $this->map(Blocks::DARK_OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::DARKOAK_STANDING_SIGN)));
- $this->map(Blocks::DARK_OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::DARK_OAK_TRAPDOOR)));
- $this->map(Blocks::DARK_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::DARKOAK_WALL_SIGN)));
- $this->mapLog(Blocks::DARK_OAK_LOG(), Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG);
- $this->mapLog(Blocks::DARK_OAK_WOOD(), Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD);
- $this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE);
- $this->mapSimple(Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS);
- $this->mapSlab(Blocks::DARK_OAK_SLAB(), Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS);
-
- $this->map(Blocks::JUNGLE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::JUNGLE_BUTTON)));
- $this->map(Blocks::JUNGLE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::JUNGLE_DOOR)));
- $this->map(Blocks::JUNGLE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::JUNGLE_FENCE_GATE)));
- $this->map(Blocks::JUNGLE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::JUNGLE_PRESSURE_PLATE)));
- $this->map(Blocks::JUNGLE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::JUNGLE_STANDING_SIGN)));
- $this->map(Blocks::JUNGLE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::JUNGLE_TRAPDOOR)));
- $this->map(Blocks::JUNGLE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::JUNGLE_WALL_SIGN)));
- $this->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG);
- $this->mapLog(Blocks::JUNGLE_WOOD(), Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD);
- $this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
- $this->mapSimple(Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS);
- $this->mapSlab(Blocks::JUNGLE_SLAB(), Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS);
-
- $this->map(Blocks::MANGROVE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::MANGROVE_BUTTON)));
- $this->map(Blocks::MANGROVE_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::MANGROVE_DOOR)));
- $this->map(Blocks::MANGROVE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::MANGROVE_FENCE_GATE)));
- $this->map(Blocks::MANGROVE_LOG(), fn(Wood $block) => Helper::encodeLog($block, Ids::MANGROVE_LOG, Ids::STRIPPED_MANGROVE_LOG));
- $this->map(Blocks::MANGROVE_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::MANGROVE_PRESSURE_PLATE)));
- $this->map(Blocks::MANGROVE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::MANGROVE_STANDING_SIGN)));
- $this->map(Blocks::MANGROVE_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::MANGROVE_TRAPDOOR)));
- $this->map(Blocks::MANGROVE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::MANGROVE_WALL_SIGN)));
- $this->mapSimple(Blocks::MANGROVE_FENCE(), Ids::MANGROVE_FENCE);
- $this->mapSimple(Blocks::MANGROVE_PLANKS(), Ids::MANGROVE_PLANKS);
- $this->mapSlab(Blocks::MANGROVE_SLAB(), Ids::MANGROVE_SLAB, Ids::MANGROVE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::MANGROVE_STAIRS(), Ids::MANGROVE_STAIRS);
- $this->mapLog(Blocks::MANGROVE_WOOD(), Ids::MANGROVE_WOOD, Ids::STRIPPED_MANGROVE_WOOD);
-
- $this->map(Blocks::OAK_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::WOODEN_BUTTON)));
- $this->map(Blocks::OAK_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::WOODEN_DOOR)));
- $this->map(Blocks::OAK_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::FENCE_GATE)));
- $this->map(Blocks::OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::WOODEN_PRESSURE_PLATE)));
- $this->map(Blocks::OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::STANDING_SIGN)));
- $this->map(Blocks::OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::TRAPDOOR)));
- $this->map(Blocks::OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WALL_SIGN)));
- $this->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG);
- $this->mapLog(Blocks::OAK_WOOD(), Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD);
- $this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
- $this->mapSimple(Blocks::OAK_PLANKS(), Ids::OAK_PLANKS);
- $this->mapSlab(Blocks::OAK_SLAB(), Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS);
-
- $this->map(Blocks::PALE_OAK_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::PALE_OAK_BUTTON)));
- $this->map(Blocks::PALE_OAK_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::PALE_OAK_DOOR)));
- $this->map(Blocks::PALE_OAK_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::PALE_OAK_FENCE_GATE)));
- $this->map(Blocks::PALE_OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::PALE_OAK_PRESSURE_PLATE)));
- $this->map(Blocks::PALE_OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::PALE_OAK_STANDING_SIGN)));
- $this->map(Blocks::PALE_OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::PALE_OAK_TRAPDOOR)));
- $this->map(Blocks::PALE_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::PALE_OAK_WALL_SIGN)));
- $this->mapLog(Blocks::PALE_OAK_LOG(), Ids::PALE_OAK_LOG, Ids::STRIPPED_PALE_OAK_LOG);
- $this->mapLog(Blocks::PALE_OAK_WOOD(), Ids::PALE_OAK_WOOD, Ids::STRIPPED_PALE_OAK_WOOD);
- $this->mapSimple(Blocks::PALE_OAK_FENCE(), Ids::PALE_OAK_FENCE);
- $this->mapSimple(Blocks::PALE_OAK_PLANKS(), Ids::PALE_OAK_PLANKS);
- $this->mapSlab(Blocks::PALE_OAK_SLAB(), Ids::PALE_OAK_SLAB, Ids::PALE_OAK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::PALE_OAK_STAIRS(), Ids::PALE_OAK_STAIRS);
-
- $this->map(Blocks::SPRUCE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::SPRUCE_BUTTON)));
- $this->map(Blocks::SPRUCE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::SPRUCE_DOOR)));
- $this->map(Blocks::SPRUCE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::SPRUCE_FENCE_GATE)));
- $this->map(Blocks::SPRUCE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::SPRUCE_PRESSURE_PLATE)));
- $this->map(Blocks::SPRUCE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::SPRUCE_STANDING_SIGN)));
- $this->map(Blocks::SPRUCE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::SPRUCE_TRAPDOOR)));
- $this->map(Blocks::SPRUCE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::SPRUCE_WALL_SIGN)));
- $this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG);
- $this->mapLog(Blocks::SPRUCE_WOOD(), Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD);
- $this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
- $this->mapSimple(Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS);
- $this->mapSlab(Blocks::SPRUCE_SLAB(), Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
- //wood and slabs still use the old way of storing wood type
-
- $this->map(Blocks::WARPED_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::WARPED_BUTTON)));
- $this->map(Blocks::WARPED_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::WARPED_DOOR)));
- $this->map(Blocks::WARPED_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::WARPED_FENCE_GATE)));
- $this->map(Blocks::WARPED_HYPHAE(), fn(Wood $block) => Helper::encodeLog($block, Ids::WARPED_HYPHAE, Ids::STRIPPED_WARPED_HYPHAE));
- $this->map(Blocks::WARPED_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::WARPED_PRESSURE_PLATE)));
- $this->map(Blocks::WARPED_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::WARPED_STANDING_SIGN)));
- $this->map(Blocks::WARPED_STEM(), fn(Wood $block) => Helper::encodeLog($block, Ids::WARPED_STEM, Ids::STRIPPED_WARPED_STEM));
- $this->map(Blocks::WARPED_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::WARPED_TRAPDOOR)));
- $this->map(Blocks::WARPED_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WARPED_WALL_SIGN)));
- $this->mapSimple(Blocks::WARPED_FENCE(), Ids::WARPED_FENCE);
- $this->mapSimple(Blocks::WARPED_PLANKS(), Ids::WARPED_PLANKS);
- $this->mapSlab(Blocks::WARPED_SLAB(), Ids::WARPED_SLAB, Ids::WARPED_DOUBLE_SLAB);
- $this->mapStairs(Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS);
- }
-
- private function registerLeavesSerializers() : void{
- //flattened IDs
- $this->map(Blocks::AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES)));
- $this->map(Blocks::CHERRY_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::CHERRY_LEAVES)));
- $this->map(Blocks::FLOWERING_AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES_FLOWERED)));
- $this->map(Blocks::MANGROVE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::MANGROVE_LEAVES)));
- $this->map(Blocks::PALE_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::PALE_OAK_LEAVES)));
-
- //legacy mess
- $this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::ACACIA_LEAVES)));
- $this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::BIRCH_LEAVES)));
- $this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::DARK_OAK_LEAVES)));
- $this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::JUNGLE_LEAVES)));
- $this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::OAK_LEAVES)));
- $this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::SPRUCE_LEAVES)));
- }
-
- private function registerSaplingSerializers() : void{
- foreach([
- Ids::ACACIA_SAPLING => Blocks::ACACIA_SAPLING(),
- Ids::BIRCH_SAPLING => Blocks::BIRCH_SAPLING(),
- Ids::DARK_OAK_SAPLING => Blocks::DARK_OAK_SAPLING(),
- Ids::JUNGLE_SAPLING => Blocks::JUNGLE_SAPLING(),
- Ids::OAK_SAPLING => Blocks::OAK_SAPLING(),
- Ids::SPRUCE_SAPLING => Blocks::SPRUCE_SAPLING(),
- ] as $id => $block){
- $this->map($block, fn(Sapling $block) => Helper::encodeSapling($block, new Writer($id)));
- }
- }
-
- private function registerMobHeadSerializers() : void{
- $this->map(Blocks::MOB_HEAD(), fn(MobHead $block) => Writer::create(match ($block->getMobHeadType()){
- MobHeadType::CREEPER => Ids::CREEPER_HEAD,
- MobHeadType::DRAGON => Ids::DRAGON_HEAD,
- MobHeadType::PIGLIN => Ids::PIGLIN_HEAD,
- MobHeadType::PLAYER => Ids::PLAYER_HEAD,
- MobHeadType::SKELETON => Ids::SKELETON_SKULL,
- MobHeadType::WITHER_SKELETON => Ids::WITHER_SKELETON_SKULL,
- MobHeadType::ZOMBIE => Ids::ZOMBIE_HEAD,
- })->writeFacingWithoutDown($block->getFacing()));
- }
-
- private function registerCopperSerializers() : void{
- $this->map(Blocks::COPPER(), function(Copper $block) : BlockStateData{
- $oxidation = $block->getOxidation();
- return BlockStateData::current(
- $block->isWaxed() ?
- Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
- Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER),
- []
- );
- });
- $this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : BlockStateData{
- $oxidation = $block->getOxidation();
- return BlockStateData::current(
- $block->isWaxed() ?
- Helper::selectCopperId($oxidation,
- Ids::WAXED_CHISELED_COPPER,
- Ids::WAXED_EXPOSED_CHISELED_COPPER,
- Ids::WAXED_WEATHERED_CHISELED_COPPER,
- Ids::WAXED_OXIDIZED_CHISELED_COPPER
- ) :
- Helper::selectCopperId($oxidation,
- Ids::CHISELED_COPPER,
- Ids::EXPOSED_CHISELED_COPPER,
- Ids::WEATHERED_CHISELED_COPPER,
- Ids::OXIDIZED_CHISELED_COPPER
- ),
- []
- );
- });
- $this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : BlockStateData{
- $oxidation = $block->getOxidation();
- return BlockStateData::current(
- $block->isWaxed() ?
- Helper::selectCopperId($oxidation,
- Ids::WAXED_COPPER_GRATE,
- Ids::WAXED_EXPOSED_COPPER_GRATE,
- Ids::WAXED_WEATHERED_COPPER_GRATE,
- Ids::WAXED_OXIDIZED_COPPER_GRATE
- ) :
- Helper::selectCopperId($oxidation,
- Ids::COPPER_GRATE,
- Ids::EXPOSED_COPPER_GRATE,
- Ids::WEATHERED_COPPER_GRATE,
- Ids::OXIDIZED_COPPER_GRATE
- ),
- []
- );
- });
- $this->map(Blocks::CUT_COPPER(), function(Copper $block) : BlockStateData{
- $oxidation = $block->getOxidation();
- return BlockStateData::current(
- $block->isWaxed() ?
- Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
- Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER),
- []
- );
- });
- $this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
- $oxidation = $block->getOxidation();
- return Helper::encodeSlab(
- $block,
- ($block->isWaxed() ?
- Helper::selectCopperId(
- $oxidation,
- Ids::WAXED_CUT_COPPER_SLAB,
- Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
- Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
- Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
- ) :
- Helper::selectCopperId(
- $oxidation,
- Ids::CUT_COPPER_SLAB,
- Ids::EXPOSED_CUT_COPPER_SLAB,
- Ids::WEATHERED_CUT_COPPER_SLAB,
- Ids::OXIDIZED_CUT_COPPER_SLAB
- )
- ),
- ($block->isWaxed() ?
- Helper::selectCopperId(
- $oxidation,
- Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
- ) :
- Helper::selectCopperId(
- $oxidation,
- Ids::DOUBLE_CUT_COPPER_SLAB,
- Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
- Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
- )
- )
- );
- });
- $this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
- $oxidation = $block->getOxidation();
- return Helper::encodeStairs(
- $block,
- new Writer($block->isWaxed() ?
- Helper::selectCopperId(
- $oxidation,
- Ids::WAXED_CUT_COPPER_STAIRS,
- Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
- Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
- Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
- ) :
- Helper::selectCopperId(
- $oxidation,
- Ids::CUT_COPPER_STAIRS,
- Ids::EXPOSED_CUT_COPPER_STAIRS,
- Ids::WEATHERED_CUT_COPPER_STAIRS,
- Ids::OXIDIZED_CUT_COPPER_STAIRS
- )
- )
- );
- });
- $this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
- $oxidation = $block->getOxidation();
- return Writer::create($block->isWaxed() ?
- Helper::selectCopperId($oxidation,
- Ids::WAXED_COPPER_BULB,
- Ids::WAXED_EXPOSED_COPPER_BULB,
- Ids::WAXED_WEATHERED_COPPER_BULB,
- Ids::WAXED_OXIDIZED_COPPER_BULB) :
- Helper::selectCopperId($oxidation,
- Ids::COPPER_BULB,
- Ids::EXPOSED_COPPER_BULB,
- Ids::WEATHERED_COPPER_BULB,
- Ids::OXIDIZED_COPPER_BULB
- ))
- ->writeBool(StateNames::LIT, $block->isLit())
- ->writeBool(StateNames::POWERED_BIT, $block->isPowered());
- });
- $this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
- $oxidation = $block->getOxidation();
- return Helper::encodeDoor(
- $block,
- new Writer($block->isWaxed() ?
- Helper::selectCopperId(
- $oxidation,
- Ids::WAXED_COPPER_DOOR,
- Ids::WAXED_EXPOSED_COPPER_DOOR,
- Ids::WAXED_WEATHERED_COPPER_DOOR,
- Ids::WAXED_OXIDIZED_COPPER_DOOR
- ) :
- Helper::selectCopperId(
- $oxidation,
- Ids::COPPER_DOOR,
- Ids::EXPOSED_COPPER_DOOR,
- Ids::WEATHERED_COPPER_DOOR,
- Ids::OXIDIZED_COPPER_DOOR
- )
- )
- );
- });
- $this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
- $oxidation = $block->getOxidation();
- return Helper::encodeTrapdoor(
- $block,
- new Writer($block->isWaxed() ?
- Helper::selectCopperId(
- $oxidation,
- Ids::WAXED_COPPER_TRAPDOOR,
- Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
- Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
- Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
- ) :
- Helper::selectCopperId(
- $oxidation,
- Ids::COPPER_TRAPDOOR,
- Ids::EXPOSED_COPPER_TRAPDOOR,
- Ids::WEATHERED_COPPER_TRAPDOOR,
- Ids::OXIDIZED_COPPER_TRAPDOOR
- )
- )
- );
- });
- }
-
- private function registerSimpleSerializers() : void{
- $this->mapSimple(Blocks::AIR(), Ids::AIR);
- $this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
- $this->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS);
- $this->mapSimple(Blocks::ANDESITE(), Ids::ANDESITE);
- $this->mapSimple(Blocks::BARRIER(), Ids::BARRIER);
- $this->mapSimple(Blocks::BEACON(), Ids::BEACON);
- $this->mapSimple(Blocks::BLACKSTONE(), Ids::BLACKSTONE);
- $this->mapSimple(Blocks::BLUE_ICE(), Ids::BLUE_ICE);
- $this->mapSimple(Blocks::BOOKSHELF(), Ids::BOOKSHELF);
- $this->mapSimple(Blocks::BRICKS(), Ids::BRICK_BLOCK);
- $this->mapSimple(Blocks::BROWN_MUSHROOM(), Ids::BROWN_MUSHROOM);
- $this->mapSimple(Blocks::BUDDING_AMETHYST(), Ids::BUDDING_AMETHYST);
- $this->mapSimple(Blocks::CALCITE(), Ids::CALCITE);
- $this->mapSimple(Blocks::CARTOGRAPHY_TABLE(), Ids::CARTOGRAPHY_TABLE);
- $this->mapSimple(Blocks::CHEMICAL_HEAT(), Ids::CHEMICAL_HEAT);
- $this->mapSimple(Blocks::CHISELED_DEEPSLATE(), Ids::CHISELED_DEEPSLATE);
- $this->mapSimple(Blocks::CHISELED_NETHER_BRICKS(), Ids::CHISELED_NETHER_BRICKS);
- $this->mapSimple(Blocks::CHISELED_POLISHED_BLACKSTONE(), Ids::CHISELED_POLISHED_BLACKSTONE);
- $this->mapSimple(Blocks::CHISELED_RED_SANDSTONE(), Ids::CHISELED_RED_SANDSTONE);
- $this->mapSimple(Blocks::CHISELED_RESIN_BRICKS(), Ids::CHISELED_RESIN_BRICKS);
- $this->mapSimple(Blocks::CHISELED_SANDSTONE(), Ids::CHISELED_SANDSTONE);
- $this->mapSimple(Blocks::CHISELED_STONE_BRICKS(), Ids::CHISELED_STONE_BRICKS);
- $this->mapSimple(Blocks::CHISELED_TUFF(), Ids::CHISELED_TUFF);
- $this->mapSimple(Blocks::CHISELED_TUFF_BRICKS(), Ids::CHISELED_TUFF_BRICKS);
- $this->mapSimple(Blocks::CHORUS_PLANT(), Ids::CHORUS_PLANT);
- $this->mapSimple(Blocks::CLAY(), Ids::CLAY);
- $this->mapSimple(Blocks::COAL(), Ids::COAL_BLOCK);
- $this->mapSimple(Blocks::COAL_ORE(), Ids::COAL_ORE);
- $this->mapSimple(Blocks::COBBLED_DEEPSLATE(), Ids::COBBLED_DEEPSLATE);
- $this->mapSimple(Blocks::COBBLESTONE(), Ids::COBBLESTONE);
- $this->mapSimple(Blocks::COBWEB(), Ids::WEB);
- $this->mapSimple(Blocks::COPPER_ORE(), Ids::COPPER_ORE);
- $this->mapSimple(Blocks::CRACKED_DEEPSLATE_BRICKS(), Ids::CRACKED_DEEPSLATE_BRICKS);
- $this->mapSimple(Blocks::CRACKED_DEEPSLATE_TILES(), Ids::CRACKED_DEEPSLATE_TILES);
- $this->mapSimple(Blocks::CRACKED_NETHER_BRICKS(), Ids::CRACKED_NETHER_BRICKS);
- $this->mapSimple(Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS(), Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS);
- $this->mapSimple(Blocks::CRACKED_STONE_BRICKS(), Ids::CRACKED_STONE_BRICKS);
- $this->mapSimple(Blocks::CRAFTING_TABLE(), Ids::CRAFTING_TABLE);
- $this->mapSimple(Blocks::CRIMSON_ROOTS(), Ids::CRIMSON_ROOTS);
- $this->mapSimple(Blocks::CRYING_OBSIDIAN(), Ids::CRYING_OBSIDIAN);
- $this->mapSimple(Blocks::DANDELION(), Ids::DANDELION);
- $this->mapSimple(Blocks::CUT_RED_SANDSTONE(), Ids::CUT_RED_SANDSTONE);
- $this->mapSimple(Blocks::CUT_SANDSTONE(), Ids::CUT_SANDSTONE);
- $this->mapSimple(Blocks::DARK_PRISMARINE(), Ids::DARK_PRISMARINE);
- $this->mapSimple(Blocks::DEAD_BUSH(), Ids::DEADBUSH);
- $this->mapSimple(Blocks::DEEPSLATE_BRICKS(), Ids::DEEPSLATE_BRICKS);
- $this->mapSimple(Blocks::DEEPSLATE_COAL_ORE(), Ids::DEEPSLATE_COAL_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_COPPER_ORE(), Ids::DEEPSLATE_COPPER_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_DIAMOND_ORE(), Ids::DEEPSLATE_DIAMOND_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_EMERALD_ORE(), Ids::DEEPSLATE_EMERALD_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_GOLD_ORE(), Ids::DEEPSLATE_GOLD_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_IRON_ORE(), Ids::DEEPSLATE_IRON_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_LAPIS_LAZULI_ORE(), Ids::DEEPSLATE_LAPIS_ORE);
- $this->mapSimple(Blocks::DEEPSLATE_TILES(), Ids::DEEPSLATE_TILES);
- $this->mapSimple(Blocks::DIAMOND(), Ids::DIAMOND_BLOCK);
- $this->mapSimple(Blocks::DIAMOND_ORE(), Ids::DIAMOND_ORE);
- $this->mapSimple(Blocks::DIORITE(), Ids::DIORITE);
- $this->mapSimple(Blocks::DRAGON_EGG(), Ids::DRAGON_EGG);
- $this->mapSimple(Blocks::DRIED_KELP(), Ids::DRIED_KELP_BLOCK);
- $this->mapSimple(Blocks::ELEMENT_ACTINIUM(), Ids::ELEMENT_89);
- $this->mapSimple(Blocks::ELEMENT_ALUMINUM(), Ids::ELEMENT_13);
- $this->mapSimple(Blocks::ELEMENT_AMERICIUM(), Ids::ELEMENT_95);
- $this->mapSimple(Blocks::ELEMENT_ANTIMONY(), Ids::ELEMENT_51);
- $this->mapSimple(Blocks::ELEMENT_ARGON(), Ids::ELEMENT_18);
- $this->mapSimple(Blocks::ELEMENT_ARSENIC(), Ids::ELEMENT_33);
- $this->mapSimple(Blocks::ELEMENT_ASTATINE(), Ids::ELEMENT_85);
- $this->mapSimple(Blocks::ELEMENT_BARIUM(), Ids::ELEMENT_56);
- $this->mapSimple(Blocks::ELEMENT_BERKELIUM(), Ids::ELEMENT_97);
- $this->mapSimple(Blocks::ELEMENT_BERYLLIUM(), Ids::ELEMENT_4);
- $this->mapSimple(Blocks::ELEMENT_BISMUTH(), Ids::ELEMENT_83);
- $this->mapSimple(Blocks::ELEMENT_BOHRIUM(), Ids::ELEMENT_107);
- $this->mapSimple(Blocks::ELEMENT_BORON(), Ids::ELEMENT_5);
- $this->mapSimple(Blocks::ELEMENT_BROMINE(), Ids::ELEMENT_35);
- $this->mapSimple(Blocks::ELEMENT_CADMIUM(), Ids::ELEMENT_48);
- $this->mapSimple(Blocks::ELEMENT_CALCIUM(), Ids::ELEMENT_20);
- $this->mapSimple(Blocks::ELEMENT_CALIFORNIUM(), Ids::ELEMENT_98);
- $this->mapSimple(Blocks::ELEMENT_CARBON(), Ids::ELEMENT_6);
- $this->mapSimple(Blocks::ELEMENT_CERIUM(), Ids::ELEMENT_58);
- $this->mapSimple(Blocks::ELEMENT_CESIUM(), Ids::ELEMENT_55);
- $this->mapSimple(Blocks::ELEMENT_CHLORINE(), Ids::ELEMENT_17);
- $this->mapSimple(Blocks::ELEMENT_CHROMIUM(), Ids::ELEMENT_24);
- $this->mapSimple(Blocks::ELEMENT_COBALT(), Ids::ELEMENT_27);
- $this->mapSimple(Blocks::ELEMENT_COPERNICIUM(), Ids::ELEMENT_112);
- $this->mapSimple(Blocks::ELEMENT_COPPER(), Ids::ELEMENT_29);
- $this->mapSimple(Blocks::ELEMENT_CURIUM(), Ids::ELEMENT_96);
- $this->mapSimple(Blocks::ELEMENT_DARMSTADTIUM(), Ids::ELEMENT_110);
- $this->mapSimple(Blocks::ELEMENT_DUBNIUM(), Ids::ELEMENT_105);
- $this->mapSimple(Blocks::ELEMENT_DYSPROSIUM(), Ids::ELEMENT_66);
- $this->mapSimple(Blocks::ELEMENT_EINSTEINIUM(), Ids::ELEMENT_99);
- $this->mapSimple(Blocks::ELEMENT_ERBIUM(), Ids::ELEMENT_68);
- $this->mapSimple(Blocks::ELEMENT_EUROPIUM(), Ids::ELEMENT_63);
- $this->mapSimple(Blocks::ELEMENT_FERMIUM(), Ids::ELEMENT_100);
- $this->mapSimple(Blocks::ELEMENT_FLEROVIUM(), Ids::ELEMENT_114);
- $this->mapSimple(Blocks::ELEMENT_FLUORINE(), Ids::ELEMENT_9);
- $this->mapSimple(Blocks::ELEMENT_FRANCIUM(), Ids::ELEMENT_87);
- $this->mapSimple(Blocks::ELEMENT_GADOLINIUM(), Ids::ELEMENT_64);
- $this->mapSimple(Blocks::ELEMENT_GALLIUM(), Ids::ELEMENT_31);
- $this->mapSimple(Blocks::ELEMENT_GERMANIUM(), Ids::ELEMENT_32);
- $this->mapSimple(Blocks::ELEMENT_GOLD(), Ids::ELEMENT_79);
- $this->mapSimple(Blocks::ELEMENT_HAFNIUM(), Ids::ELEMENT_72);
- $this->mapSimple(Blocks::ELEMENT_HASSIUM(), Ids::ELEMENT_108);
- $this->mapSimple(Blocks::ELEMENT_HELIUM(), Ids::ELEMENT_2);
- $this->mapSimple(Blocks::ELEMENT_HOLMIUM(), Ids::ELEMENT_67);
- $this->mapSimple(Blocks::ELEMENT_HYDROGEN(), Ids::ELEMENT_1);
- $this->mapSimple(Blocks::ELEMENT_INDIUM(), Ids::ELEMENT_49);
- $this->mapSimple(Blocks::ELEMENT_IODINE(), Ids::ELEMENT_53);
- $this->mapSimple(Blocks::ELEMENT_IRIDIUM(), Ids::ELEMENT_77);
- $this->mapSimple(Blocks::ELEMENT_IRON(), Ids::ELEMENT_26);
- $this->mapSimple(Blocks::ELEMENT_KRYPTON(), Ids::ELEMENT_36);
- $this->mapSimple(Blocks::ELEMENT_LANTHANUM(), Ids::ELEMENT_57);
- $this->mapSimple(Blocks::ELEMENT_LAWRENCIUM(), Ids::ELEMENT_103);
- $this->mapSimple(Blocks::ELEMENT_LEAD(), Ids::ELEMENT_82);
- $this->mapSimple(Blocks::ELEMENT_LITHIUM(), Ids::ELEMENT_3);
- $this->mapSimple(Blocks::ELEMENT_LIVERMORIUM(), Ids::ELEMENT_116);
- $this->mapSimple(Blocks::ELEMENT_LUTETIUM(), Ids::ELEMENT_71);
- $this->mapSimple(Blocks::ELEMENT_MAGNESIUM(), Ids::ELEMENT_12);
- $this->mapSimple(Blocks::ELEMENT_MANGANESE(), Ids::ELEMENT_25);
- $this->mapSimple(Blocks::ELEMENT_MEITNERIUM(), Ids::ELEMENT_109);
- $this->mapSimple(Blocks::ELEMENT_MENDELEVIUM(), Ids::ELEMENT_101);
- $this->mapSimple(Blocks::ELEMENT_MERCURY(), Ids::ELEMENT_80);
- $this->mapSimple(Blocks::ELEMENT_MOLYBDENUM(), Ids::ELEMENT_42);
- $this->mapSimple(Blocks::ELEMENT_MOSCOVIUM(), Ids::ELEMENT_115);
- $this->mapSimple(Blocks::ELEMENT_NEODYMIUM(), Ids::ELEMENT_60);
- $this->mapSimple(Blocks::ELEMENT_NEON(), Ids::ELEMENT_10);
- $this->mapSimple(Blocks::ELEMENT_NEPTUNIUM(), Ids::ELEMENT_93);
- $this->mapSimple(Blocks::ELEMENT_NICKEL(), Ids::ELEMENT_28);
- $this->mapSimple(Blocks::ELEMENT_NIHONIUM(), Ids::ELEMENT_113);
- $this->mapSimple(Blocks::ELEMENT_NIOBIUM(), Ids::ELEMENT_41);
- $this->mapSimple(Blocks::ELEMENT_NITROGEN(), Ids::ELEMENT_7);
- $this->mapSimple(Blocks::ELEMENT_NOBELIUM(), Ids::ELEMENT_102);
- $this->mapSimple(Blocks::ELEMENT_OGANESSON(), Ids::ELEMENT_118);
- $this->mapSimple(Blocks::ELEMENT_OSMIUM(), Ids::ELEMENT_76);
- $this->mapSimple(Blocks::ELEMENT_OXYGEN(), Ids::ELEMENT_8);
- $this->mapSimple(Blocks::ELEMENT_PALLADIUM(), Ids::ELEMENT_46);
- $this->mapSimple(Blocks::ELEMENT_PHOSPHORUS(), Ids::ELEMENT_15);
- $this->mapSimple(Blocks::ELEMENT_PLATINUM(), Ids::ELEMENT_78);
- $this->mapSimple(Blocks::ELEMENT_PLUTONIUM(), Ids::ELEMENT_94);
- $this->mapSimple(Blocks::ELEMENT_POLONIUM(), Ids::ELEMENT_84);
- $this->mapSimple(Blocks::ELEMENT_POTASSIUM(), Ids::ELEMENT_19);
- $this->mapSimple(Blocks::ELEMENT_PRASEODYMIUM(), Ids::ELEMENT_59);
- $this->mapSimple(Blocks::ELEMENT_PROMETHIUM(), Ids::ELEMENT_61);
- $this->mapSimple(Blocks::ELEMENT_PROTACTINIUM(), Ids::ELEMENT_91);
- $this->mapSimple(Blocks::ELEMENT_RADIUM(), Ids::ELEMENT_88);
- $this->mapSimple(Blocks::ELEMENT_RADON(), Ids::ELEMENT_86);
- $this->mapSimple(Blocks::ELEMENT_RHENIUM(), Ids::ELEMENT_75);
- $this->mapSimple(Blocks::ELEMENT_RHODIUM(), Ids::ELEMENT_45);
- $this->mapSimple(Blocks::ELEMENT_ROENTGENIUM(), Ids::ELEMENT_111);
- $this->mapSimple(Blocks::ELEMENT_RUBIDIUM(), Ids::ELEMENT_37);
- $this->mapSimple(Blocks::ELEMENT_RUTHENIUM(), Ids::ELEMENT_44);
- $this->mapSimple(Blocks::ELEMENT_RUTHERFORDIUM(), Ids::ELEMENT_104);
- $this->mapSimple(Blocks::ELEMENT_SAMARIUM(), Ids::ELEMENT_62);
- $this->mapSimple(Blocks::ELEMENT_SCANDIUM(), Ids::ELEMENT_21);
- $this->mapSimple(Blocks::ELEMENT_SEABORGIUM(), Ids::ELEMENT_106);
- $this->mapSimple(Blocks::ELEMENT_SELENIUM(), Ids::ELEMENT_34);
- $this->mapSimple(Blocks::ELEMENT_SILICON(), Ids::ELEMENT_14);
- $this->mapSimple(Blocks::ELEMENT_SILVER(), Ids::ELEMENT_47);
- $this->mapSimple(Blocks::ELEMENT_SODIUM(), Ids::ELEMENT_11);
- $this->mapSimple(Blocks::ELEMENT_STRONTIUM(), Ids::ELEMENT_38);
- $this->mapSimple(Blocks::ELEMENT_SULFUR(), Ids::ELEMENT_16);
- $this->mapSimple(Blocks::ELEMENT_TANTALUM(), Ids::ELEMENT_73);
- $this->mapSimple(Blocks::ELEMENT_TECHNETIUM(), Ids::ELEMENT_43);
- $this->mapSimple(Blocks::ELEMENT_TELLURIUM(), Ids::ELEMENT_52);
- $this->mapSimple(Blocks::ELEMENT_TENNESSINE(), Ids::ELEMENT_117);
- $this->mapSimple(Blocks::ELEMENT_TERBIUM(), Ids::ELEMENT_65);
- $this->mapSimple(Blocks::ELEMENT_THALLIUM(), Ids::ELEMENT_81);
- $this->mapSimple(Blocks::ELEMENT_THORIUM(), Ids::ELEMENT_90);
- $this->mapSimple(Blocks::ELEMENT_THULIUM(), Ids::ELEMENT_69);
- $this->mapSimple(Blocks::ELEMENT_TIN(), Ids::ELEMENT_50);
- $this->mapSimple(Blocks::ELEMENT_TITANIUM(), Ids::ELEMENT_22);
- $this->mapSimple(Blocks::ELEMENT_TUNGSTEN(), Ids::ELEMENT_74);
- $this->mapSimple(Blocks::ELEMENT_URANIUM(), Ids::ELEMENT_92);
- $this->mapSimple(Blocks::ELEMENT_VANADIUM(), Ids::ELEMENT_23);
- $this->mapSimple(Blocks::ELEMENT_XENON(), Ids::ELEMENT_54);
- $this->mapSimple(Blocks::ELEMENT_YTTERBIUM(), Ids::ELEMENT_70);
- $this->mapSimple(Blocks::ELEMENT_YTTRIUM(), Ids::ELEMENT_39);
- $this->mapSimple(Blocks::ELEMENT_ZERO(), Ids::ELEMENT_0);
- $this->mapSimple(Blocks::ELEMENT_ZINC(), Ids::ELEMENT_30);
- $this->mapSimple(Blocks::ELEMENT_ZIRCONIUM(), Ids::ELEMENT_40);
- $this->mapSimple(Blocks::EMERALD(), Ids::EMERALD_BLOCK);
- $this->mapSimple(Blocks::EMERALD_ORE(), Ids::EMERALD_ORE);
- $this->mapSimple(Blocks::ENCHANTING_TABLE(), Ids::ENCHANTING_TABLE);
- $this->mapSimple(Blocks::END_STONE(), Ids::END_STONE);
- $this->mapSimple(Blocks::END_STONE_BRICKS(), Ids::END_BRICKS);
- $this->mapSimple(Blocks::FERN(), Ids::FERN);
- $this->mapSimple(Blocks::FLETCHING_TABLE(), Ids::FLETCHING_TABLE);
- $this->mapSimple(Blocks::GILDED_BLACKSTONE(), Ids::GILDED_BLACKSTONE);
- $this->mapSimple(Blocks::GLASS(), Ids::GLASS);
- $this->mapSimple(Blocks::GLASS_PANE(), Ids::GLASS_PANE);
- $this->mapSimple(Blocks::GLOWING_OBSIDIAN(), Ids::GLOWINGOBSIDIAN);
- $this->mapSimple(Blocks::GLOWSTONE(), Ids::GLOWSTONE);
- $this->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK);
- $this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE);
- $this->mapSimple(Blocks::GRANITE(), Ids::GRANITE);
- $this->mapSimple(Blocks::GRASS(), Ids::GRASS_BLOCK);
- $this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH);
- $this->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL);
- $this->mapSimple(Blocks::HANGING_ROOTS(), Ids::HANGING_ROOTS);
- $this->mapSimple(Blocks::HARDENED_CLAY(), Ids::HARDENED_CLAY);
- $this->mapSimple(Blocks::HARDENED_GLASS(), Ids::HARD_GLASS);
- $this->mapSimple(Blocks::HARDENED_GLASS_PANE(), Ids::HARD_GLASS_PANE);
- $this->mapSimple(Blocks::HONEYCOMB(), Ids::HONEYCOMB_BLOCK);
- $this->mapSimple(Blocks::ICE(), Ids::ICE);
- $this->mapSimple(Blocks::INFESTED_CHISELED_STONE_BRICK(), Ids::INFESTED_CHISELED_STONE_BRICKS);
- $this->mapSimple(Blocks::INFESTED_COBBLESTONE(), Ids::INFESTED_COBBLESTONE);
- $this->mapSimple(Blocks::INFESTED_CRACKED_STONE_BRICK(), Ids::INFESTED_CRACKED_STONE_BRICKS);
- $this->mapSimple(Blocks::INFESTED_MOSSY_STONE_BRICK(), Ids::INFESTED_MOSSY_STONE_BRICKS);
- $this->mapSimple(Blocks::INFESTED_STONE(), Ids::INFESTED_STONE);
- $this->mapSimple(Blocks::INFESTED_STONE_BRICK(), Ids::INFESTED_STONE_BRICKS);
- $this->mapSimple(Blocks::INFO_UPDATE(), Ids::INFO_UPDATE);
- $this->mapSimple(Blocks::INFO_UPDATE2(), Ids::INFO_UPDATE2);
- $this->mapSimple(Blocks::INVISIBLE_BEDROCK(), Ids::INVISIBLE_BEDROCK);
- $this->mapSimple(Blocks::IRON(), Ids::IRON_BLOCK);
- $this->mapSimple(Blocks::IRON_BARS(), Ids::IRON_BARS);
- $this->mapSimple(Blocks::IRON_ORE(), Ids::IRON_ORE);
- $this->mapSimple(Blocks::JUKEBOX(), Ids::JUKEBOX);
- $this->mapSimple(Blocks::LAPIS_LAZULI(), Ids::LAPIS_BLOCK);
- $this->mapSimple(Blocks::LAPIS_LAZULI_ORE(), Ids::LAPIS_ORE);
- $this->mapSimple(Blocks::LEGACY_STONECUTTER(), Ids::STONECUTTER);
- $this->mapSimple(Blocks::LILY_PAD(), Ids::WATERLILY);
- $this->mapSimple(Blocks::MAGMA(), Ids::MAGMA);
- $this->mapSimple(Blocks::MANGROVE_ROOTS(), Ids::MANGROVE_ROOTS);
- $this->mapSimple(Blocks::MELON(), Ids::MELON_BLOCK);
- $this->mapSimple(Blocks::MONSTER_SPAWNER(), Ids::MOB_SPAWNER);
- $this->mapSimple(Blocks::MOSSY_COBBLESTONE(), Ids::MOSSY_COBBLESTONE);
- $this->mapSimple(Blocks::MOSSY_STONE_BRICKS(), Ids::MOSSY_STONE_BRICKS);
- $this->mapSimple(Blocks::MUD(), Ids::MUD);
- $this->mapSimple(Blocks::MUD_BRICKS(), Ids::MUD_BRICKS);
- $this->mapSimple(Blocks::MYCELIUM(), Ids::MYCELIUM);
- $this->mapSimple(Blocks::NETHERITE(), Ids::NETHERITE_BLOCK);
- $this->mapSimple(Blocks::NETHERRACK(), Ids::NETHERRACK);
- $this->mapSimple(Blocks::NETHER_BRICKS(), Ids::NETHER_BRICK);
- $this->mapSimple(Blocks::NETHER_BRICK_FENCE(), Ids::NETHER_BRICK_FENCE);
- $this->mapSimple(Blocks::NETHER_GOLD_ORE(), Ids::NETHER_GOLD_ORE);
- $this->mapSimple(Blocks::NETHER_QUARTZ_ORE(), Ids::QUARTZ_ORE);
- $this->mapSimple(Blocks::NETHER_REACTOR_CORE(), Ids::NETHERREACTOR);
- $this->mapSimple(Blocks::NETHER_WART_BLOCK(), Ids::NETHER_WART_BLOCK);
- $this->mapSimple(Blocks::NOTE_BLOCK(), Ids::NOTEBLOCK);
- $this->mapSimple(Blocks::OBSIDIAN(), Ids::OBSIDIAN);
- $this->mapSimple(Blocks::PACKED_ICE(), Ids::PACKED_ICE);
- $this->mapSimple(Blocks::PACKED_MUD(), Ids::PACKED_MUD);
- $this->mapSimple(Blocks::PODZOL(), Ids::PODZOL);
- $this->mapSimple(Blocks::POLISHED_ANDESITE(), Ids::POLISHED_ANDESITE);
- $this->mapSimple(Blocks::POLISHED_BLACKSTONE(), Ids::POLISHED_BLACKSTONE);
- $this->mapSimple(Blocks::POLISHED_BLACKSTONE_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS);
- $this->mapSimple(Blocks::POLISHED_DEEPSLATE(), Ids::POLISHED_DEEPSLATE);
- $this->mapSimple(Blocks::POLISHED_DIORITE(), Ids::POLISHED_DIORITE);
- $this->mapSimple(Blocks::POLISHED_GRANITE(), Ids::POLISHED_GRANITE);
- $this->mapSimple(Blocks::POLISHED_TUFF(), Ids::POLISHED_TUFF);
- $this->mapSimple(Blocks::PRISMARINE(), Ids::PRISMARINE);
- $this->mapSimple(Blocks::PRISMARINE_BRICKS(), Ids::PRISMARINE_BRICKS);
- $this->mapSimple(Blocks::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS);
- $this->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK);
- $this->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK);
- $this->mapSimple(Blocks::RAW_IRON(), Ids::RAW_IRON_BLOCK);
- $this->mapSimple(Blocks::REDSTONE(), Ids::REDSTONE_BLOCK);
- $this->mapSimple(Blocks::RED_MUSHROOM(), Ids::RED_MUSHROOM);
- $this->mapSimple(Blocks::RED_NETHER_BRICKS(), Ids::RED_NETHER_BRICK);
- $this->mapSimple(Blocks::RED_SAND(), Ids::RED_SAND);
- $this->mapSimple(Blocks::RED_SANDSTONE(), Ids::RED_SANDSTONE);
- $this->mapSimple(Blocks::REINFORCED_DEEPSLATE(), Ids::REINFORCED_DEEPSLATE);
- $this->mapSimple(Blocks::RESERVED6(), Ids::RESERVED6);
- $this->mapSimple(Blocks::RESIN(), Ids::RESIN_BLOCK);
- $this->mapSimple(Blocks::RESIN_BRICKS(), Ids::RESIN_BRICKS);
- $this->mapSimple(Blocks::SAND(), Ids::SAND);
- $this->mapSimple(Blocks::SANDSTONE(), Ids::SANDSTONE);
- $this->mapSimple(Blocks::SCULK(), Ids::SCULK);
- $this->mapSimple(Blocks::SEA_LANTERN(), Ids::SEA_LANTERN);
- $this->mapSimple(Blocks::SHROOMLIGHT(), Ids::SHROOMLIGHT);
- $this->mapSimple(Blocks::SHULKER_BOX(), Ids::UNDYED_SHULKER_BOX);
- $this->mapSimple(Blocks::SLIME(), Ids::SLIME);
- $this->mapSimple(Blocks::SMITHING_TABLE(), Ids::SMITHING_TABLE);
- $this->mapSimple(Blocks::SMOOTH_BASALT(), Ids::SMOOTH_BASALT);
- $this->mapSimple(Blocks::SMOOTH_RED_SANDSTONE(), Ids::SMOOTH_RED_SANDSTONE);
- $this->mapSimple(Blocks::SMOOTH_SANDSTONE(), Ids::SMOOTH_SANDSTONE);
- $this->mapSimple(Blocks::SMOOTH_STONE(), Ids::SMOOTH_STONE);
- $this->mapSimple(Blocks::SNOW(), Ids::SNOW);
- $this->mapSimple(Blocks::SOUL_SAND(), Ids::SOUL_SAND);
- $this->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL);
- $this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM);
- $this->mapSimple(Blocks::STONE(), Ids::STONE);
- $this->mapSimple(Blocks::STONE_BRICKS(), Ids::STONE_BRICKS);
- $this->mapSimple(Blocks::TALL_GRASS(), Ids::SHORT_GRASS); //no, this is not a typo - tall_grass is now the double block, just to be confusing :(
- $this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS);
- $this->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER);
- $this->mapSimple(Blocks::TUFF(), Ids::TUFF);
- $this->mapSimple(Blocks::TUFF_BRICKS(), Ids::TUFF_BRICKS);
- $this->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK);
- $this->mapSimple(Blocks::WARPED_ROOTS(), Ids::WARPED_ROOTS);
- $this->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE);
-
- $this->mapSimple(Blocks::ALLIUM(), Ids::ALLIUM);
- $this->mapSimple(Blocks::CORNFLOWER(), Ids::CORNFLOWER);
- $this->mapSimple(Blocks::AZURE_BLUET(), Ids::AZURE_BLUET);
- $this->mapSimple(Blocks::LILY_OF_THE_VALLEY(), Ids::LILY_OF_THE_VALLEY);
- $this->mapSimple(Blocks::BLUE_ORCHID(), Ids::BLUE_ORCHID);
- $this->mapSimple(Blocks::OXEYE_DAISY(), Ids::OXEYE_DAISY);
- $this->mapSimple(Blocks::POPPY(), Ids::POPPY);
- $this->mapSimple(Blocks::ORANGE_TULIP(), Ids::ORANGE_TULIP);
- $this->mapSimple(Blocks::PINK_TULIP(), Ids::PINK_TULIP);
- $this->mapSimple(Blocks::RED_TULIP(), Ids::RED_TULIP);
- $this->mapSimple(Blocks::WHITE_TULIP(), Ids::WHITE_TULIP);
- }
-
- private function registerSerializers() : void{
- $this->map(Blocks::ACTIVATOR_RAIL(), function(ActivatorRail $block) : Writer{
- return Writer::create(Ids::ACTIVATOR_RAIL)
- ->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered())
- ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
- });
- $this->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM)
- ->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM));
- $this->map(Blocks::AMETHYST_CLUSTER(), fn(AmethystCluster $block) => Writer::create(
- match($stage = $block->getStage()){
- AmethystCluster::STAGE_SMALL_BUD => Ids::SMALL_AMETHYST_BUD,
- AmethystCluster::STAGE_MEDIUM_BUD => Ids::MEDIUM_AMETHYST_BUD,
- AmethystCluster::STAGE_LARGE_BUD => Ids::LARGE_AMETHYST_BUD,
- AmethystCluster::STAGE_CLUSTER => Ids::AMETHYST_CLUSTER,
- default => throw new BlockStateSerializeException("Invalid Amethyst Cluster stage $stage"),
- })
- ->writeBlockFace($block->getFacing())
- );
- $this->mapSlab(Blocks::ANDESITE_SLAB(), Ids::ANDESITE_SLAB, Ids::ANDESITE_DOUBLE_SLAB);
- $this->map(Blocks::ANDESITE_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::ANDESITE_STAIRS)));
- $this->map(Blocks::ANDESITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::ANDESITE_WALL)));
- $this->map(Blocks::ANVIL(), fn(Anvil $block) : Writer => Writer::create(
- match($damage = $block->getDamage()){
- 0 => Ids::ANVIL,
- 1 => Ids::CHIPPED_ANVIL,
- 2 => Ids::DAMAGED_ANVIL,
- default => throw new BlockStateSerializeException("Invalid Anvil damage {$damage}"),
- })
- ->writeCardinalHorizontalFacing($block->getFacing())
- );
- $this->map(Blocks::BAMBOO(), function(Bamboo $block) : Writer{
- return Writer::create(Ids::BAMBOO)
- ->writeBool(StateNames::AGE_BIT, $block->isReady())
- ->writeString(StateNames::BAMBOO_LEAF_SIZE, match($block->getLeafSize()){
- Bamboo::NO_LEAVES => StringValues::BAMBOO_LEAF_SIZE_NO_LEAVES,
- Bamboo::SMALL_LEAVES => StringValues::BAMBOO_LEAF_SIZE_SMALL_LEAVES,
- Bamboo::LARGE_LEAVES => StringValues::BAMBOO_LEAF_SIZE_LARGE_LEAVES,
- default => throw new BlockStateSerializeException("Invalid Bamboo leaf thickness " . $block->getLeafSize()),
- })
- ->writeString(StateNames::BAMBOO_STALK_THICKNESS, $block->isThick() ? StringValues::BAMBOO_STALK_THICKNESS_THICK : StringValues::BAMBOO_STALK_THICKNESS_THIN);
- });
- $this->map(Blocks::BAMBOO_SAPLING(), function(BambooSapling $block) : Writer{
- return Writer::create(Ids::BAMBOO_SAPLING)
- ->writeBool(StateNames::AGE_BIT, $block->isReady());
- });
- $this->map(Blocks::BANNER(), function(FloorBanner $block) : Writer{
- return Writer::create(Ids::STANDING_BANNER)
- ->writeInt(StateNames::GROUND_SIGN_DIRECTION, $block->getRotation());
- });
- $this->map(Blocks::BARREL(), function(Barrel $block) : Writer{
- return Writer::create(Ids::BARREL)
- ->writeBool(StateNames::OPEN_BIT, $block->isOpen())
- ->writeFacingDirection($block->getFacing());
- });
- $this->map(Blocks::BASALT(), function(SimplePillar $block) : Writer{
- return Writer::create(Ids::BASALT)
- ->writePillarAxis($block->getAxis());
- });
- $this->map(Blocks::BED(), function(Bed $block) : Writer{
- return Writer::create(Ids::BED)
- ->writeBool(StateNames::HEAD_PIECE_BIT, $block->isHeadPart())
- ->writeBool(StateNames::OCCUPIED_BIT, $block->isOccupied())
- ->writeLegacyHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::BEDROCK(), function(Block $block) : Writer{
- return Writer::create(Ids::BEDROCK)
- ->writeBool(StateNames::INFINIBURN_BIT, $block->burnsForever());
- });
- $this->map(Blocks::BEETROOTS(), fn(Beetroot $block) => Helper::encodeCrops($block, new Writer(Ids::BEETROOT)));
- $this->map(Blocks::BELL(), function(Bell $block) : Writer{
- return Writer::create(Ids::BELL)
- ->writeBellAttachmentType($block->getAttachmentType())
- ->writeBool(StateNames::TOGGLE_BIT, false) //we don't care about this; it's just to keep MCPE happy
- ->writeLegacyHorizontalFacing($block->getFacing());
-
- });
- $this->map(Blocks::BIG_DRIPLEAF_HEAD(), function(BigDripleafHead $block) : Writer{
- return Writer::create(Ids::BIG_DRIPLEAF)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeString(StateNames::BIG_DRIPLEAF_TILT, match($block->getLeafState()){
- DripleafState::STABLE => StringValues::BIG_DRIPLEAF_TILT_NONE,
- DripleafState::UNSTABLE => StringValues::BIG_DRIPLEAF_TILT_UNSTABLE,
- DripleafState::PARTIAL_TILT => StringValues::BIG_DRIPLEAF_TILT_PARTIAL_TILT,
- DripleafState::FULL_TILT => StringValues::BIG_DRIPLEAF_TILT_FULL_TILT,
- })
- ->writeBool(StateNames::BIG_DRIPLEAF_HEAD, true);
- });
- $this->map(Blocks::BIG_DRIPLEAF_STEM(), function(BigDripleafStem $block) : Writer{
- return Writer::create(Ids::BIG_DRIPLEAF)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeString(StateNames::BIG_DRIPLEAF_TILT, StringValues::BIG_DRIPLEAF_TILT_NONE)
- ->writeBool(StateNames::BIG_DRIPLEAF_HEAD, false);
- });
- $this->mapSlab(Blocks::BLACKSTONE_SLAB(), Ids::BLACKSTONE_SLAB, Ids::BLACKSTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::BLACKSTONE_STAIRS(), Ids::BLACKSTONE_STAIRS);
- $this->map(Blocks::BLACKSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::BLACKSTONE_WALL)));
- $this->map(Blocks::BLAST_FURNACE(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::BLAST_FURNACE, Ids::LIT_BLAST_FURNACE));
- $this->map(Blocks::BLUE_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_BLUE)));
- $this->map(Blocks::BONE_BLOCK(), function(BoneBlock $block) : Writer{
- return Writer::create(Ids::BONE_BLOCK)
- ->writeInt(StateNames::DEPRECATED, 0)
- ->writePillarAxis($block->getAxis());
- });
- $this->map(Blocks::BREWING_STAND(), function(BrewingStand $block) : Writer{
- return Writer::create(Ids::BREWING_STAND)
- ->writeBool(StateNames::BREWING_STAND_SLOT_A_BIT, $block->hasSlot(BrewingStandSlot::EAST))
- ->writeBool(StateNames::BREWING_STAND_SLOT_B_BIT, $block->hasSlot(BrewingStandSlot::SOUTHWEST))
- ->writeBool(StateNames::BREWING_STAND_SLOT_C_BIT, $block->hasSlot(BrewingStandSlot::NORTHWEST));
- });
- $this->mapSlab(Blocks::BRICK_SLAB(), Ids::BRICK_SLAB, Ids::BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::BRICK_STAIRS(), Ids::BRICK_STAIRS);
- $this->map(Blocks::BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::BRICK_WALL)));
- $this->map(Blocks::BROWN_MUSHROOM_BLOCK(), fn(BrownMushroomBlock $block) => Helper::encodeMushroomBlock($block, new Writer(Ids::BROWN_MUSHROOM_BLOCK)));
- $this->map(Blocks::CACTUS(), function(Cactus $block) : Writer{
- return Writer::create(Ids::CACTUS)
- ->writeInt(StateNames::AGE, $block->getAge());
- });
- $this->map(Blocks::CAKE(), function(Cake $block) : Writer{
- return Writer::create(Ids::CAKE)
- ->writeInt(StateNames::BITE_COUNTER, $block->getBites());
- });
- $this->map(Blocks::CAMPFIRE(), function(Campfire $block) : Writer{
- return Writer::create(Ids::CAMPFIRE)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeBool(StateNames::EXTINGUISHED, !$block->isLit());
- });
- $this->map(Blocks::CARROTS(), fn(Carrot $block) => Helper::encodeCrops($block, new Writer(Ids::CARROTS)));
- $this->map(Blocks::CARVED_PUMPKIN(), function(CarvedPumpkin $block) : Writer{
- return Writer::create(Ids::CARVED_PUMPKIN)
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::CAVE_VINES(), function(CaveVines $block) : Writer{
- //I have no idea why this only has 3 IDs - there are 4 in Java and 4 visually distinct states in Bedrock
- return Writer::create($block->hasBerries() ?
- ($block->isHead() ?
- Ids::CAVE_VINES_HEAD_WITH_BERRIES :
- Ids::CAVE_VINES_BODY_WITH_BERRIES
- ) :
- Ids::CAVE_VINES
- )
- ->writeInt(StateNames::GROWING_PLANT_AGE, $block->getAge());
- });
- $this->map(Blocks::CHAIN(), function(Chain $block) : Writer{
- return Writer::create(Ids::CHAIN)
- ->writePillarAxis($block->getAxis());
- });
- $this->map(Blocks::CHEST(), function(Chest $block) : Writer{
- return Writer::create(Ids::CHEST)
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::CHISELED_BOOKSHELF(), function(ChiseledBookshelf $block) : Writer{
- $flags = 0;
- foreach($block->getSlots() as $slot){
- $flags |= 1 << $slot->value;
- }
- return Writer::create(Ids::CHISELED_BOOKSHELF)
- ->writeLegacyHorizontalFacing($block->getFacing())
- ->writeInt(StateNames::BOOKS_STORED, $flags);
- });
- $this->map(Blocks::CHISELED_QUARTZ(), fn(SimplePillar $block) => Helper::encodeQuartz($block->getAxis(), Writer::create(Ids::CHISELED_QUARTZ_BLOCK)));
- $this->map(Blocks::CHORUS_FLOWER(), function(ChorusFlower $block) : Writer{
- return Writer::create(Ids::CHORUS_FLOWER)
- ->writeInt(StateNames::AGE, $block->getAge());
- });
- $this->mapSlab(Blocks::COBBLED_DEEPSLATE_SLAB(), Ids::COBBLED_DEEPSLATE_SLAB, Ids::COBBLED_DEEPSLATE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::COBBLED_DEEPSLATE_STAIRS(), Ids::COBBLED_DEEPSLATE_STAIRS);
- $this->map(Blocks::COBBLED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::COBBLED_DEEPSLATE_WALL)));
- $this->mapSlab(Blocks::COBBLESTONE_SLAB(), Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
- $this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL)));
- $this->map(Blocks::COCOA_POD(), function(CocoaBlock $block) : Writer{
- return Writer::create(Ids::COCOA)
- ->writeInt(StateNames::AGE, $block->getAge())
- ->writeLegacyHorizontalFacing(Facing::opposite($block->getFacing()));
- });
- $this->map(Blocks::COMPOUND_CREATOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::COMPOUND_CREATOR)));
- $this->mapSlab(Blocks::CUT_RED_SANDSTONE_SLAB(), Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB);
- $this->mapSlab(Blocks::CUT_SANDSTONE_SLAB(), Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB);
- $this->mapSlab(Blocks::DARK_PRISMARINE_SLAB(), Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::DARK_PRISMARINE_STAIRS(), Ids::DARK_PRISMARINE_STAIRS);
- $this->map(Blocks::DAYLIGHT_SENSOR(), function(DaylightSensor $block) : Writer{
- return Writer::create($block->isInverted() ? Ids::DAYLIGHT_DETECTOR_INVERTED : Ids::DAYLIGHT_DETECTOR)
- ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
- });
- $this->map(Blocks::DEEPSLATE(), function(SimplePillar $block) : Writer{
- return Writer::create(Ids::DEEPSLATE)
- ->writePillarAxis($block->getAxis());
- });
- $this->mapSlab(Blocks::DEEPSLATE_BRICK_SLAB(), Ids::DEEPSLATE_BRICK_SLAB, Ids::DEEPSLATE_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::DEEPSLATE_BRICK_STAIRS(), Ids::DEEPSLATE_BRICK_STAIRS);
- $this->map(Blocks::DEEPSLATE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::DEEPSLATE_BRICK_WALL)));
- $this->map(Blocks::DEEPSLATE_REDSTONE_ORE(), fn(RedstoneOre $block) => new Writer($block->isLit() ? Ids::LIT_DEEPSLATE_REDSTONE_ORE : Ids::DEEPSLATE_REDSTONE_ORE));
- $this->mapSlab(Blocks::DEEPSLATE_TILE_SLAB(), Ids::DEEPSLATE_TILE_SLAB, Ids::DEEPSLATE_TILE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::DEEPSLATE_TILE_STAIRS(), Ids::DEEPSLATE_TILE_STAIRS);
- $this->map(Blocks::DEEPSLATE_TILE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::DEEPSLATE_TILE_WALL)));
- $this->map(Blocks::DETECTOR_RAIL(), function(DetectorRail $block) : Writer{
- return Writer::create(Ids::DETECTOR_RAIL)
- ->writeBool(StateNames::RAIL_DATA_BIT, $block->isActivated())
- ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
- });
- $this->mapSlab(Blocks::DIORITE_SLAB(), Ids::DIORITE_SLAB, Ids::DIORITE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS);
- $this->map(Blocks::DIORITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::DIORITE_WALL)));
- $this->map(Blocks::DIRT(), fn(Dirt $block) => BlockStateData::current(match($block->getDirtType()){
- DirtType::NORMAL => Ids::DIRT,
- DirtType::COARSE => Ids::COARSE_DIRT,
- DirtType::ROOTED => Ids::DIRT_WITH_ROOTS,
- }, []));
- $this->map(Blocks::DOUBLE_TALLGRASS(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::TALL_GRASS)));
- $this->map(Blocks::ELEMENT_CONSTRUCTOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::ELEMENT_CONSTRUCTOR)));
- $this->map(Blocks::ENDER_CHEST(), function(EnderChest $block) : Writer{
- return Writer::create(Ids::ENDER_CHEST)
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::END_PORTAL_FRAME(), function(EndPortalFrame $block) : Writer{
- return Writer::create(Ids::END_PORTAL_FRAME)
- ->writeBool(StateNames::END_PORTAL_EYE_BIT, $block->hasEye())
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::END_ROD(), function(EndRod $block) : Writer{
- return Writer::create(Ids::END_ROD)
- ->writeEndRodFacingDirection($block->getFacing());
- });
- $this->mapSlab(Blocks::END_STONE_BRICK_SLAB(), Ids::END_STONE_BRICK_SLAB, Ids::END_STONE_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::END_STONE_BRICK_STAIRS(), Ids::END_BRICK_STAIRS);
- $this->map(Blocks::END_STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::END_STONE_BRICK_WALL)));
- $this->mapSlab(Blocks::FAKE_WOODEN_SLAB(), Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB);
- $this->map(Blocks::FARMLAND(), function(Farmland $block) : Writer{
- return Writer::create(Ids::FARMLAND)
- ->writeInt(StateNames::MOISTURIZED_AMOUNT, $block->getWetness());
- });
- $this->map(Blocks::FIRE(), function(Fire $block) : Writer{
- return Writer::create(Ids::FIRE)
- ->writeInt(StateNames::AGE, $block->getAge());
- });
- $this->map(Blocks::FLOWER_POT(), Writer::create(Ids::FLOWER_POT)
- ->writeBool(StateNames::UPDATE_BIT, false) //to keep MCPE happy
- );
- $this->map(Blocks::FROGLIGHT(), function(Froglight $block){
- return Writer::create(match($block->getFroglightType()){
- FroglightType::OCHRE => Ids::OCHRE_FROGLIGHT,
- FroglightType::PEARLESCENT => Ids::PEARLESCENT_FROGLIGHT,
- FroglightType::VERDANT => Ids::VERDANT_FROGLIGHT,
- })
- ->writePillarAxis($block->getAxis());
- });
- $this->map(Blocks::FROSTED_ICE(), function(FrostedIce $block) : Writer{
- return Writer::create(Ids::FROSTED_ICE)
- ->writeInt(StateNames::AGE, $block->getAge());
- });
- $this->map(Blocks::FURNACE(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::FURNACE, Ids::LIT_FURNACE));
- $this->map(Blocks::GLOW_LICHEN(), function(GlowLichen $block) : Writer{
- return Writer::create(Ids::GLOW_LICHEN)
- ->writeFacingFlags($block->getFaces());
- });
- $this->map(Blocks::GLOWING_ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::GLOW_FRAME));
- $this->mapSlab(Blocks::GRANITE_SLAB(), Ids::GRANITE_SLAB, Ids::GRANITE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS);
- $this->map(Blocks::GRANITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::GRANITE_WALL)));
- $this->map(Blocks::GREEN_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_GREEN)));
- $this->map(Blocks::HAY_BALE(), function(HayBale $block) : Writer{
- return Writer::create(Ids::HAY_BLOCK)
- ->writeInt(StateNames::DEPRECATED, 0)
- ->writePillarAxis($block->getAxis());
- });
- $this->map(Blocks::HOPPER(), function(Hopper $block) : Writer{
- return Writer::create(Ids::HOPPER)
- ->writeBool(StateNames::TOGGLE_BIT, $block->isPowered())
- ->writeFacingWithoutUp($block->getFacing());
- });
- $this->map(Blocks::IRON_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::IRON_DOOR)));
- $this->map(Blocks::IRON_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::IRON_TRAPDOOR)));
- $this->map(Blocks::ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::FRAME));
- $this->map(Blocks::LAB_TABLE(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::LAB_TABLE)));
- $this->map(Blocks::LADDER(), function(Ladder $block) : Writer{
- return Writer::create(Ids::LADDER)
- ->writeHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::LANTERN(), function(Lantern $block) : Writer{
- return Writer::create(Ids::LANTERN)
- ->writeBool(StateNames::HANGING, $block->isHanging());
- });
- $this->map(Blocks::LARGE_FERN(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::LARGE_FERN)));
- $this->map(Blocks::LAVA(), fn(Lava $block) => Helper::encodeLiquid($block, Ids::LAVA, Ids::FLOWING_LAVA));
- $this->map(Blocks::LECTERN(), function(Lectern $block) : Writer{
- return Writer::create(Ids::LECTERN)
- ->writeBool(StateNames::POWERED_BIT, $block->isProducingSignal())
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::LEVER(), function(Lever $block) : Writer{
- return Writer::create(Ids::LEVER)
- ->writeBool(StateNames::OPEN_BIT, $block->isActivated())
- ->writeString(StateNames::LEVER_DIRECTION, match($block->getFacing()){
- LeverFacing::DOWN_AXIS_Z => StringValues::LEVER_DIRECTION_DOWN_NORTH_SOUTH,
- LeverFacing::DOWN_AXIS_X => StringValues::LEVER_DIRECTION_DOWN_EAST_WEST,
- LeverFacing::UP_AXIS_Z => StringValues::LEVER_DIRECTION_UP_NORTH_SOUTH,
- LeverFacing::UP_AXIS_X => StringValues::LEVER_DIRECTION_UP_EAST_WEST,
- LeverFacing::NORTH => StringValues::LEVER_DIRECTION_NORTH,
- LeverFacing::SOUTH => StringValues::LEVER_DIRECTION_SOUTH,
- LeverFacing::WEST => StringValues::LEVER_DIRECTION_WEST,
- LeverFacing::EAST => StringValues::LEVER_DIRECTION_EAST,
- });
- });
- $this->map(Blocks::LIGHT(), fn(Light $block) => BlockStateData::current(match($block->getLightLevel()){
- 0 => Ids::LIGHT_BLOCK_0,
- 1 => Ids::LIGHT_BLOCK_1,
- 2 => Ids::LIGHT_BLOCK_2,
- 3 => Ids::LIGHT_BLOCK_3,
- 4 => Ids::LIGHT_BLOCK_4,
- 5 => Ids::LIGHT_BLOCK_5,
- 6 => Ids::LIGHT_BLOCK_6,
- 7 => Ids::LIGHT_BLOCK_7,
- 8 => Ids::LIGHT_BLOCK_8,
- 9 => Ids::LIGHT_BLOCK_9,
- 10 => Ids::LIGHT_BLOCK_10,
- 11 => Ids::LIGHT_BLOCK_11,
- 12 => Ids::LIGHT_BLOCK_12,
- 13 => Ids::LIGHT_BLOCK_13,
- 14 => Ids::LIGHT_BLOCK_14,
- 15 => Ids::LIGHT_BLOCK_15,
- default => throw new BlockStateSerializeException("Invalid light level " . $block->getLightLevel()),
- }, []));
- $this->map(Blocks::LIGHTNING_ROD(), function(LightningRod $block) : Writer{
- return Writer::create(Ids::LIGHTNING_ROD)
- ->writeFacingDirection($block->getFacing());
- });
- $this->map(Blocks::LILAC(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::LILAC)));
- $this->map(Blocks::LIT_PUMPKIN(), function(LitPumpkin $block) : Writer{
- return Writer::create(Ids::LIT_PUMPKIN)
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::LOOM(), function(Loom $block) : Writer{
- return Writer::create(Ids::LOOM)
- ->writeLegacyHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::MATERIAL_REDUCER(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::MATERIAL_REDUCER)));
- $this->map(Blocks::MELON_STEM(), fn(MelonStem $block) => Helper::encodeStem($block, new Writer(Ids::MELON_STEM)));
- $this->mapSlab(Blocks::MOSSY_COBBLESTONE_SLAB(), Ids::MOSSY_COBBLESTONE_SLAB, Ids::MOSSY_COBBLESTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::MOSSY_COBBLESTONE_STAIRS(), Ids::MOSSY_COBBLESTONE_STAIRS);
- $this->map(Blocks::MOSSY_COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::MOSSY_COBBLESTONE_WALL)));
- $this->mapSlab(Blocks::MOSSY_STONE_BRICK_SLAB(), Ids::MOSSY_STONE_BRICK_SLAB, Ids::MOSSY_STONE_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::MOSSY_STONE_BRICK_STAIRS(), Ids::MOSSY_STONE_BRICK_STAIRS);
- $this->map(Blocks::MOSSY_STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::MOSSY_STONE_BRICK_WALL)));
- $this->mapSlab(Blocks::MUD_BRICK_SLAB(), Ids::MUD_BRICK_SLAB, Ids::MUD_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::MUD_BRICK_STAIRS(), Ids::MUD_BRICK_STAIRS);
- $this->map(Blocks::MUD_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::MUD_BRICK_WALL)));
- $this->map(Blocks::MUDDY_MANGROVE_ROOTS(), fn(SimplePillar $block) => Writer::create(Ids::MUDDY_MANGROVE_ROOTS)
- ->writePillarAxis($block->getAxis()));
- $this->map(Blocks::MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM)
- ->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_STEM));
- $this->mapSlab(Blocks::NETHER_BRICK_SLAB(), Ids::NETHER_BRICK_SLAB, Ids::NETHER_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::NETHER_BRICK_STAIRS(), Ids::NETHER_BRICK_STAIRS);
- $this->map(Blocks::NETHER_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::NETHER_BRICK_WALL)));
- $this->map(Blocks::NETHER_PORTAL(), function(NetherPortal $block) : Writer{
- return Writer::create(Ids::PORTAL)
- ->writeString(StateNames::PORTAL_AXIS, match($block->getAxis()){
- Axis::X => StringValues::PORTAL_AXIS_X,
- Axis::Z => StringValues::PORTAL_AXIS_Z,
- default => throw new BlockStateSerializeException("Invalid Nether Portal axis " . $block->getAxis()),
- });
- });
- $this->map(Blocks::NETHER_WART(), function(NetherWartPlant $block) : Writer{
- return Writer::create(Ids::NETHER_WART)
- ->writeInt(StateNames::AGE, $block->getAge());
- });
- $this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::PEONY)));
- $this->map(Blocks::PINK_PETALS(), function(PinkPetals $block) : Writer{
- return Writer::create(Ids::PINK_PETALS)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeInt(StateNames::GROWTH, $block->getCount() - 1);
- });
- $this->map(Blocks::PITCHER_PLANT(), function(DoublePlant $block) : Writer{
- return Writer::create(Ids::PITCHER_PLANT)
- ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
- });
- $this->map(Blocks::PITCHER_CROP(), function(PitcherCrop $block) : Writer{
- return Writer::create(Ids::PITCHER_CROP)
- ->writeInt(StateNames::GROWTH, $block->getAge())
- ->writeBool(StateNames::UPPER_BLOCK_BIT, false);
- });
- $this->map(Blocks::DOUBLE_PITCHER_CROP(), function(DoublePitcherCrop $block) : Writer{
- return Writer::create(Ids::PITCHER_CROP)
- ->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE)
- ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
- });
- $this->mapSlab(Blocks::POLISHED_ANDESITE_SLAB(), Ids::POLISHED_ANDESITE_SLAB, Ids::POLISHED_ANDESITE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS);
- $this->map(Blocks::POLISHED_BASALT(), function(SimplePillar $block) : Writer{
- return Writer::create(Ids::POLISHED_BASALT)
- ->writePillarAxis($block->getAxis());
- });
- $this->mapSlab(Blocks::POLISHED_BLACKSTONE_BRICK_SLAB(), Ids::POLISHED_BLACKSTONE_BRICK_SLAB, Ids::POLISHED_BLACKSTONE_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_BLACKSTONE_BRICK_STAIRS(), Ids::POLISHED_BLACKSTONE_BRICK_STAIRS);
- $this->map(Blocks::POLISHED_BLACKSTONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_BLACKSTONE_BRICK_WALL)));
- $this->map(Blocks::POLISHED_BLACKSTONE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::POLISHED_BLACKSTONE_BUTTON)));
- $this->map(Blocks::POLISHED_BLACKSTONE_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE)));
- $this->mapSlab(Blocks::POLISHED_BLACKSTONE_SLAB(), Ids::POLISHED_BLACKSTONE_SLAB, Ids::POLISHED_BLACKSTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_BLACKSTONE_STAIRS(), Ids::POLISHED_BLACKSTONE_STAIRS);
- $this->map(Blocks::POLISHED_BLACKSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_BLACKSTONE_WALL)));
- $this->mapSlab(Blocks::POLISHED_DEEPSLATE_SLAB(), Ids::POLISHED_DEEPSLATE_SLAB, Ids::POLISHED_DEEPSLATE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_DEEPSLATE_STAIRS(), Ids::POLISHED_DEEPSLATE_STAIRS);
- $this->map(Blocks::POLISHED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_DEEPSLATE_WALL)));
- $this->mapSlab(Blocks::POLISHED_DIORITE_SLAB(), Ids::POLISHED_DIORITE_SLAB, Ids::POLISHED_DIORITE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS);
- $this->mapSlab(Blocks::POLISHED_GRANITE_SLAB(), Ids::POLISHED_GRANITE_SLAB, Ids::POLISHED_GRANITE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS);
- $this->mapSlab(Blocks::POLISHED_TUFF_SLAB(), Ids::POLISHED_TUFF_SLAB, Ids::POLISHED_TUFF_DOUBLE_SLAB);
- $this->mapStairs(Blocks::POLISHED_TUFF_STAIRS(), Ids::POLISHED_TUFF_STAIRS);
- $this->map(Blocks::POLISHED_TUFF_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_TUFF_WALL)));
- $this->map(Blocks::POTATOES(), fn(Potato $block) => Helper::encodeCrops($block, new Writer(Ids::POTATOES)));
- $this->map(Blocks::POWERED_RAIL(), function(PoweredRail $block) : Writer{
- return Writer::create(Ids::GOLDEN_RAIL)
- ->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered())
- ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
- });
- $this->mapSlab(Blocks::PRISMARINE_BRICKS_SLAB(), Ids::PRISMARINE_BRICK_SLAB, Ids::PRISMARINE_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::PRISMARINE_BRICKS_STAIRS(), Ids::PRISMARINE_BRICKS_STAIRS);
- $this->mapSlab(Blocks::PRISMARINE_SLAB(), Ids::PRISMARINE_SLAB, Ids::PRISMARINE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::PRISMARINE_STAIRS(), Ids::PRISMARINE_STAIRS);
- $this->map(Blocks::PRISMARINE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::PRISMARINE_WALL)));
- $this->map(Blocks::PUMPKIN(), Writer::create(Ids::PUMPKIN)
- ->writeCardinalHorizontalFacing(Facing::SOUTH) //no longer used
- );
- $this->map(Blocks::PUMPKIN_STEM(), fn(PumpkinStem $block) => Helper::encodeStem($block, new Writer(Ids::PUMPKIN_STEM)));
- $this->map(Blocks::PURPUR(), Writer::create(Ids::PURPUR_BLOCK)->writePillarAxis(Axis::Y));
- $this->map(Blocks::PURPLE_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_PURPLE)));
- $this->map(Blocks::PURPUR_PILLAR(), function(SimplePillar $block) : Writer{
- return Writer::create(Ids::PURPUR_PILLAR)
- ->writePillarAxis($block->getAxis());
- });
- $this->mapSlab(Blocks::PURPUR_SLAB(), Ids::PURPUR_SLAB, Ids::PURPUR_DOUBLE_SLAB);
- $this->mapStairs(Blocks::PURPUR_STAIRS(), Ids::PURPUR_STAIRS);
- $this->map(Blocks::QUARTZ(), Helper::encodeQuartz(Axis::Y, Writer::create(Ids::QUARTZ_BLOCK)));
- $this->map(Blocks::QUARTZ_PILLAR(), fn(SimplePillar $block) => Helper::encodeQuartz($block->getAxis(), Writer::create(Ids::QUARTZ_PILLAR)));
- $this->mapSlab(Blocks::QUARTZ_SLAB(), Ids::QUARTZ_SLAB, Ids::QUARTZ_DOUBLE_SLAB);
- $this->mapStairs(Blocks::QUARTZ_STAIRS(), Ids::QUARTZ_STAIRS);
- $this->map(Blocks::RAIL(), function(Rail $block) : Writer{
- return Writer::create(Ids::RAIL)
- ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
- });
- $this->map(Blocks::REDSTONE_COMPARATOR(), function(RedstoneComparator $block) : Writer{
- return Writer::create($block->isPowered() ? Ids::POWERED_COMPARATOR : Ids::UNPOWERED_COMPARATOR)
- ->writeBool(StateNames::OUTPUT_LIT_BIT, $block->isPowered())
- ->writeBool(StateNames::OUTPUT_SUBTRACT_BIT, $block->isSubtractMode())
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::REDSTONE_LAMP(), fn(RedstoneLamp $block) => new Writer($block->isPowered() ? Ids::LIT_REDSTONE_LAMP : Ids::REDSTONE_LAMP));
- $this->map(Blocks::REDSTONE_ORE(), fn(RedstoneOre $block) => new Writer($block->isLit() ? Ids::LIT_REDSTONE_ORE : Ids::REDSTONE_ORE));
- $this->map(Blocks::REDSTONE_REPEATER(), function(RedstoneRepeater $block) : Writer{
- return Writer::create($block->isPowered() ? Ids::POWERED_REPEATER : Ids::UNPOWERED_REPEATER)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeInt(StateNames::REPEATER_DELAY, $block->getDelay() - 1);
- });
- $this->map(Blocks::REDSTONE_TORCH(), function(RedstoneTorch $block) : Writer{
- return Writer::create($block->isLit() ? Ids::REDSTONE_TORCH : Ids::UNLIT_REDSTONE_TORCH)
- ->writeTorchFacing($block->getFacing());
- });
- $this->map(Blocks::REDSTONE_WIRE(), function(RedstoneWire $block) : Writer{
- return Writer::create(Ids::REDSTONE_WIRE)
- ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
- });
- $this->map(Blocks::RED_MUSHROOM_BLOCK(), fn(RedMushroomBlock $block) => Helper::encodeMushroomBlock($block, new Writer(Ids::RED_MUSHROOM_BLOCK)));
- $this->mapSlab(Blocks::RED_NETHER_BRICK_SLAB(), Ids::RED_NETHER_BRICK_SLAB, Ids::RED_NETHER_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::RED_NETHER_BRICK_STAIRS(), Ids::RED_NETHER_BRICK_STAIRS);
- $this->map(Blocks::RED_NETHER_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::RED_NETHER_BRICK_WALL)));
- $this->mapSlab(Blocks::RED_SANDSTONE_SLAB(), Ids::RED_SANDSTONE_SLAB, Ids::RED_SANDSTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::RED_SANDSTONE_STAIRS(), Ids::RED_SANDSTONE_STAIRS);
- $this->map(Blocks::RED_SANDSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::RED_SANDSTONE_WALL)));
- $this->map(Blocks::RED_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_RED)));
- $this->mapSlab(Blocks::RESIN_BRICK_SLAB(), Ids::RESIN_BRICK_SLAB, Ids::RESIN_BRICK_DOUBLE_SLAB);
- $this->map(Blocks::RESIN_BRICK_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::RESIN_BRICK_STAIRS)));
- $this->map(Blocks::RESIN_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::RESIN_BRICK_WALL)));
- $this->map(Blocks::RESIN_CLUMP(), function(ResinClump $block) : Writer{
- return Writer::create(Ids::RESIN_CLUMP)
- ->writeFacingFlags($block->getFaces());
- });
- $this->map(Blocks::RESPAWN_ANCHOR(), function(RespawnAnchor $block) : Writer{
- return Writer::create(Ids::RESPAWN_ANCHOR)
- ->writeInt(StateNames::RESPAWN_ANCHOR_CHARGE, $block->getCharges());
- });
- $this->map(Blocks::ROSE_BUSH(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::ROSE_BUSH)));
- $this->mapSlab(Blocks::SANDSTONE_SLAB(), Ids::SANDSTONE_SLAB, Ids::SANDSTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::SANDSTONE_STAIRS(), Ids::SANDSTONE_STAIRS);
- $this->map(Blocks::SANDSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::SANDSTONE_WALL)));
- $this->map(Blocks::SEA_PICKLE(), function(SeaPickle $block) : Writer{
- return Writer::create(Ids::SEA_PICKLE)
- ->writeBool(StateNames::DEAD_BIT, !$block->isUnderwater())
- ->writeInt(StateNames::CLUSTER_COUNT, $block->getCount() - 1);
- });
- $this->map(Blocks::SMALL_DRIPLEAF(), function(SmallDripleaf $block) : Writer{
- return Writer::create(Ids::SMALL_DRIPLEAF_BLOCK)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
- });
- $this->map(Blocks::SMOKER(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::SMOKER, Ids::LIT_SMOKER));
- $this->map(Blocks::SMOOTH_QUARTZ(), Helper::encodeQuartz(Axis::Y, Writer::create(Ids::SMOOTH_QUARTZ)));
- $this->mapSlab(Blocks::SMOOTH_QUARTZ_SLAB(), Ids::SMOOTH_QUARTZ_SLAB, Ids::SMOOTH_QUARTZ_DOUBLE_SLAB);
- $this->mapStairs(Blocks::SMOOTH_QUARTZ_STAIRS(), Ids::SMOOTH_QUARTZ_STAIRS);
- $this->mapSlab(Blocks::SMOOTH_RED_SANDSTONE_SLAB(), Ids::SMOOTH_RED_SANDSTONE_SLAB, Ids::SMOOTH_RED_SANDSTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::SMOOTH_RED_SANDSTONE_STAIRS(), Ids::SMOOTH_RED_SANDSTONE_STAIRS);
- $this->mapSlab(Blocks::SMOOTH_SANDSTONE_SLAB(), Ids::SMOOTH_SANDSTONE_SLAB, Ids::SMOOTH_SANDSTONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::SMOOTH_SANDSTONE_STAIRS(), Ids::SMOOTH_SANDSTONE_STAIRS);
- $this->mapSlab(Blocks::SMOOTH_STONE_SLAB(), Ids::SMOOTH_STONE_SLAB, Ids::SMOOTH_STONE_DOUBLE_SLAB);
- $this->map(Blocks::SNOW_LAYER(), function(SnowLayer $block) : Writer{
- return Writer::create(Ids::SNOW_LAYER)
- ->writeBool(StateNames::COVERED_BIT, false)
- ->writeInt(StateNames::HEIGHT, $block->getLayers() - 1);
- });
- $this->map(Blocks::SOUL_CAMPFIRE(), function(SoulCampfire $block) : Writer{
- return Writer::create(Ids::SOUL_CAMPFIRE)
- ->writeCardinalHorizontalFacing($block->getFacing())
- ->writeBool(StateNames::EXTINGUISHED, !$block->isLit());
- });
- $this->map(Blocks::SOUL_FIRE(), Writer::create(Ids::SOUL_FIRE)
- ->writeInt(StateNames::AGE, 0) //useless for soul fire, we don't track it
- );
- $this->map(Blocks::SOUL_LANTERN(), function(Lantern $block) : Writer{
- return Writer::create(Ids::SOUL_LANTERN)
- ->writeBool(StateNames::HANGING, $block->isHanging());
- });
- $this->map(Blocks::SOUL_TORCH(), function(Torch $block) : Writer{
- return Writer::create(Ids::SOUL_TORCH)
- ->writeTorchFacing($block->getFacing());
- });
- $this->map(Blocks::SPONGE(), fn(Sponge $block) => Writer::create($block->isWet() ? Ids::WET_SPONGE : Ids::SPONGE));
- $this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK)
- ->writeCardinalHorizontalFacing($block->getFacing()));
- $this->mapSlab(Blocks::STONE_BRICK_SLAB(), Ids::STONE_BRICK_SLAB, Ids::STONE_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::STONE_BRICK_STAIRS(), Ids::STONE_BRICK_STAIRS);
- $this->map(Blocks::STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::STONE_BRICK_WALL)));
- $this->map(Blocks::STONE_BUTTON(), fn(StoneButton $block) => Helper::encodeButton($block, new Writer(Ids::STONE_BUTTON)));
- $this->map(Blocks::STONE_PRESSURE_PLATE(), fn(StonePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::STONE_PRESSURE_PLATE)));
- $this->mapSlab(Blocks::STONE_SLAB(), Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB);
- $this->mapStairs(Blocks::STONE_STAIRS(), Ids::NORMAL_STONE_STAIRS);
- $this->map(Blocks::SUGARCANE(), function(Sugarcane $block) : Writer{
- return Writer::create(Ids::REEDS)
- ->writeInt(StateNames::AGE, $block->getAge());
- });
- $this->map(Blocks::SUNFLOWER(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::SUNFLOWER)));
- $this->map(Blocks::SWEET_BERRY_BUSH(), function(SweetBerryBush $block) : Writer{
- return Writer::create(Ids::SWEET_BERRY_BUSH)
- ->writeInt(StateNames::GROWTH, $block->getAge());
- });
- $this->map(Blocks::TNT(), fn(TNT $block) => Writer::create($block->worksUnderwater() ? Ids::UNDERWATER_TNT : Ids::TNT)
- ->writeBool(StateNames::EXPLODE_BIT, $block->isUnstable())
- );
- $this->map(Blocks::TORCH(), function(Torch $block) : Writer{
- return Writer::create(Ids::TORCH)
- ->writeTorchFacing($block->getFacing());
- });
- $this->map(Blocks::TORCHFLOWER_CROP(), function(TorchflowerCrop $block){
- return Writer::create(Ids::TORCHFLOWER_CROP)
- ->writeInt(StateNames::GROWTH, $block->isReady() ? 1 : 0);
- });
- $this->map(Blocks::TRAPPED_CHEST(), function(TrappedChest $block) : Writer{
- return Writer::create(Ids::TRAPPED_CHEST)
- ->writeCardinalHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::TRIPWIRE(), function(Tripwire $block) : Writer{
- return Writer::create(Ids::TRIP_WIRE)
- ->writeBool(StateNames::ATTACHED_BIT, $block->isConnected())
- ->writeBool(StateNames::DISARMED_BIT, $block->isDisarmed())
- ->writeBool(StateNames::POWERED_BIT, $block->isTriggered())
- ->writeBool(StateNames::SUSPENDED_BIT, $block->isSuspended());
- });
- $this->map(Blocks::TRIPWIRE_HOOK(), function(TripwireHook $block) : Writer{
- return Writer::create(Ids::TRIPWIRE_HOOK)
- ->writeBool(StateNames::ATTACHED_BIT, $block->isConnected())
- ->writeBool(StateNames::POWERED_BIT, $block->isPowered())
- ->writeLegacyHorizontalFacing($block->getFacing());
- });
- $this->mapSlab(Blocks::TUFF_BRICK_SLAB(), Ids::TUFF_BRICK_SLAB, Ids::TUFF_BRICK_DOUBLE_SLAB);
- $this->mapStairs(Blocks::TUFF_BRICK_STAIRS(), Ids::TUFF_BRICK_STAIRS);
- $this->map(Blocks::TUFF_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::TUFF_BRICK_WALL)));
- $this->mapSlab(Blocks::TUFF_SLAB(), Ids::TUFF_SLAB, Ids::TUFF_DOUBLE_SLAB);
- $this->mapStairs(Blocks::TUFF_STAIRS(), Ids::TUFF_STAIRS);
- $this->map(Blocks::TUFF_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::TUFF_WALL)));
- $this->map(Blocks::TWISTING_VINES(), function(NetherVines $block) : Writer{
- return Writer::create(Ids::TWISTING_VINES)
- ->writeInt(StateNames::TWISTING_VINES_AGE, $block->getAge());
- });
- $this->map(Blocks::UNDERWATER_TORCH(), function(UnderwaterTorch $block) : Writer{
- return Writer::create(Ids::UNDERWATER_TORCH)
- ->writeTorchFacing($block->getFacing());
- });
- $this->map(Blocks::VINES(), function(Vine $block) : Writer{
- return Writer::create(Ids::VINE)
- ->writeInt(StateNames::VINE_DIRECTION_BITS, ($block->hasFace(Facing::NORTH) ? BlockLegacyMetadata::VINE_FLAG_NORTH : 0) | ($block->hasFace(Facing::SOUTH) ? BlockLegacyMetadata::VINE_FLAG_SOUTH : 0) | ($block->hasFace(Facing::WEST) ? BlockLegacyMetadata::VINE_FLAG_WEST : 0) | ($block->hasFace(Facing::EAST) ? BlockLegacyMetadata::VINE_FLAG_EAST : 0));
- });
- $this->map(Blocks::WALL_BANNER(), function(WallBanner $block) : Writer{
- return Writer::create(Ids::WALL_BANNER)
- ->writeHorizontalFacing($block->getFacing());
- });
- $this->map(Blocks::WATER(), fn(Water $block) => Helper::encodeLiquid($block, Ids::WATER, Ids::FLOWING_WATER));
- $this->map(Blocks::WEEPING_VINES(), function(NetherVines $block) : Writer{
- return Writer::create(Ids::WEEPING_VINES)
- ->writeInt(StateNames::WEEPING_VINES_AGE, $block->getAge());
- });
- $this->map(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), function(WeightedPressurePlateHeavy $block) : Writer{
- return Writer::create(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE)
- ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
- });
- $this->map(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), function(WeightedPressurePlateLight $block) : Writer{
- return Writer::create(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE)
- ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
- });
- $this->map(Blocks::WHEAT(), fn(Wheat $block) => Helper::encodeCrops($block, new Writer(Ids::WHEAT)));
- }
}
diff --git a/src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php b/src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php
new file mode 100644
index 000000000..02491bae6
--- /dev/null
+++ b/src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php
@@ -0,0 +1,237 @@
+> $components
+ *
+ * @return string[][]
+ * @phpstan-return list>
+ */
+ private static function compileFlattenedIdPartMatrix(array $components) : array{
+ $result = [];
+ foreach($components as $component){
+ $column = is_string($component) ? [$component] : $component->getPossibleValues();
+
+ if(count($result) === 0){
+ $result = array_map(fn($value) => [$value], $column);
+ }else{
+ $stepResult = [];
+ foreach($result as $parts){
+ foreach($column as $value){
+ $stepPart = $parts;
+ $stepPart[] = $value;
+ $stepResult[] = $stepPart;
+ }
+ }
+
+ $result = $stepResult;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param string[]|StringProperty[] $idComponents
+ *
+ * @phpstan-template TBlock of Block
+ *
+ * @phpstan-param TBlock $block
+ * @phpstan-param list> $idComponents
+ */
+ private static function serializeFlattenedId(Block $block, array $idComponents) : string{
+ $id = "";
+ foreach($idComponents as $infix){
+ $id .= is_string($infix) ? $infix : $infix->serializePlain($block);
+ }
+ return $id;
+ }
+
+ /**
+ * @param string[]|StringProperty[] $idComponents
+ * @param string[] $idPropertyValues
+ *
+ * @phpstan-template TBlock of Block
+ *
+ * @phpstan-param TBlock $baseBlock
+ * @phpstan-param list> $idComponents
+ * @phpstan-param list $idPropertyValues
+ *
+ * @phpstan-return TBlock
+ */
+ private static function deserializeFlattenedId(Block $baseBlock, array $idComponents, array $idPropertyValues) : Block{
+ $preparedBlock = clone $baseBlock;
+ foreach($idComponents as $k => $component){
+ if($component instanceof StringProperty){
+ $fakeValue = $idPropertyValues[$k];
+ $component->deserializePlain($preparedBlock, $fakeValue);
+ }
+ }
+
+ return $preparedBlock;
+ }
+
+ public function mapSimple(Block $block, string $id) : void{
+ $this->deserializer->mapSimple($id, fn() => clone $block);
+ $this->serializer->mapSimple($block, $id);
+ }
+
+ /**
+ * @phpstan-template TBlock of Block
+ * @phpstan-param FlattenedIdModel $model
+ */
+ public function mapFlattenedId(FlattenedIdModel $model) : void{
+ $block = $model->getBlock();
+
+ $idComponents = $model->getIdComponents();
+ if(count($idComponents) === 0){
+ throw new \InvalidArgumentException("No ID components provided");
+ }
+ $properties = $model->getProperties();
+
+ //This is a really cursed hack that lets us essentially write flattened properties as blockstate properties, and
+ //then pull them out to compile an ID :D
+ //This works surprisingly well and is much more elegant than I would've expected
+
+ if(count($properties) > 0){
+ $this->serializer->map($block, function(Block $block) use ($idComponents, $properties) : Writer{
+ $id = self::serializeFlattenedId($block, $idComponents);
+
+ $writer = new Writer($id);
+ foreach($properties as $property){
+ $property->serialize($block, $writer);
+ }
+
+ return $writer;
+ });
+ }else{
+ $this->serializer->map($block, function(Block $block) use ($idComponents) : BlockStateData{
+ //fast path for blocks with no state properties
+ $id = self::serializeFlattenedId($block, $idComponents);
+ return BlockStateData::current($id, []);
+ });
+ }
+
+ $idPermutations = self::compileFlattenedIdPartMatrix($idComponents);
+ foreach($idPermutations as $idParts){
+ //deconstruct the ID into a partial state
+ //we can do this at registration time since there will be multiple deserializers
+ $preparedBlock = self::deserializeFlattenedId($block, $idComponents, $idParts);
+ $id = implode("", $idParts);
+
+ if(count($properties) > 0){
+ $this->deserializer->map($id, function(Reader $reader) use ($preparedBlock, $properties) : Block{
+ $block = clone $preparedBlock;
+
+ foreach($properties as $property){
+ $property->deserialize($block, $reader);
+ }
+ return $block;
+ });
+ }else{
+ //fast path for blocks with no state properties
+ $this->deserializer->map($id, fn() => clone $preparedBlock);
+ }
+ }
+ }
+
+ /**
+ * @phpstan-template TBlock of Block&Colored
+ * @phpstan-param TBlock $block
+ */
+ public function mapColored(Block $block, string $idPrefix, string $idSuffix) : void{
+ $this->mapFlattenedId(FlattenedIdModel::create($block)
+ ->idComponents([
+ $idPrefix,
+ CommonProperties::getInstance()->dyeColorIdInfix,
+ $idSuffix
+ ])
+ );
+ }
+
+ public function mapSlab(Slab $block, string $type) : void{
+ $commonProperties = CommonProperties::getInstance();
+ $this->mapFlattenedId(FlattenedIdModel::create($block)
+ ->idComponents(["minecraft:", $type, "_", $commonProperties->slabIdInfix, "slab"])
+ ->properties([$commonProperties->slabPositionProperty])
+ );
+ }
+
+ public function mapStairs(Stair $block, string $id) : void{
+ $this->mapModel(Model::create($block, $id)->properties(CommonProperties::getInstance()->stairProperties));
+ }
+
+ /**
+ * @phpstan-template TBlock of Block
+ * @phpstan-param Model $model
+ */
+ public function mapModel(Model $model) : void{
+ $id = $model->getId();
+ $block = $model->getBlock();
+ $propertyDescriptors = $model->getProperties();
+
+ $this->deserializer->map($id, static function(Reader $in) use ($block, $propertyDescriptors) : Block{
+ $newBlock = clone $block;
+ foreach($propertyDescriptors as $descriptor){
+ $descriptor->deserialize($newBlock, $in);
+ }
+ return $newBlock;
+ });
+ $this->serializer->map($block, static function(Block $block) use ($id, $propertyDescriptors) : Writer{
+ $writer = new Writer($id);
+ foreach($propertyDescriptors as $descriptor){
+ $descriptor->serialize($block, $writer);
+ }
+ return $writer;
+ });
+ }
+}
diff --git a/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php b/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php
index 3cf55429e..1d48ec76f 100644
--- a/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php
+++ b/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php
@@ -56,11 +56,13 @@ use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
+use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
-use pocketmine\math\Axis;
use pocketmine\math\Facing;
-use pocketmine\utils\AssumptionFailedError;
+/**
+ * @deprecated
+ */
final class BlockStateDeserializerHelper{
/** @throws BlockStateDeserializeException */
@@ -71,6 +73,7 @@ final class BlockStateDeserializerHelper{
}
/**
+ * @deprecated
* @phpstan-template TCandle of Candle
* @phpstan-param TCandle $block
* @phpstan-return TCandle
@@ -103,6 +106,7 @@ final class BlockStateDeserializerHelper{
}
/**
+ * @deprecated
* @phpstan-template TBlock of CopperMaterial
*
* @phpstan-param TBlock $block
@@ -115,6 +119,7 @@ final class BlockStateDeserializerHelper{
}
/**
+ * @deprecated
* @phpstan-template TBlock of CopperMaterial
*
* @phpstan-param TBlock $block
@@ -133,6 +138,7 @@ final class BlockStateDeserializerHelper{
}
/**
+ * @deprecated
* @phpstan-template TDoor of Door
* @phpstan-param TDoor $block
* @phpstan-return TDoor
@@ -155,7 +161,10 @@ final class BlockStateDeserializerHelper{
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT));
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public static function decodeFenceGate(FenceGate $block, BlockStateReader $in) : FenceGate{
return $block
->setFacing($in->readCardinalHorizontalFacing())
@@ -163,17 +172,19 @@ final class BlockStateDeserializerHelper{
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public static function decodeFloorCoralFan(FloorCoralFan $block, BlockStateReader $in) : FloorCoralFan{
return $block
- ->setAxis(match($in->readBoundedInt(BlockStateNames::CORAL_FAN_DIRECTION, 0, 1)){
- 0 => Axis::X,
- 1 => Axis::Z,
- default => throw new AssumptionFailedError("readBoundedInt() should have prevented this"),
- });
+ ->setAxis($in->mapIntFromInt(BlockStateNames::CORAL_FAN_DIRECTION, ValueMappings::getInstance()->coralAxis));
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public static function decodeFloorSign(FloorSign $block, BlockStateReader $in) : FloorSign{
return $block
->setRotation($in->readBoundedInt(BlockStateNames::GROUND_SIGN_DIRECTION, 0, 15));
@@ -186,7 +197,10 @@ final class BlockStateDeserializerHelper{
->setHasMap($in->readBool(StateNames::ITEM_FRAME_MAP_BIT));
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @throws BlockStateDeserializeException
+ * @deprecated
+ */
public static function decodeLeaves(Leaves $block, BlockStateReader $in) : Leaves{
return $block
->setNoDecay($in->readBool(StateNames::PERSISTENT_BIT))
@@ -236,7 +250,10 @@ final class BlockStateDeserializerHelper{
->setDelay($in->readBoundedInt(BlockStateNames::REPEATER_DELAY, 0, 3) + 1);
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @throws BlockStateDeserializeException
+ * @deprecated
+ */
public static function decodeSapling(Sapling $block, BlockStateReader $in) : Sapling{
return $block
->setReady($in->readBool(BlockStateNames::AGE_BIT));
@@ -273,6 +290,7 @@ final class BlockStateDeserializerHelper{
}
/**
+ * @deprecated
* @phpstan-template TStair of Stair
* @phpstan-param TStair $block
* @phpstan-return TStair
@@ -296,6 +314,7 @@ final class BlockStateDeserializerHelper{
}
/**
+ * @deprecated
* @phpstan-template TTrapdoor of Trapdoor
* @phpstan-param TTrapdoor $block
* @phpstan-return TTrapdoor
@@ -320,12 +339,19 @@ final class BlockStateDeserializerHelper{
return $block;
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public static function decodeWallSign(WallSign $block, BlockStateReader $in) : WallSign{
return $block
->setFacing($in->readHorizontalFacing());
}
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public static function decodeWeightedPressurePlate(WeightedPressurePlate $block, BlockStateReader $in) : WeightedPressurePlate{
return $block
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));
diff --git a/src/data/bedrock/block/convert/BlockStateReader.php b/src/data/bedrock/block/convert/BlockStateReader.php
index e3a02885f..4d09d2f85 100644
--- a/src/data/bedrock/block/convert/BlockStateReader.php
+++ b/src/data/bedrock/block/convert/BlockStateReader.php
@@ -31,6 +31,9 @@ use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
+use pocketmine\data\bedrock\block\convert\property\EnumFromRawStateMap;
+use pocketmine\data\bedrock\block\convert\property\IntFromRawStateMap;
+use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\nbt\tag\ByteTag;
@@ -112,45 +115,45 @@ final class BlockStateReader{
}
/**
- * @param int[] $mapping
- * @phpstan-param array $mapping
- * @phpstan-return int
+ * @deprecated
+ * @phpstan-param IntFromRawStateMap $map
* @throws BlockStateDeserializeException
*/
- private function parseFacingValue(int $value, array $mapping) : int{
- $result = $mapping[$value] ?? null;
- if($result === null){
- throw new BlockStateDeserializeException("Unmapped facing value " . $value);
- }
- return $result;
- }
+ public function mapIntFromString(string $name, IntFromRawStateMap $map) : int{
+ $raw = $this->readString($name);
- /** @throws BlockStateDeserializeException */
- public function readFacingDirection() : int{
- return $this->parseFacingValue($this->readInt(BlockStateNames::FACING_DIRECTION), [
- 0 => Facing::DOWN,
- 1 => Facing::UP,
- 2 => Facing::NORTH,
- 3 => Facing::SOUTH,
- 4 => Facing::WEST,
- 5 => Facing::EAST
- ]);
- }
-
- /** @throws BlockStateDeserializeException */
- public function readBlockFace() : int{
- return match($raw = $this->readString(BlockStateNames::MC_BLOCK_FACE)){
- StringValues::MC_BLOCK_FACE_DOWN => Facing::DOWN,
- StringValues::MC_BLOCK_FACE_UP => Facing::UP,
- StringValues::MC_BLOCK_FACE_NORTH => Facing::NORTH,
- StringValues::MC_BLOCK_FACE_SOUTH => Facing::SOUTH,
- StringValues::MC_BLOCK_FACE_WEST => Facing::WEST,
- StringValues::MC_BLOCK_FACE_EAST => Facing::EAST,
- default => throw $this->badValueException(BlockStateNames::MC_BLOCK_FACE, $raw)
- };
+ return $map->rawToValue($raw) ?? throw $this->badValueException($name, $raw);
}
/**
+ * @deprecated
+ * @phpstan-param IntFromRawStateMap $map
+ * @throws BlockStateDeserializeException
+ */
+ public function mapIntFromInt(string $name, IntFromRawStateMap $map) : int{
+ $raw = $this->readInt($name);
+
+ return $map->rawToValue($raw) ?? throw $this->badValueException($name, (string) $raw);
+ }
+
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
+ public function readFacingDirection() : int{
+ return $this->mapIntFromInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->facing);
+ }
+
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
+ public function readBlockFace() : int{
+ return $this->mapIntFromString(BlockStateNames::MC_BLOCK_FACE, ValueMappings::getInstance()->blockFace);
+ }
+
+ /**
+ * @deprecated
* @return int[]
* @phpstan-return array
*/
@@ -173,82 +176,69 @@ final class BlockStateReader{
return $result;
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readEndRodFacingDirection() : int{
$result = $this->readFacingDirection();
return Facing::axis($result) !== Axis::Y ? Facing::opposite($result) : $result;
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readHorizontalFacing() : int{
- return $this->parseFacingValue($this->readInt(BlockStateNames::FACING_DIRECTION), [
- 0 => Facing::NORTH, //should be illegal, but 1.13 allows it
- 1 => Facing::NORTH, //also should be illegal
- 2 => Facing::NORTH,
- 3 => Facing::SOUTH,
- 4 => Facing::WEST,
- 5 => Facing::EAST
- ]);
- }
-
- /** @throws BlockStateDeserializeException */
- public function readWeirdoHorizontalFacing() : int{
- return $this->parseFacingValue($this->readInt(BlockStateNames::WEIRDO_DIRECTION), [
- 0 => Facing::EAST,
- 1 => Facing::WEST,
- 2 => Facing::SOUTH,
- 3 => Facing::NORTH
- ]);
- }
-
- /** @throws BlockStateDeserializeException */
- public function readLegacyHorizontalFacing() : int{
- return $this->parseFacingValue($this->readInt(BlockStateNames::DIRECTION), [
- 0 => Facing::SOUTH,
- 1 => Facing::WEST,
- 2 => Facing::NORTH,
- 3 => Facing::EAST
- ]);
+ return $this->mapIntFromInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->horizontalFacingClassic);
}
/**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
+ public function readWeirdoHorizontalFacing() : int{
+ return $this->mapIntFromInt(BlockStateNames::WEIRDO_DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus);
+ }
+
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
+ public function readLegacyHorizontalFacing() : int{
+ return $this->mapIntFromInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacingSWNE);
+ }
+
+ /**
+ * @deprecated
* This is for trapdoors, because Mojang botched the conversion in 1.13
* @throws BlockStateDeserializeException
*/
public function read5MinusHorizontalFacing() : int{
- return $this->parseFacingValue($this->readInt(BlockStateNames::DIRECTION), [
- 0 => Facing::EAST,
- 1 => Facing::WEST,
- 2 => Facing::SOUTH,
- 3 => Facing::NORTH
- ]);
+ return $this->mapIntFromInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus);
}
/**
+ * @deprecated
* Used by pumpkins as of 1.20.0.23 beta
* @throws BlockStateDeserializeException
*/
public function readCardinalHorizontalFacing() : int{
- return match($raw = $this->readString(BlockStateNames::MC_CARDINAL_DIRECTION)){
- StringValues::MC_CARDINAL_DIRECTION_NORTH => Facing::NORTH,
- StringValues::MC_CARDINAL_DIRECTION_SOUTH => Facing::SOUTH,
- StringValues::MC_CARDINAL_DIRECTION_WEST => Facing::WEST,
- StringValues::MC_CARDINAL_DIRECTION_EAST => Facing::EAST,
- default => throw $this->badValueException(BlockStateNames::MC_CARDINAL_DIRECTION, $raw)
- };
+ return $this->mapIntFromString(BlockStateNames::MC_CARDINAL_DIRECTION, ValueMappings::getInstance()->cardinalDirection);
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readCoralFacing() : int{
- return $this->parseFacingValue($this->readInt(BlockStateNames::CORAL_DIRECTION), [
- 0 => Facing::WEST,
- 1 => Facing::EAST,
- 2 => Facing::NORTH,
- 3 => Facing::SOUTH
- ]);
+ return $this->mapIntFromInt(BlockStateNames::CORAL_DIRECTION, ValueMappings::getInstance()->horizontalFacingCoral);
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readFacingWithoutDown() : int{
$result = $this->readFacingDirection();
if($result === Facing::DOWN){ //shouldn't be legal, but 1.13 allows it
@@ -257,6 +247,10 @@ final class BlockStateReader{
return $result;
}
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readFacingWithoutUp() : int{
$result = $this->readFacingDirection();
if($result === Facing::UP){
@@ -266,23 +260,17 @@ final class BlockStateReader{
}
/**
- * @phpstan-return Axis::*
+ * @deprecated
* @throws BlockStateDeserializeException
*/
public function readPillarAxis() : int{
- $rawValue = $this->readString(BlockStateNames::PILLAR_AXIS);
- $value = [
- StringValues::PILLAR_AXIS_X => Axis::X,
- StringValues::PILLAR_AXIS_Y => Axis::Y,
- StringValues::PILLAR_AXIS_Z => Axis::Z
- ][$rawValue] ?? null;
- if($value === null){
- throw $this->badValueException(BlockStateNames::PILLAR_AXIS, $rawValue, "Invalid axis value");
- }
- return $value;
+ return $this->mapIntFromString(BlockStateNames::PILLAR_AXIS, ValueMappings::getInstance()->pillarAxis);
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readSlabPosition() : SlabType{
return match($rawValue = $this->readString(BlockStateNames::MC_VERTICAL_HALF)){
StringValues::MC_VERTICAL_HALF_BOTTOM => SlabType::BOTTOM,
@@ -292,34 +280,25 @@ final class BlockStateReader{
}
/**
- * @phpstan-return Facing::UP|Facing::NORTH|Facing::SOUTH|Facing::WEST|Facing::EAST
+ * @deprecated
* @throws BlockStateDeserializeException
*/
public function readTorchFacing() : int{
- //TODO: horizontal directions are flipped (MCPE bug: https://bugs.mojang.com/browse/MCPE-152036)
- return match($rawValue = $this->readString(BlockStateNames::TORCH_FACING_DIRECTION)){
- StringValues::TORCH_FACING_DIRECTION_EAST => Facing::WEST,
- StringValues::TORCH_FACING_DIRECTION_NORTH => Facing::SOUTH,
- StringValues::TORCH_FACING_DIRECTION_SOUTH => Facing::NORTH,
- StringValues::TORCH_FACING_DIRECTION_TOP => Facing::UP,
- StringValues::TORCH_FACING_DIRECTION_UNKNOWN => Facing::UP, //should be illegal, but 1.13 allows it
- StringValues::TORCH_FACING_DIRECTION_WEST => Facing::EAST,
- default => throw $this->badValueException(BlockStateNames::TORCH_FACING_DIRECTION, $rawValue, "Invalid torch facing"),
- };
+ return $this->mapIntFromString(BlockStateNames::TORCH_FACING_DIRECTION, ValueMappings::getInstance()->torchFacing);
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readBellAttachmentType() : BellAttachmentType{
- return match($type = $this->readString(BlockStateNames::ATTACHMENT)){
- StringValues::ATTACHMENT_HANGING => BellAttachmentType::CEILING,
- StringValues::ATTACHMENT_STANDING => BellAttachmentType::FLOOR,
- StringValues::ATTACHMENT_SIDE => BellAttachmentType::ONE_WALL,
- StringValues::ATTACHMENT_MULTIPLE => BellAttachmentType::TWO_WALLS,
- default => throw $this->badValueException(BlockStateNames::ATTACHMENT, $type),
- };
+ return $this->readUnitEnum(BlockStateNames::ATTACHMENT, ValueMappings::getInstance()->bellAttachmentType);
}
- /** @throws BlockStateDeserializeException */
+ /**
+ * @deprecated
+ * @throws BlockStateDeserializeException
+ */
public function readWallConnectionType(string $name) : ?WallConnectionType{
return match($type = $this->readString($name)){
//TODO: this looks a bit confusing due to use of EAST, but the values are the same for all connections
@@ -332,6 +311,23 @@ final class BlockStateReader{
};
}
+ /**
+ * @deprecated
+ * @phpstan-template TEnum of \UnitEnum
+ * @phpstan-param EnumFromRawStateMap $map
+ * @phpstan-return TEnum
+ * @throws BlockStateDeserializeException
+ */
+ public function readUnitEnum(string $name, EnumFromRawStateMap $map) : \UnitEnum{
+ $value = $this->readString($name);
+
+ $mapped = $map->rawToValue($value);
+ if($mapped === null){
+ throw $this->badValueException($name, $value);
+ }
+ return $mapped;
+ }
+
/**
* Explicitly mark a property as unused, so it doesn't get flagged as an error when debug mode is enabled
*/
diff --git a/src/data/bedrock/block/convert/BlockStateSerializerHelper.php b/src/data/bedrock/block/convert/BlockStateSerializerHelper.php
index a25044153..da3dbb387 100644
--- a/src/data/bedrock/block/convert/BlockStateSerializerHelper.php
+++ b/src/data/bedrock/block/convert/BlockStateSerializerHelper.php
@@ -55,6 +55,9 @@ use pocketmine\data\bedrock\block\convert\BlockStateWriter as Writer;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
use pocketmine\math\Facing;
+/**
+ * @deprecated
+ */
final class BlockStateSerializerHelper{
public static function encodeButton(Button $block, Writer $out) : Writer{
return $out
@@ -77,6 +80,9 @@ final class BlockStateSerializerHelper{
return $out->writeInt(BlockStateNames::GROWTH, $block->getAge());
}
+ /**
+ * @deprecated
+ */
public static function encodeTorch(Torch $block, Writer $out) : Writer{
return $out
->writeTorchFacing($block->getFacing());
@@ -97,6 +103,9 @@ final class BlockStateSerializerHelper{
};
}
+ /**
+ * @deprecated
+ */
public static function encodeDoor(Door $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
@@ -111,6 +120,9 @@ final class BlockStateSerializerHelper{
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop());
}
+ /**
+ * @deprecated
+ */
public static function encodeFenceGate(FenceGate $block, Writer $out) : Writer{
return $out
->writeCardinalHorizontalFacing($block->getFacing())
@@ -118,6 +130,9 @@ final class BlockStateSerializerHelper{
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
+ /**
+ * @deprecated
+ */
public static function encodeFloorSign(FloorSign $block, Writer $out) : Writer{
return $out
->writeInt(BlockStateNames::GROUND_SIGN_DIRECTION, $block->getRotation());
@@ -135,6 +150,9 @@ final class BlockStateSerializerHelper{
->writeFacingDirection($block->getFacing());
}
+ /**
+ * @deprecated
+ */
public static function encodeLeaves(Leaves $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::PERSISTENT_BIT, $block->isNoDecay())
@@ -159,11 +177,17 @@ final class BlockStateSerializerHelper{
->writeInt(BlockStateNames::HUGE_MUSHROOM_BITS, MushroomBlockTypeIdMap::getInstance()->toId($block->getMushroomBlockType()));
}
+ /**
+ * @deprecated
+ */
public static function encodeQuartz(int $axis, Writer $out) : Writer{
return $out
->writePillarAxis($axis); //this isn't needed for all types, but we have to write it anyway
}
+ /**
+ * @deprecated
+ */
public static function encodeSapling(Sapling $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::AGE_BIT, $block->isReady());
@@ -193,6 +217,9 @@ final class BlockStateSerializerHelper{
self::encodeSingleSlab($block, $singleId);
}
+ /**
+ * @deprecated
+ */
public static function encodeStairs(Stair $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isUpsideDown())
@@ -208,6 +235,9 @@ final class BlockStateSerializerHelper{
->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing);
}
+ /**
+ * @deprecated
+ */
public static function encodeTrapdoor(Trapdoor $block, Writer $out) : Writer{
return $out
->write5MinusHorizontalFacing($block->getFacing())
@@ -224,6 +254,9 @@ final class BlockStateSerializerHelper{
->writeWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_WEST, $block->getConnection(Facing::WEST));
}
+ /**
+ * @deprecated
+ */
public static function encodeWallSign(WallSign $block, Writer $out) : Writer{
return $out
->writeHorizontalFacing($block->getFacing());
diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
index 1e9a4041f..ca5c12412 100644
--- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
+++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php
@@ -23,50 +23,18 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
-use pocketmine\block\AmethystCluster;
-use pocketmine\block\Anvil;
-use pocketmine\block\Bamboo;
use pocketmine\block\Block;
-use pocketmine\block\CakeWithDyedCandle;
-use pocketmine\block\CaveVines;
-use pocketmine\block\ChorusFlower;
-use pocketmine\block\DoublePitcherCrop;
-use pocketmine\block\Opaque;
-use pocketmine\block\PinkPetals;
-use pocketmine\block\PitcherCrop;
use pocketmine\block\RuntimeBlockStateRegistry;
use pocketmine\block\Slab;
use pocketmine\block\Stair;
-use pocketmine\block\SweetBerryBush;
-use pocketmine\block\utils\BrewingStandSlot;
-use pocketmine\block\utils\ChiseledBookshelfSlot;
-use pocketmine\block\utils\Colored;
-use pocketmine\block\utils\CopperMaterial;
-use pocketmine\block\utils\CopperOxidation;
-use pocketmine\block\utils\CoralType;
-use pocketmine\block\utils\DirtType;
-use pocketmine\block\utils\DripleafState;
-use pocketmine\block\utils\DyeColor;
-use pocketmine\block\utils\FroglightType;
-use pocketmine\block\utils\LeverFacing;
-use pocketmine\block\utils\MobHeadType;
-use pocketmine\block\VanillaBlocks as Blocks;
use pocketmine\block\Wood;
-use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\BlockStateDeserializer;
-use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
-use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
-use pocketmine\data\bedrock\block\BlockTypeNames as Ids;
use pocketmine\data\bedrock\block\convert\BlockStateDeserializerHelper as Helper;
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
-use pocketmine\math\Axis;
-use pocketmine\math\Facing;
-use pocketmine\utils\Utils;
use function array_key_exists;
use function count;
-use function min;
final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
@@ -82,21 +50,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
*/
private array $simpleCache = [];
- public function __construct(){
- $this->registerCandleDeserializers();
- $this->registerFlatColorBlockDeserializers();
- $this->registerFlatCoralDeserializers();
- $this->registerCauldronDeserializers();
- $this->registerFlatWoodBlockDeserializers();
- $this->registerLeavesDeserializers();
- $this->registerSaplingDeserializers();
- $this->registerLightDeserializers();
- $this->registerMobHeadDeserializers();
- $this->registerCopperDeserializers();
- $this->registerSimpleDeserializers();
- $this->registerDeserializers();
- }
-
public function deserialize(BlockStateData $stateData) : int{
if(count($stateData->getStates()) === 0){
//if a block has zero properties, we can keep a map of string ID -> internal blockstate ID
@@ -133,12 +86,16 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
return $this->deserializeFuncs[$id] ?? null;
}
- /** @phpstan-param \Closure() : Block $getBlock */
+ /**
+ * @deprecated
+ * @phpstan-param \Closure() : Block $getBlock
+ */
public function mapSimple(string $id, \Closure $getBlock) : void{
$this->map($id, $getBlock);
}
/**
+ * @deprecated
* @phpstan-param \Closure(Reader) : Slab $getBlock
*/
public function mapSlab(string $singleId, string $doubleId, \Closure $getBlock) : void{
@@ -147,1552 +104,22 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
}
/**
+ * @deprecated
* @phpstan-param \Closure() : Stair $getBlock
*/
public function mapStairs(string $id, \Closure $getBlock) : void{
$this->map($id, fn(Reader $in) : Stair => Helper::decodeStairs($getBlock(), $in));
}
- /** @phpstan-param \Closure() : Wood $getBlock */
+ /**
+ * @deprecated
+ * @phpstan-param \Closure() : Wood $getBlock
+ */
public function mapLog(string $unstrippedId, string $strippedId, \Closure $getBlock) : void{
$this->map($unstrippedId, fn(Reader $in) => Helper::decodeLog($getBlock(), false, $in));
$this->map($strippedId, fn(Reader $in) => Helper::decodeLog($getBlock(), true, $in));
}
- /**
- * @phpstan-template TBlock of Block
- * @phpstan-template TEnum of \UnitEnum
- *
- * @phpstan-param StringEnumMap $mapProperty
- * @phpstan-param \Closure(TEnum) : TBlock $getBlock
- * @phpstan-param ?\Closure(TBlock, Reader) : TBlock $extra
- */
- public function mapFlattenedEnum(
- StringEnumMap $mapProperty,
- string $prefix,
- string $suffix,
- \Closure $getBlock,
- ?\Closure $extra = null
- ) : void{
- foreach(Utils::stringifyKeys($mapProperty->getValueToEnum()) as $infix => $enumCase){
- $id = $prefix . $infix . $suffix;
- if($extra === null){
- $this->map($id, fn() => $getBlock($enumCase));
- }else{
- $this->map($id, function(Reader $in) use ($enumCase, $getBlock, $extra) : Block{
- $block = $getBlock($enumCase);
- $extra($block, $in);
- return $block;
- });
- }
- }
- }
-
- /**
- * @phpstan-template TBlock of Block&Colored
- * @phpstan-param \Closure() : TBlock $getBlock
- * @phpstan-param ?\Closure(TBlock, Reader) : TBlock $extra
- */
- public function mapColored(string $prefix, string $suffix, \Closure $getBlock, ?\Closure $extra = null) : void{
- $this->mapFlattenedEnum(
- ValueMappings::getInstance()->getEnumMap(DyeColor::class),
- $prefix,
- $suffix,
- fn(DyeColor $color) => $getBlock()->setColor($color),
- $extra
- );
- }
-
- private function registerCandleDeserializers() : void{
- $this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in));
- $this->mapColored(
- "minecraft:",
- "_candle",
- fn() => Blocks::DYED_CANDLE(),
- Helper::decodeCandle(...)
- );
-
- $this->map(Ids::CANDLE_CAKE, fn(Reader $in) => Blocks::CAKE_WITH_CANDLE()->setLit($in->readBool(StateNames::LIT)));
-
- $this->mapColored(
- "minecraft:",
- "_candle_cake",
- fn() => Blocks::CAKE_WITH_DYED_CANDLE(),
- fn(CakeWithDyedCandle $block, Reader $in) => $block->setLit($in->readBool(StateNames::LIT))
- );
- }
-
- private function registerFlatColorBlockDeserializers() : void{
- $this->mapColored("minecraft:hard_", "_stained_glass", fn() => Blocks::STAINED_HARDENED_GLASS());
- $this->mapColored("minecraft:hard_", "_stained_glass_pane", fn() => Blocks::STAINED_HARDENED_GLASS_PANE());
-
- $this->mapColored("minecraft:", "_carpet", fn() => Blocks::CARPET());
- $this->mapColored("minecraft:", "_concrete", fn() => Blocks::CONCRETE());
- $this->mapColored("minecraft:", "_concrete_powder", fn() => Blocks::CONCRETE_POWDER());
- $this->mapColored("minecraft:", "_shulker_box", fn() => Blocks::DYED_SHULKER_BOX());
- $this->mapColored("minecraft:", "_stained_glass", fn() => Blocks::STAINED_GLASS());
- $this->mapColored("minecraft:", "_stained_glass_pane", fn() => Blocks::STAINED_GLASS_PANE());
- $this->mapColored("minecraft:", "_terracotta", fn() => Blocks::STAINED_CLAY());
- $this->mapColored("minecraft:", "_wool", fn() => Blocks::WOOL());
-
- foreach([
- Ids::BLACK_GLAZED_TERRACOTTA => DyeColor::BLACK,
- Ids::BLUE_GLAZED_TERRACOTTA => DyeColor::BLUE,
- Ids::BROWN_GLAZED_TERRACOTTA => DyeColor::BROWN,
- Ids::CYAN_GLAZED_TERRACOTTA => DyeColor::CYAN,
- Ids::GRAY_GLAZED_TERRACOTTA => DyeColor::GRAY,
- Ids::GREEN_GLAZED_TERRACOTTA => DyeColor::GREEN,
- Ids::LIGHT_BLUE_GLAZED_TERRACOTTA => DyeColor::LIGHT_BLUE,
- Ids::SILVER_GLAZED_TERRACOTTA => DyeColor::LIGHT_GRAY, //minecraft sadness
- Ids::LIME_GLAZED_TERRACOTTA => DyeColor::LIME,
- Ids::MAGENTA_GLAZED_TERRACOTTA => DyeColor::MAGENTA,
- Ids::ORANGE_GLAZED_TERRACOTTA => DyeColor::ORANGE,
- Ids::PINK_GLAZED_TERRACOTTA => DyeColor::PINK,
- Ids::PURPLE_GLAZED_TERRACOTTA => DyeColor::PURPLE,
- Ids::RED_GLAZED_TERRACOTTA => DyeColor::RED,
- Ids::WHITE_GLAZED_TERRACOTTA => DyeColor::WHITE,
- Ids::YELLOW_GLAZED_TERRACOTTA => DyeColor::YELLOW,
- ] as $id => $color){
- $this->map($id, fn(Reader $in) => Blocks::GLAZED_TERRACOTTA()
- ->setColor($color)
- ->setFacing($in->readHorizontalFacing())
- );
- }
- }
-
- private function registerFlatCoralDeserializers() : void{
- foreach([
- Ids::BRAIN_CORAL => CoralType::BRAIN,
- Ids::BUBBLE_CORAL => CoralType::BUBBLE,
- Ids::FIRE_CORAL => CoralType::FIRE,
- Ids::HORN_CORAL => CoralType::HORN,
- Ids::TUBE_CORAL => CoralType::TUBE,
- ] as $id => $coralType){
- $this->mapSimple($id, fn() => Blocks::CORAL()->setCoralType($coralType)->setDead(false));
- }
- foreach([
- Ids::DEAD_BRAIN_CORAL => CoralType::BRAIN,
- Ids::DEAD_BUBBLE_CORAL => CoralType::BUBBLE,
- Ids::DEAD_FIRE_CORAL => CoralType::FIRE,
- Ids::DEAD_HORN_CORAL => CoralType::HORN,
- Ids::DEAD_TUBE_CORAL => CoralType::TUBE,
- ] as $id => $coralType){
- $this->mapSimple($id, fn() => Blocks::CORAL()->setCoralType($coralType)->setDead(true));
- }
-
- foreach([
- [CoralType::BRAIN, Ids::BRAIN_CORAL_FAN, Ids::DEAD_BRAIN_CORAL_FAN],
- [CoralType::BUBBLE, Ids::BUBBLE_CORAL_FAN, Ids::DEAD_BUBBLE_CORAL_FAN],
- [CoralType::FIRE, Ids::FIRE_CORAL_FAN, Ids::DEAD_FIRE_CORAL_FAN],
- [CoralType::HORN, Ids::HORN_CORAL_FAN, Ids::DEAD_HORN_CORAL_FAN],
- [CoralType::TUBE, Ids::TUBE_CORAL_FAN, Ids::DEAD_TUBE_CORAL_FAN],
- ] as [$coralType, $aliveId, $deadId]){
- $this->map($aliveId, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(false), $in));
- $this->map($deadId, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(true), $in));
- }
-
- foreach([
- [CoralType::BRAIN, Ids::BRAIN_CORAL_BLOCK, Ids::DEAD_BRAIN_CORAL_BLOCK],
- [CoralType::BUBBLE, Ids::BUBBLE_CORAL_BLOCK, Ids::DEAD_BUBBLE_CORAL_BLOCK],
- [CoralType::FIRE, Ids::FIRE_CORAL_BLOCK, Ids::DEAD_FIRE_CORAL_BLOCK],
- [CoralType::HORN, Ids::HORN_CORAL_BLOCK, Ids::DEAD_HORN_CORAL_BLOCK],
- [CoralType::TUBE, Ids::TUBE_CORAL_BLOCK, Ids::DEAD_TUBE_CORAL_BLOCK],
- ] as [$coralType, $aliveId, $deadId]){
- $this->map($aliveId, fn(Reader $in) => Blocks::CORAL_BLOCK()->setCoralType($coralType)->setDead(false));
- $this->map($deadId, fn(Reader $in) => Blocks::CORAL_BLOCK()->setCoralType($coralType)->setDead(true));
- }
-
- foreach([
- [CoralType::BRAIN, Ids::BRAIN_CORAL_WALL_FAN, Ids::DEAD_BRAIN_CORAL_WALL_FAN],
- [CoralType::BUBBLE, Ids::BUBBLE_CORAL_WALL_FAN, Ids::DEAD_BUBBLE_CORAL_WALL_FAN],
- [CoralType::FIRE, Ids::FIRE_CORAL_WALL_FAN, Ids::DEAD_FIRE_CORAL_WALL_FAN],
- [CoralType::HORN, Ids::HORN_CORAL_WALL_FAN, Ids::DEAD_HORN_CORAL_WALL_FAN],
- [CoralType::TUBE, Ids::TUBE_CORAL_WALL_FAN, Ids::DEAD_TUBE_CORAL_WALL_FAN],
- ] as [$coralType, $aliveId, $deadId]){
- $this->map($aliveId, fn(Reader $in) => Blocks::WALL_CORAL_FAN()->setFacing($in->readCoralFacing())->setCoralType($coralType)->setDead(false));
- $this->map($deadId, fn(Reader $in) => Blocks::WALL_CORAL_FAN()->setFacing($in->readCoralFacing())->setCoralType($coralType)->setDead(true));
- }
- }
-
- private function registerCauldronDeserializers() : void{
- $deserializer = function(Reader $in) : Block{
- $level = $in->readBoundedInt(StateNames::FILL_LEVEL, 0, 6);
- if($level === 0){
- $in->ignored(StateNames::CAULDRON_LIQUID);
- return Blocks::CAULDRON();
- }
-
- return (match($liquid = $in->readString(StateNames::CAULDRON_LIQUID)){
- StringValues::CAULDRON_LIQUID_WATER => Blocks::WATER_CAULDRON(),
- StringValues::CAULDRON_LIQUID_LAVA => Blocks::LAVA_CAULDRON(),
- StringValues::CAULDRON_LIQUID_POWDER_SNOW => throw new UnsupportedBlockStateException("Powder snow is not supported yet"),
- default => throw $in->badValueException(StateNames::CAULDRON_LIQUID, $liquid)
- })->setFillLevel($level);
- };
- $this->map(Ids::CAULDRON, $deserializer);
- }
-
- private function registerFlatWoodBlockDeserializers() : void{
- $this->map(Ids::ACACIA_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::ACACIA_BUTTON(), $in));
- $this->map(Ids::ACACIA_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::ACACIA_DOOR(), $in));
- $this->map(Ids::ACACIA_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::ACACIA_FENCE_GATE(), $in));
- $this->map(Ids::ACACIA_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::ACACIA_PRESSURE_PLATE(), $in));
- $this->map(Ids::ACACIA_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::ACACIA_SIGN(), $in));
- $this->map(Ids::ACACIA_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::ACACIA_TRAPDOOR(), $in));
- $this->map(Ids::ACACIA_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::ACACIA_WALL_SIGN(), $in));
- $this->mapLog(Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG, fn() => Blocks::ACACIA_LOG());
- $this->mapLog(Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD, fn() => Blocks::ACACIA_WOOD());
- $this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE());
- $this->mapSimple(Ids::ACACIA_PLANKS, fn() => Blocks::ACACIA_PLANKS());
- $this->mapSlab(Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB, fn() => Blocks::ACACIA_SLAB());
- $this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
-
- $this->map(Ids::BIRCH_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::BIRCH_BUTTON(), $in));
- $this->map(Ids::BIRCH_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::BIRCH_DOOR(), $in));
- $this->map(Ids::BIRCH_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::BIRCH_FENCE_GATE(), $in));
- $this->map(Ids::BIRCH_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::BIRCH_PRESSURE_PLATE(), $in));
- $this->map(Ids::BIRCH_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::BIRCH_SIGN(), $in));
- $this->map(Ids::BIRCH_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::BIRCH_TRAPDOOR(), $in));
- $this->map(Ids::BIRCH_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::BIRCH_WALL_SIGN(), $in));
- $this->mapLog(Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG, fn() => Blocks::BIRCH_LOG());
- $this->mapLog(Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD, fn() => Blocks::BIRCH_WOOD());
- $this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE());
- $this->mapSimple(Ids::BIRCH_PLANKS, fn() => Blocks::BIRCH_PLANKS());
- $this->mapSlab(Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB, fn() => Blocks::BIRCH_SLAB());
- $this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
-
- $this->map(Ids::CHERRY_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::CHERRY_BUTTON(), $in));
- $this->map(Ids::CHERRY_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::CHERRY_DOOR(), $in));
- $this->map(Ids::CHERRY_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::CHERRY_FENCE_GATE(), $in));
- $this->map(Ids::CHERRY_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::CHERRY_PRESSURE_PLATE(), $in));
- $this->map(Ids::CHERRY_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::CHERRY_SIGN(), $in));
- $this->map(Ids::CHERRY_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::CHERRY_TRAPDOOR(), $in));
- $this->map(Ids::CHERRY_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::CHERRY_WALL_SIGN(), $in));
- $this->mapLog(Ids::CHERRY_LOG, Ids::STRIPPED_CHERRY_LOG, fn() => Blocks::CHERRY_LOG());
- $this->mapSimple(Ids::CHERRY_FENCE, fn() => Blocks::CHERRY_FENCE());
- $this->mapSimple(Ids::CHERRY_PLANKS, fn() => Blocks::CHERRY_PLANKS());
- $this->mapSlab(Ids::CHERRY_SLAB, Ids::CHERRY_DOUBLE_SLAB, fn() => Blocks::CHERRY_SLAB());
- $this->mapStairs(Ids::CHERRY_STAIRS, fn() => Blocks::CHERRY_STAIRS());
- $this->map(Ids::CHERRY_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::CHERRY_WOOD(), false, $in));
- $this->map(Ids::STRIPPED_CHERRY_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::CHERRY_WOOD(), true, $in));
-
- $this->map(Ids::CRIMSON_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::CRIMSON_BUTTON(), $in));
- $this->map(Ids::CRIMSON_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::CRIMSON_DOOR(), $in));
- $this->map(Ids::CRIMSON_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::CRIMSON_FENCE_GATE(), $in));
- $this->map(Ids::CRIMSON_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::CRIMSON_PRESSURE_PLATE(), $in));
- $this->map(Ids::CRIMSON_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::CRIMSON_SIGN(), $in));
- $this->map(Ids::CRIMSON_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::CRIMSON_TRAPDOOR(), $in));
- $this->map(Ids::CRIMSON_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::CRIMSON_WALL_SIGN(), $in));
- $this->mapLog(Ids::CRIMSON_HYPHAE, Ids::STRIPPED_CRIMSON_HYPHAE, fn() => Blocks::CRIMSON_HYPHAE());
- $this->mapLog(Ids::CRIMSON_STEM, Ids::STRIPPED_CRIMSON_STEM, fn() => Blocks::CRIMSON_STEM());
- $this->mapSimple(Ids::CRIMSON_FENCE, fn() => Blocks::CRIMSON_FENCE());
- $this->mapSimple(Ids::CRIMSON_PLANKS, fn() => Blocks::CRIMSON_PLANKS());
- $this->mapSlab(Ids::CRIMSON_SLAB, Ids::CRIMSON_DOUBLE_SLAB, fn() => Blocks::CRIMSON_SLAB());
- $this->mapStairs(Ids::CRIMSON_STAIRS, fn() => Blocks::CRIMSON_STAIRS());
-
- $this->map(Ids::DARKOAK_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::DARK_OAK_SIGN(), $in));
- $this->map(Ids::DARKOAK_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::DARK_OAK_WALL_SIGN(), $in));
- $this->map(Ids::DARK_OAK_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::DARK_OAK_BUTTON(), $in));
- $this->map(Ids::DARK_OAK_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::DARK_OAK_DOOR(), $in));
- $this->map(Ids::DARK_OAK_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::DARK_OAK_FENCE_GATE(), $in));
- $this->map(Ids::DARK_OAK_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::DARK_OAK_PRESSURE_PLATE(), $in));
- $this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in));
- $this->mapLog(Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG, fn() => Blocks::DARK_OAK_LOG());
- $this->mapLog(Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD, fn() => Blocks::DARK_OAK_WOOD());
- $this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE());
- $this->mapSimple(Ids::DARK_OAK_PLANKS, fn() => Blocks::DARK_OAK_PLANKS());
- $this->mapSlab(Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB, fn() => Blocks::DARK_OAK_SLAB());
- $this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
-
- $this->map(Ids::JUNGLE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::JUNGLE_BUTTON(), $in));
- $this->map(Ids::JUNGLE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::JUNGLE_DOOR(), $in));
- $this->map(Ids::JUNGLE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::JUNGLE_FENCE_GATE(), $in));
- $this->map(Ids::JUNGLE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::JUNGLE_PRESSURE_PLATE(), $in));
- $this->map(Ids::JUNGLE_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::JUNGLE_SIGN(), $in));
- $this->map(Ids::JUNGLE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::JUNGLE_TRAPDOOR(), $in));
- $this->map(Ids::JUNGLE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::JUNGLE_WALL_SIGN(), $in));
- $this->mapLog(Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG, fn() => Blocks::JUNGLE_LOG());
- $this->mapLog(Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD, fn() => Blocks::JUNGLE_WOOD());
- $this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE());
- $this->mapSimple(Ids::JUNGLE_PLANKS, fn() => Blocks::JUNGLE_PLANKS());
- $this->mapSlab(Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB, fn() => Blocks::JUNGLE_SLAB());
- $this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
-
- $this->map(Ids::MANGROVE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::MANGROVE_BUTTON(), $in));
- $this->map(Ids::MANGROVE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::MANGROVE_DOOR(), $in));
- $this->map(Ids::MANGROVE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::MANGROVE_FENCE_GATE(), $in));
- $this->map(Ids::MANGROVE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::MANGROVE_PRESSURE_PLATE(), $in));
- $this->map(Ids::MANGROVE_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::MANGROVE_SIGN(), $in));
- $this->map(Ids::MANGROVE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::MANGROVE_TRAPDOOR(), $in));
- $this->map(Ids::MANGROVE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::MANGROVE_WALL_SIGN(), $in));
- $this->mapLog(Ids::MANGROVE_LOG, Ids::STRIPPED_MANGROVE_LOG, fn() => Blocks::MANGROVE_LOG());
- $this->mapSimple(Ids::MANGROVE_FENCE, fn() => Blocks::MANGROVE_FENCE());
- $this->mapSimple(Ids::MANGROVE_PLANKS, fn() => Blocks::MANGROVE_PLANKS());
- $this->mapSlab(Ids::MANGROVE_SLAB, Ids::MANGROVE_DOUBLE_SLAB, fn() => Blocks::MANGROVE_SLAB());
- $this->mapStairs(Ids::MANGROVE_STAIRS, fn() => Blocks::MANGROVE_STAIRS());
- $this->map(Ids::MANGROVE_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_WOOD(), false, $in));
- $this->map(Ids::STRIPPED_MANGROVE_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_WOOD(), true, $in));
-
- //oak - due to age, many of these don't specify "oak", making for confusing reading
- $this->map(Ids::WOODEN_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::OAK_BUTTON(), $in));
- $this->map(Ids::WOODEN_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::OAK_DOOR(), $in));
- $this->map(Ids::FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::OAK_FENCE_GATE(), $in));
- $this->map(Ids::WOODEN_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::OAK_PRESSURE_PLATE(), $in));
- $this->map(Ids::STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::OAK_SIGN(), $in));
- $this->map(Ids::TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::OAK_TRAPDOOR(), $in));
- $this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in));
- $this->mapLog(Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG, fn() => Blocks::OAK_LOG());
- $this->mapLog(Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD, fn() => Blocks::OAK_WOOD());
- $this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE());
- $this->mapSimple(Ids::OAK_PLANKS, fn() => Blocks::OAK_PLANKS());
- $this->mapSlab(Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB, fn() => Blocks::OAK_SLAB());
- $this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
-
- $this->map(Ids::PALE_OAK_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::PALE_OAK_BUTTON(), $in));
- $this->map(Ids::PALE_OAK_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::PALE_OAK_DOOR(), $in));
- $this->map(Ids::PALE_OAK_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::PALE_OAK_FENCE_GATE(), $in));
- $this->map(Ids::PALE_OAK_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::PALE_OAK_PRESSURE_PLATE(), $in));
- $this->map(Ids::PALE_OAK_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::PALE_OAK_SIGN(), $in));
- $this->map(Ids::PALE_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::PALE_OAK_TRAPDOOR(), $in));
- $this->map(Ids::PALE_OAK_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::PALE_OAK_WALL_SIGN(), $in));
- $this->mapLog(Ids::PALE_OAK_LOG, Ids::STRIPPED_PALE_OAK_LOG, fn() => Blocks::PALE_OAK_LOG());
- $this->mapLog(Ids::PALE_OAK_WOOD, Ids::STRIPPED_PALE_OAK_WOOD, fn() => Blocks::PALE_OAK_WOOD());
- $this->mapSimple(Ids::PALE_OAK_FENCE, fn() => Blocks::PALE_OAK_FENCE());
- $this->mapSimple(Ids::PALE_OAK_PLANKS, fn() => Blocks::PALE_OAK_PLANKS());
- $this->mapSlab(Ids::PALE_OAK_SLAB, Ids::PALE_OAK_DOUBLE_SLAB, fn() => Blocks::PALE_OAK_SLAB());
- $this->mapStairs(Ids::PALE_OAK_STAIRS, fn() => Blocks::PALE_OAK_STAIRS());
-
- $this->map(Ids::SPRUCE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::SPRUCE_BUTTON(), $in));
- $this->map(Ids::SPRUCE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::SPRUCE_DOOR(), $in));
- $this->map(Ids::SPRUCE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::SPRUCE_FENCE_GATE(), $in));
- $this->map(Ids::SPRUCE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::SPRUCE_PRESSURE_PLATE(), $in));
- $this->map(Ids::SPRUCE_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::SPRUCE_SIGN(), $in));
- $this->map(Ids::SPRUCE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::SPRUCE_TRAPDOOR(), $in));
- $this->map(Ids::SPRUCE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::SPRUCE_WALL_SIGN(), $in));
- $this->mapLog(Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG, fn() => Blocks::SPRUCE_LOG());
- $this->mapLog(Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD, fn() => Blocks::SPRUCE_WOOD());
- $this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE());
- $this->mapSimple(Ids::SPRUCE_PLANKS, fn() => Blocks::SPRUCE_PLANKS());
- $this->mapSlab(Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB, fn() => Blocks::SPRUCE_SLAB());
- $this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
-
- $this->map(Ids::WARPED_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::WARPED_BUTTON(), $in));
- $this->map(Ids::WARPED_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::WARPED_DOOR(), $in));
- $this->map(Ids::WARPED_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::WARPED_FENCE_GATE(), $in));
- $this->map(Ids::WARPED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::WARPED_PRESSURE_PLATE(), $in));
- $this->map(Ids::WARPED_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::WARPED_SIGN(), $in));
- $this->map(Ids::WARPED_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::WARPED_TRAPDOOR(), $in));
- $this->map(Ids::WARPED_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::WARPED_WALL_SIGN(), $in));
- $this->mapLog(Ids::WARPED_HYPHAE, Ids::STRIPPED_WARPED_HYPHAE, fn() => Blocks::WARPED_HYPHAE());
- $this->mapLog(Ids::WARPED_STEM, Ids::STRIPPED_WARPED_STEM, fn() => Blocks::WARPED_STEM());
- $this->mapSimple(Ids::WARPED_FENCE, fn() => Blocks::WARPED_FENCE());
- $this->mapSimple(Ids::WARPED_PLANKS, fn() => Blocks::WARPED_PLANKS());
- $this->mapSlab(Ids::WARPED_SLAB, Ids::WARPED_DOUBLE_SLAB, fn() => Blocks::WARPED_SLAB());
- $this->mapStairs(Ids::WARPED_STAIRS, fn() => Blocks::WARPED_STAIRS());
- }
-
- private function registerLeavesDeserializers() : void{
- $this->map(Ids::ACACIA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::ACACIA_LEAVES(), $in));
- $this->map(Ids::AZALEA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::AZALEA_LEAVES(), $in));
- $this->map(Ids::AZALEA_LEAVES_FLOWERED, fn(Reader $in) => Helper::decodeLeaves(Blocks::FLOWERING_AZALEA_LEAVES(), $in));
- $this->map(Ids::BIRCH_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::BIRCH_LEAVES(), $in));
- $this->map(Ids::CHERRY_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::CHERRY_LEAVES(), $in));
- $this->map(Ids::DARK_OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::DARK_OAK_LEAVES(), $in));
- $this->map(Ids::JUNGLE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::JUNGLE_LEAVES(), $in));
- $this->map(Ids::MANGROVE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::MANGROVE_LEAVES(), $in));
- $this->map(Ids::OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::OAK_LEAVES(), $in));
- $this->map(Ids::PALE_OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::PALE_OAK_LEAVES(), $in));
- $this->map(Ids::SPRUCE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::SPRUCE_LEAVES(), $in));
- }
-
- private function registerSaplingDeserializers() : void{
- foreach([
- Ids::ACACIA_SAPLING => fn() => Blocks::ACACIA_SAPLING(),
- Ids::BIRCH_SAPLING => fn() => Blocks::BIRCH_SAPLING(),
- Ids::DARK_OAK_SAPLING => fn() => Blocks::DARK_OAK_SAPLING(),
- Ids::JUNGLE_SAPLING => fn() => Blocks::JUNGLE_SAPLING(),
- Ids::OAK_SAPLING => fn() => Blocks::OAK_SAPLING(),
- Ids::SPRUCE_SAPLING => fn() => Blocks::SPRUCE_SAPLING(),
- ] as $id => $getBlock){
- $this->map($id, fn(Reader $in) => Helper::decodeSapling($getBlock(), $in));
- }
- }
-
- private function registerLightDeserializers() : void{
- foreach([
- Ids::LIGHT_BLOCK_0 => 0,
- Ids::LIGHT_BLOCK_1 => 1,
- Ids::LIGHT_BLOCK_2 => 2,
- Ids::LIGHT_BLOCK_3 => 3,
- Ids::LIGHT_BLOCK_4 => 4,
- Ids::LIGHT_BLOCK_5 => 5,
- Ids::LIGHT_BLOCK_6 => 6,
- Ids::LIGHT_BLOCK_7 => 7,
- Ids::LIGHT_BLOCK_8 => 8,
- Ids::LIGHT_BLOCK_9 => 9,
- Ids::LIGHT_BLOCK_10 => 10,
- Ids::LIGHT_BLOCK_11 => 11,
- Ids::LIGHT_BLOCK_12 => 12,
- Ids::LIGHT_BLOCK_13 => 13,
- Ids::LIGHT_BLOCK_14 => 14,
- Ids::LIGHT_BLOCK_15 => 15,
- ] as $id => $level){
- $this->mapSimple($id, fn() => Blocks::LIGHT()->setLightLevel($level));
- }
- }
-
- private function registerMobHeadDeserializers() : void{
- foreach([
- Ids::CREEPER_HEAD => MobHeadType::CREEPER,
- Ids::DRAGON_HEAD => MobHeadType::DRAGON,
- Ids::PIGLIN_HEAD => MobHeadType::PIGLIN,
- Ids::PLAYER_HEAD => MobHeadType::PLAYER,
- Ids::SKELETON_SKULL => MobHeadType::SKELETON,
- Ids::WITHER_SKELETON_SKULL => MobHeadType::WITHER_SKELETON,
- Ids::ZOMBIE_HEAD => MobHeadType::ZOMBIE
- ] as $id => $mobHeadType){
- $this->map($id, fn(Reader $in) => Blocks::MOB_HEAD()->setMobHeadType($mobHeadType)->setFacing($in->readFacingWithoutDown()));
- }
- }
-
- /**
- * @phpstan-param \Closure(Reader) : (CopperMaterial&Block) $deserializer
- */
- private function mapCopper(
- string $normalId,
- string $waxedNormalId,
- string $exposedId,
- string $waxedExposedId,
- string $weatheredId,
- string $waxedWeatheredId,
- string $oxidizedId,
- string $waxedOxidizedId,
- \Closure $deserializer
- ) : void{
- foreach(Utils::stringifyKeys([
- $normalId => [CopperOxidation::NONE, false],
- $waxedNormalId => [CopperOxidation::NONE, true],
- $exposedId => [CopperOxidation::EXPOSED, false],
- $waxedExposedId => [CopperOxidation::EXPOSED, true],
- $weatheredId => [CopperOxidation::WEATHERED, false],
- $waxedWeatheredId => [CopperOxidation::WEATHERED, true],
- $oxidizedId => [CopperOxidation::OXIDIZED, false],
- $waxedOxidizedId => [CopperOxidation::OXIDIZED, true],
- ]) as $id => [$oxidation, $waxed]){
- $this->map($id, fn(Reader $in) => $deserializer($in)->setOxidation($oxidation)->setWaxed($waxed));
- }
- }
-
- private function registerCopperDeserializers() : void{
- $this->mapCopper(
- Ids::CUT_COPPER_SLAB,
- Ids::WAXED_CUT_COPPER_SLAB,
- Ids::EXPOSED_CUT_COPPER_SLAB,
- Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
- Ids::WEATHERED_CUT_COPPER_SLAB,
- Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
- Ids::OXIDIZED_CUT_COPPER_SLAB,
- Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB,
- fn(Reader $in) => Helper::decodeSingleSlab(Blocks::CUT_COPPER_SLAB(), $in)
- );
- $this->mapCopper(
- Ids::DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
- Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
- Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB,
- Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB,
- fn(Reader $in) => Helper::decodeDoubleSlab(Blocks::CUT_COPPER_SLAB(), $in)
- );
-
- $this->mapCopper(
- Ids::COPPER_BULB,
- Ids::WAXED_COPPER_BULB,
- Ids::EXPOSED_COPPER_BULB,
- Ids::WAXED_EXPOSED_COPPER_BULB,
- Ids::WEATHERED_COPPER_BULB,
- Ids::WAXED_WEATHERED_COPPER_BULB,
- Ids::OXIDIZED_COPPER_BULB,
- Ids::WAXED_OXIDIZED_COPPER_BULB,
- fn(Reader $in) => Blocks::COPPER_BULB()
- ->setLit($in->readBool(StateNames::LIT))
- ->setPowered($in->readBool(StateNames::POWERED_BIT))
- );
- $this->mapCopper(
- Ids::COPPER_DOOR,
- Ids::WAXED_COPPER_DOOR,
- Ids::EXPOSED_COPPER_DOOR,
- Ids::WAXED_EXPOSED_COPPER_DOOR,
- Ids::WEATHERED_COPPER_DOOR,
- Ids::WAXED_WEATHERED_COPPER_DOOR,
- Ids::OXIDIZED_COPPER_DOOR,
- Ids::WAXED_OXIDIZED_COPPER_DOOR,
- fn(Reader $in) => Helper::decodeDoor(Blocks::COPPER_DOOR(), $in)
- );
- $this->mapCopper(
- Ids::COPPER_TRAPDOOR,
- Ids::WAXED_COPPER_TRAPDOOR,
- Ids::EXPOSED_COPPER_TRAPDOOR,
- Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
- Ids::WEATHERED_COPPER_TRAPDOOR,
- Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
- Ids::OXIDIZED_COPPER_TRAPDOOR,
- Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR,
- fn(Reader $in) => Helper::decodeTrapdoor(Blocks::COPPER_TRAPDOOR(), $in)
- );
- $this->mapCopper(
- Ids::COPPER_BLOCK,
- Ids::WAXED_COPPER,
- Ids::EXPOSED_COPPER,
- Ids::WAXED_EXPOSED_COPPER,
- Ids::WEATHERED_COPPER,
- Ids::WAXED_WEATHERED_COPPER,
- Ids::OXIDIZED_COPPER,
- Ids::WAXED_OXIDIZED_COPPER,
- fn(Reader $in) => Blocks::COPPER()
- );
- $this->mapCopper(
- Ids::CHISELED_COPPER,
- Ids::WAXED_CHISELED_COPPER,
- Ids::EXPOSED_CHISELED_COPPER,
- Ids::WAXED_EXPOSED_CHISELED_COPPER,
- Ids::WEATHERED_CHISELED_COPPER,
- Ids::WAXED_WEATHERED_CHISELED_COPPER,
- Ids::OXIDIZED_CHISELED_COPPER,
- Ids::WAXED_OXIDIZED_CHISELED_COPPER,
- fn(Reader $in) => Blocks::CHISELED_COPPER()
- );
- $this->mapCopper(
- Ids::COPPER_GRATE,
- Ids::WAXED_COPPER_GRATE,
- Ids::EXPOSED_COPPER_GRATE,
- Ids::WAXED_EXPOSED_COPPER_GRATE,
- Ids::WEATHERED_COPPER_GRATE,
- Ids::WAXED_WEATHERED_COPPER_GRATE,
- Ids::OXIDIZED_COPPER_GRATE,
- Ids::WAXED_OXIDIZED_COPPER_GRATE,
- fn(Reader $in) => Blocks::COPPER_GRATE()
- );
- $this->mapCopper(
- Ids::CUT_COPPER,
- Ids::WAXED_CUT_COPPER,
- Ids::EXPOSED_CUT_COPPER,
- Ids::WAXED_EXPOSED_CUT_COPPER,
- Ids::WEATHERED_CUT_COPPER,
- Ids::WAXED_WEATHERED_CUT_COPPER,
- Ids::OXIDIZED_CUT_COPPER,
- Ids::WAXED_OXIDIZED_CUT_COPPER,
- fn(Reader $in) => Blocks::CUT_COPPER()
- );
- $this->mapCopper(
- Ids::CUT_COPPER_STAIRS,
- Ids::WAXED_CUT_COPPER_STAIRS,
- Ids::EXPOSED_CUT_COPPER_STAIRS,
- Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
- Ids::WEATHERED_CUT_COPPER_STAIRS,
- Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
- Ids::OXIDIZED_CUT_COPPER_STAIRS,
- Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS,
- fn(Reader $in) => Helper::decodeStairs(Blocks::CUT_COPPER_STAIRS(), $in)
- );
- }
-
- private function registerSimpleDeserializers() : void{
- $this->mapSimple(Ids::AIR, fn() => Blocks::AIR());
- $this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
- $this->mapSimple(Ids::ANCIENT_DEBRIS, fn() => Blocks::ANCIENT_DEBRIS());
- $this->mapSimple(Ids::ANDESITE, fn() => Blocks::ANDESITE());
- $this->mapSimple(Ids::BARRIER, fn() => Blocks::BARRIER());
- $this->mapSimple(Ids::BEACON, fn() => Blocks::BEACON());
- $this->mapSimple(Ids::BLACKSTONE, fn() => Blocks::BLACKSTONE());
- $this->mapSimple(Ids::BLUE_ICE, fn() => Blocks::BLUE_ICE());
- $this->mapSimple(Ids::BOOKSHELF, fn() => Blocks::BOOKSHELF());
- $this->mapSimple(Ids::BRICK_BLOCK, fn() => Blocks::BRICKS());
- $this->mapSimple(Ids::BROWN_MUSHROOM, fn() => Blocks::BROWN_MUSHROOM());
- $this->mapSimple(Ids::BUDDING_AMETHYST, fn() => Blocks::BUDDING_AMETHYST());
- $this->mapSimple(Ids::CALCITE, fn() => Blocks::CALCITE());
- $this->mapSimple(Ids::CARTOGRAPHY_TABLE, fn() => Blocks::CARTOGRAPHY_TABLE());
- $this->mapSimple(Ids::CHEMICAL_HEAT, fn() => Blocks::CHEMICAL_HEAT());
- $this->mapSimple(Ids::CHISELED_DEEPSLATE, fn() => Blocks::CHISELED_DEEPSLATE());
- $this->mapSimple(Ids::CHISELED_NETHER_BRICKS, fn() => Blocks::CHISELED_NETHER_BRICKS());
- $this->mapSimple(Ids::CHISELED_POLISHED_BLACKSTONE, fn() => Blocks::CHISELED_POLISHED_BLACKSTONE());
- $this->mapSimple(Ids::CHISELED_RED_SANDSTONE, fn() => Blocks::CHISELED_RED_SANDSTONE());
- $this->mapSimple(Ids::CHISELED_RESIN_BRICKS, fn() => Blocks::CHISELED_RESIN_BRICKS());
- $this->mapSimple(Ids::CHISELED_SANDSTONE, fn() => Blocks::CHISELED_SANDSTONE());
- $this->mapSimple(Ids::CHISELED_STONE_BRICKS, fn() => Blocks::CHISELED_STONE_BRICKS());
- $this->mapSimple(Ids::CHISELED_TUFF, fn() => Blocks::CHISELED_TUFF());
- $this->mapSimple(Ids::CHISELED_TUFF_BRICKS, fn() => Blocks::CHISELED_TUFF_BRICKS());
- $this->mapSimple(Ids::CHORUS_PLANT, fn() => Blocks::CHORUS_PLANT());
- $this->mapSimple(Ids::CLAY, fn() => Blocks::CLAY());
- $this->mapSimple(Ids::COAL_BLOCK, fn() => Blocks::COAL());
- $this->mapSimple(Ids::COAL_ORE, fn() => Blocks::COAL_ORE());
- $this->mapSimple(Ids::COBBLED_DEEPSLATE, fn() => Blocks::COBBLED_DEEPSLATE());
- $this->mapSimple(Ids::COBBLESTONE, fn() => Blocks::COBBLESTONE());
- $this->mapSimple(Ids::COPPER_ORE, fn() => Blocks::COPPER_ORE());
- $this->mapSimple(Ids::CRACKED_DEEPSLATE_BRICKS, fn() => Blocks::CRACKED_DEEPSLATE_BRICKS());
- $this->mapSimple(Ids::CRACKED_DEEPSLATE_TILES, fn() => Blocks::CRACKED_DEEPSLATE_TILES());
- $this->mapSimple(Ids::CRACKED_NETHER_BRICKS, fn() => Blocks::CRACKED_NETHER_BRICKS());
- $this->mapSimple(Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS());
- $this->mapSimple(Ids::CRACKED_STONE_BRICKS, fn() => Blocks::CRACKED_STONE_BRICKS());
- $this->mapSimple(Ids::CRAFTING_TABLE, fn() => Blocks::CRAFTING_TABLE());
- $this->mapSimple(Ids::CRIMSON_ROOTS, fn() => Blocks::CRIMSON_ROOTS());
- $this->mapSimple(Ids::CRYING_OBSIDIAN, fn() => Blocks::CRYING_OBSIDIAN());
- $this->mapSimple(Ids::CUT_RED_SANDSTONE, fn() => Blocks::CUT_RED_SANDSTONE());
- $this->mapSimple(Ids::CUT_SANDSTONE, fn() => Blocks::CUT_SANDSTONE());
- $this->mapSimple(Ids::DARK_PRISMARINE, fn() => Blocks::DARK_PRISMARINE());
- $this->mapSimple(Ids::DEADBUSH, fn() => Blocks::DEAD_BUSH());
- $this->mapSimple(Ids::DEEPSLATE_BRICKS, fn() => Blocks::DEEPSLATE_BRICKS());
- $this->mapSimple(Ids::DEEPSLATE_COAL_ORE, fn() => Blocks::DEEPSLATE_COAL_ORE());
- $this->mapSimple(Ids::DEEPSLATE_COPPER_ORE, fn() => Blocks::DEEPSLATE_COPPER_ORE());
- $this->mapSimple(Ids::DEEPSLATE_DIAMOND_ORE, fn() => Blocks::DEEPSLATE_DIAMOND_ORE());
- $this->mapSimple(Ids::DEEPSLATE_EMERALD_ORE, fn() => Blocks::DEEPSLATE_EMERALD_ORE());
- $this->mapSimple(Ids::DEEPSLATE_GOLD_ORE, fn() => Blocks::DEEPSLATE_GOLD_ORE());
- $this->mapSimple(Ids::DEEPSLATE_IRON_ORE, fn() => Blocks::DEEPSLATE_IRON_ORE());
- $this->mapSimple(Ids::DEEPSLATE_LAPIS_ORE, fn() => Blocks::DEEPSLATE_LAPIS_LAZULI_ORE());
- $this->mapSimple(Ids::DEEPSLATE_TILES, fn() => Blocks::DEEPSLATE_TILES());
- $this->mapSimple(Ids::DIAMOND_BLOCK, fn() => Blocks::DIAMOND());
- $this->mapSimple(Ids::DIAMOND_ORE, fn() => Blocks::DIAMOND_ORE());
- $this->mapSimple(Ids::DIORITE, fn() => Blocks::DIORITE());
- $this->mapSimple(Ids::DRAGON_EGG, fn() => Blocks::DRAGON_EGG());
- $this->mapSimple(Ids::DRIED_KELP_BLOCK, fn() => Blocks::DRIED_KELP());
- $this->mapSimple(Ids::ELEMENT_0, fn() => Blocks::ELEMENT_ZERO());
- $this->mapSimple(Ids::ELEMENT_1, fn() => Blocks::ELEMENT_HYDROGEN());
- $this->mapSimple(Ids::ELEMENT_10, fn() => Blocks::ELEMENT_NEON());
- $this->mapSimple(Ids::ELEMENT_100, fn() => Blocks::ELEMENT_FERMIUM());
- $this->mapSimple(Ids::ELEMENT_101, fn() => Blocks::ELEMENT_MENDELEVIUM());
- $this->mapSimple(Ids::ELEMENT_102, fn() => Blocks::ELEMENT_NOBELIUM());
- $this->mapSimple(Ids::ELEMENT_103, fn() => Blocks::ELEMENT_LAWRENCIUM());
- $this->mapSimple(Ids::ELEMENT_104, fn() => Blocks::ELEMENT_RUTHERFORDIUM());
- $this->mapSimple(Ids::ELEMENT_105, fn() => Blocks::ELEMENT_DUBNIUM());
- $this->mapSimple(Ids::ELEMENT_106, fn() => Blocks::ELEMENT_SEABORGIUM());
- $this->mapSimple(Ids::ELEMENT_107, fn() => Blocks::ELEMENT_BOHRIUM());
- $this->mapSimple(Ids::ELEMENT_108, fn() => Blocks::ELEMENT_HASSIUM());
- $this->mapSimple(Ids::ELEMENT_109, fn() => Blocks::ELEMENT_MEITNERIUM());
- $this->mapSimple(Ids::ELEMENT_11, fn() => Blocks::ELEMENT_SODIUM());
- $this->mapSimple(Ids::ELEMENT_110, fn() => Blocks::ELEMENT_DARMSTADTIUM());
- $this->mapSimple(Ids::ELEMENT_111, fn() => Blocks::ELEMENT_ROENTGENIUM());
- $this->mapSimple(Ids::ELEMENT_112, fn() => Blocks::ELEMENT_COPERNICIUM());
- $this->mapSimple(Ids::ELEMENT_113, fn() => Blocks::ELEMENT_NIHONIUM());
- $this->mapSimple(Ids::ELEMENT_114, fn() => Blocks::ELEMENT_FLEROVIUM());
- $this->mapSimple(Ids::ELEMENT_115, fn() => Blocks::ELEMENT_MOSCOVIUM());
- $this->mapSimple(Ids::ELEMENT_116, fn() => Blocks::ELEMENT_LIVERMORIUM());
- $this->mapSimple(Ids::ELEMENT_117, fn() => Blocks::ELEMENT_TENNESSINE());
- $this->mapSimple(Ids::ELEMENT_118, fn() => Blocks::ELEMENT_OGANESSON());
- $this->mapSimple(Ids::ELEMENT_12, fn() => Blocks::ELEMENT_MAGNESIUM());
- $this->mapSimple(Ids::ELEMENT_13, fn() => Blocks::ELEMENT_ALUMINUM());
- $this->mapSimple(Ids::ELEMENT_14, fn() => Blocks::ELEMENT_SILICON());
- $this->mapSimple(Ids::ELEMENT_15, fn() => Blocks::ELEMENT_PHOSPHORUS());
- $this->mapSimple(Ids::ELEMENT_16, fn() => Blocks::ELEMENT_SULFUR());
- $this->mapSimple(Ids::ELEMENT_17, fn() => Blocks::ELEMENT_CHLORINE());
- $this->mapSimple(Ids::ELEMENT_18, fn() => Blocks::ELEMENT_ARGON());
- $this->mapSimple(Ids::ELEMENT_19, fn() => Blocks::ELEMENT_POTASSIUM());
- $this->mapSimple(Ids::ELEMENT_2, fn() => Blocks::ELEMENT_HELIUM());
- $this->mapSimple(Ids::ELEMENT_20, fn() => Blocks::ELEMENT_CALCIUM());
- $this->mapSimple(Ids::ELEMENT_21, fn() => Blocks::ELEMENT_SCANDIUM());
- $this->mapSimple(Ids::ELEMENT_22, fn() => Blocks::ELEMENT_TITANIUM());
- $this->mapSimple(Ids::ELEMENT_23, fn() => Blocks::ELEMENT_VANADIUM());
- $this->mapSimple(Ids::ELEMENT_24, fn() => Blocks::ELEMENT_CHROMIUM());
- $this->mapSimple(Ids::ELEMENT_25, fn() => Blocks::ELEMENT_MANGANESE());
- $this->mapSimple(Ids::ELEMENT_26, fn() => Blocks::ELEMENT_IRON());
- $this->mapSimple(Ids::ELEMENT_27, fn() => Blocks::ELEMENT_COBALT());
- $this->mapSimple(Ids::ELEMENT_28, fn() => Blocks::ELEMENT_NICKEL());
- $this->mapSimple(Ids::ELEMENT_29, fn() => Blocks::ELEMENT_COPPER());
- $this->mapSimple(Ids::ELEMENT_3, fn() => Blocks::ELEMENT_LITHIUM());
- $this->mapSimple(Ids::ELEMENT_30, fn() => Blocks::ELEMENT_ZINC());
- $this->mapSimple(Ids::ELEMENT_31, fn() => Blocks::ELEMENT_GALLIUM());
- $this->mapSimple(Ids::ELEMENT_32, fn() => Blocks::ELEMENT_GERMANIUM());
- $this->mapSimple(Ids::ELEMENT_33, fn() => Blocks::ELEMENT_ARSENIC());
- $this->mapSimple(Ids::ELEMENT_34, fn() => Blocks::ELEMENT_SELENIUM());
- $this->mapSimple(Ids::ELEMENT_35, fn() => Blocks::ELEMENT_BROMINE());
- $this->mapSimple(Ids::ELEMENT_36, fn() => Blocks::ELEMENT_KRYPTON());
- $this->mapSimple(Ids::ELEMENT_37, fn() => Blocks::ELEMENT_RUBIDIUM());
- $this->mapSimple(Ids::ELEMENT_38, fn() => Blocks::ELEMENT_STRONTIUM());
- $this->mapSimple(Ids::ELEMENT_39, fn() => Blocks::ELEMENT_YTTRIUM());
- $this->mapSimple(Ids::ELEMENT_4, fn() => Blocks::ELEMENT_BERYLLIUM());
- $this->mapSimple(Ids::ELEMENT_40, fn() => Blocks::ELEMENT_ZIRCONIUM());
- $this->mapSimple(Ids::ELEMENT_41, fn() => Blocks::ELEMENT_NIOBIUM());
- $this->mapSimple(Ids::ELEMENT_42, fn() => Blocks::ELEMENT_MOLYBDENUM());
- $this->mapSimple(Ids::ELEMENT_43, fn() => Blocks::ELEMENT_TECHNETIUM());
- $this->mapSimple(Ids::ELEMENT_44, fn() => Blocks::ELEMENT_RUTHENIUM());
- $this->mapSimple(Ids::ELEMENT_45, fn() => Blocks::ELEMENT_RHODIUM());
- $this->mapSimple(Ids::ELEMENT_46, fn() => Blocks::ELEMENT_PALLADIUM());
- $this->mapSimple(Ids::ELEMENT_47, fn() => Blocks::ELEMENT_SILVER());
- $this->mapSimple(Ids::ELEMENT_48, fn() => Blocks::ELEMENT_CADMIUM());
- $this->mapSimple(Ids::ELEMENT_49, fn() => Blocks::ELEMENT_INDIUM());
- $this->mapSimple(Ids::ELEMENT_5, fn() => Blocks::ELEMENT_BORON());
- $this->mapSimple(Ids::ELEMENT_50, fn() => Blocks::ELEMENT_TIN());
- $this->mapSimple(Ids::ELEMENT_51, fn() => Blocks::ELEMENT_ANTIMONY());
- $this->mapSimple(Ids::ELEMENT_52, fn() => Blocks::ELEMENT_TELLURIUM());
- $this->mapSimple(Ids::ELEMENT_53, fn() => Blocks::ELEMENT_IODINE());
- $this->mapSimple(Ids::ELEMENT_54, fn() => Blocks::ELEMENT_XENON());
- $this->mapSimple(Ids::ELEMENT_55, fn() => Blocks::ELEMENT_CESIUM());
- $this->mapSimple(Ids::ELEMENT_56, fn() => Blocks::ELEMENT_BARIUM());
- $this->mapSimple(Ids::ELEMENT_57, fn() => Blocks::ELEMENT_LANTHANUM());
- $this->mapSimple(Ids::ELEMENT_58, fn() => Blocks::ELEMENT_CERIUM());
- $this->mapSimple(Ids::ELEMENT_59, fn() => Blocks::ELEMENT_PRASEODYMIUM());
- $this->mapSimple(Ids::ELEMENT_6, fn() => Blocks::ELEMENT_CARBON());
- $this->mapSimple(Ids::ELEMENT_60, fn() => Blocks::ELEMENT_NEODYMIUM());
- $this->mapSimple(Ids::ELEMENT_61, fn() => Blocks::ELEMENT_PROMETHIUM());
- $this->mapSimple(Ids::ELEMENT_62, fn() => Blocks::ELEMENT_SAMARIUM());
- $this->mapSimple(Ids::ELEMENT_63, fn() => Blocks::ELEMENT_EUROPIUM());
- $this->mapSimple(Ids::ELEMENT_64, fn() => Blocks::ELEMENT_GADOLINIUM());
- $this->mapSimple(Ids::ELEMENT_65, fn() => Blocks::ELEMENT_TERBIUM());
- $this->mapSimple(Ids::ELEMENT_66, fn() => Blocks::ELEMENT_DYSPROSIUM());
- $this->mapSimple(Ids::ELEMENT_67, fn() => Blocks::ELEMENT_HOLMIUM());
- $this->mapSimple(Ids::ELEMENT_68, fn() => Blocks::ELEMENT_ERBIUM());
- $this->mapSimple(Ids::ELEMENT_69, fn() => Blocks::ELEMENT_THULIUM());
- $this->mapSimple(Ids::ELEMENT_7, fn() => Blocks::ELEMENT_NITROGEN());
- $this->mapSimple(Ids::ELEMENT_70, fn() => Blocks::ELEMENT_YTTERBIUM());
- $this->mapSimple(Ids::ELEMENT_71, fn() => Blocks::ELEMENT_LUTETIUM());
- $this->mapSimple(Ids::ELEMENT_72, fn() => Blocks::ELEMENT_HAFNIUM());
- $this->mapSimple(Ids::ELEMENT_73, fn() => Blocks::ELEMENT_TANTALUM());
- $this->mapSimple(Ids::ELEMENT_74, fn() => Blocks::ELEMENT_TUNGSTEN());
- $this->mapSimple(Ids::ELEMENT_75, fn() => Blocks::ELEMENT_RHENIUM());
- $this->mapSimple(Ids::ELEMENT_76, fn() => Blocks::ELEMENT_OSMIUM());
- $this->mapSimple(Ids::ELEMENT_77, fn() => Blocks::ELEMENT_IRIDIUM());
- $this->mapSimple(Ids::ELEMENT_78, fn() => Blocks::ELEMENT_PLATINUM());
- $this->mapSimple(Ids::ELEMENT_79, fn() => Blocks::ELEMENT_GOLD());
- $this->mapSimple(Ids::ELEMENT_8, fn() => Blocks::ELEMENT_OXYGEN());
- $this->mapSimple(Ids::ELEMENT_80, fn() => Blocks::ELEMENT_MERCURY());
- $this->mapSimple(Ids::ELEMENT_81, fn() => Blocks::ELEMENT_THALLIUM());
- $this->mapSimple(Ids::ELEMENT_82, fn() => Blocks::ELEMENT_LEAD());
- $this->mapSimple(Ids::ELEMENT_83, fn() => Blocks::ELEMENT_BISMUTH());
- $this->mapSimple(Ids::ELEMENT_84, fn() => Blocks::ELEMENT_POLONIUM());
- $this->mapSimple(Ids::ELEMENT_85, fn() => Blocks::ELEMENT_ASTATINE());
- $this->mapSimple(Ids::ELEMENT_86, fn() => Blocks::ELEMENT_RADON());
- $this->mapSimple(Ids::ELEMENT_87, fn() => Blocks::ELEMENT_FRANCIUM());
- $this->mapSimple(Ids::ELEMENT_88, fn() => Blocks::ELEMENT_RADIUM());
- $this->mapSimple(Ids::ELEMENT_89, fn() => Blocks::ELEMENT_ACTINIUM());
- $this->mapSimple(Ids::ELEMENT_9, fn() => Blocks::ELEMENT_FLUORINE());
- $this->mapSimple(Ids::ELEMENT_90, fn() => Blocks::ELEMENT_THORIUM());
- $this->mapSimple(Ids::ELEMENT_91, fn() => Blocks::ELEMENT_PROTACTINIUM());
- $this->mapSimple(Ids::ELEMENT_92, fn() => Blocks::ELEMENT_URANIUM());
- $this->mapSimple(Ids::ELEMENT_93, fn() => Blocks::ELEMENT_NEPTUNIUM());
- $this->mapSimple(Ids::ELEMENT_94, fn() => Blocks::ELEMENT_PLUTONIUM());
- $this->mapSimple(Ids::ELEMENT_95, fn() => Blocks::ELEMENT_AMERICIUM());
- $this->mapSimple(Ids::ELEMENT_96, fn() => Blocks::ELEMENT_CURIUM());
- $this->mapSimple(Ids::ELEMENT_97, fn() => Blocks::ELEMENT_BERKELIUM());
- $this->mapSimple(Ids::ELEMENT_98, fn() => Blocks::ELEMENT_CALIFORNIUM());
- $this->mapSimple(Ids::ELEMENT_99, fn() => Blocks::ELEMENT_EINSTEINIUM());
- $this->mapSimple(Ids::EMERALD_BLOCK, fn() => Blocks::EMERALD());
- $this->mapSimple(Ids::EMERALD_ORE, fn() => Blocks::EMERALD_ORE());
- $this->mapSimple(Ids::ENCHANTING_TABLE, fn() => Blocks::ENCHANTING_TABLE());
- $this->mapSimple(Ids::END_BRICKS, fn() => Blocks::END_STONE_BRICKS());
- $this->mapSimple(Ids::END_STONE, fn() => Blocks::END_STONE());
- $this->mapSimple(Ids::FERN, fn() => Blocks::FERN());
- $this->mapSimple(Ids::FLETCHING_TABLE, fn() => Blocks::FLETCHING_TABLE());
- $this->mapSimple(Ids::GILDED_BLACKSTONE, fn() => Blocks::GILDED_BLACKSTONE());
- $this->mapSimple(Ids::GLASS, fn() => Blocks::GLASS());
- $this->mapSimple(Ids::GLASS_PANE, fn() => Blocks::GLASS_PANE());
- $this->mapSimple(Ids::GLOWINGOBSIDIAN, fn() => Blocks::GLOWING_OBSIDIAN());
- $this->mapSimple(Ids::GLOWSTONE, fn() => Blocks::GLOWSTONE());
- $this->mapSimple(Ids::GOLD_BLOCK, fn() => Blocks::GOLD());
- $this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE());
- $this->mapSimple(Ids::GRANITE, fn() => Blocks::GRANITE());
- $this->mapSimple(Ids::GRASS_BLOCK, fn() => Blocks::GRASS());
- $this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH());
- $this->mapSimple(Ids::GRAVEL, fn() => Blocks::GRAVEL());
- $this->mapSimple(Ids::HANGING_ROOTS, fn() => Blocks::HANGING_ROOTS());
- $this->mapSimple(Ids::HARD_GLASS, fn() => Blocks::HARDENED_GLASS());
- $this->mapSimple(Ids::HARD_GLASS_PANE, fn() => Blocks::HARDENED_GLASS_PANE());
- $this->mapSimple(Ids::HARDENED_CLAY, fn() => Blocks::HARDENED_CLAY());
- $this->mapSimple(Ids::HONEYCOMB_BLOCK, fn() => Blocks::HONEYCOMB());
- $this->mapSimple(Ids::ICE, fn() => Blocks::ICE());
- $this->mapSimple(Ids::INFESTED_CHISELED_STONE_BRICKS, fn() => Blocks::INFESTED_CHISELED_STONE_BRICK());
- $this->mapSimple(Ids::INFESTED_COBBLESTONE, fn() => Blocks::INFESTED_COBBLESTONE());
- $this->mapSimple(Ids::INFESTED_CRACKED_STONE_BRICKS, fn() => Blocks::INFESTED_CRACKED_STONE_BRICK());
- $this->mapSimple(Ids::INFESTED_MOSSY_STONE_BRICKS, fn() => Blocks::INFESTED_MOSSY_STONE_BRICK());
- $this->mapSimple(Ids::INFESTED_STONE, fn() => Blocks::INFESTED_STONE());
- $this->mapSimple(Ids::INFESTED_STONE_BRICKS, fn() => Blocks::INFESTED_STONE_BRICK());
- $this->mapSimple(Ids::INFO_UPDATE, fn() => Blocks::INFO_UPDATE());
- $this->mapSimple(Ids::INFO_UPDATE2, fn() => Blocks::INFO_UPDATE2());
- $this->mapSimple(Ids::INVISIBLE_BEDROCK, fn() => Blocks::INVISIBLE_BEDROCK());
- $this->mapSimple(Ids::IRON_BARS, fn() => Blocks::IRON_BARS());
- $this->mapSimple(Ids::IRON_BLOCK, fn() => Blocks::IRON());
- $this->mapSimple(Ids::IRON_ORE, fn() => Blocks::IRON_ORE());
- $this->mapSimple(Ids::JUKEBOX, fn() => Blocks::JUKEBOX());
- $this->mapSimple(Ids::LAPIS_BLOCK, fn() => Blocks::LAPIS_LAZULI());
- $this->mapSimple(Ids::LAPIS_ORE, fn() => Blocks::LAPIS_LAZULI_ORE());
- $this->mapSimple(Ids::MAGMA, fn() => Blocks::MAGMA());
- $this->mapSimple(Ids::MANGROVE_ROOTS, fn() => Blocks::MANGROVE_ROOTS());
- $this->mapSimple(Ids::MELON_BLOCK, fn() => Blocks::MELON());
- $this->mapSimple(Ids::MOB_SPAWNER, fn() => Blocks::MONSTER_SPAWNER());
- $this->mapSimple(Ids::MOSSY_COBBLESTONE, fn() => Blocks::MOSSY_COBBLESTONE());
- $this->mapSimple(Ids::MOSSY_STONE_BRICKS, fn() => Blocks::MOSSY_STONE_BRICKS());
- $this->mapSimple(Ids::MUD, fn() => Blocks::MUD());
- $this->mapSimple(Ids::MUD_BRICKS, fn() => Blocks::MUD_BRICKS());
- $this->mapSimple(Ids::MYCELIUM, fn() => Blocks::MYCELIUM());
- $this->mapSimple(Ids::NETHER_BRICK, fn() => Blocks::NETHER_BRICKS());
- $this->mapSimple(Ids::NETHER_BRICK_FENCE, fn() => Blocks::NETHER_BRICK_FENCE());
- $this->mapSimple(Ids::NETHER_GOLD_ORE, fn() => Blocks::NETHER_GOLD_ORE());
- $this->mapSimple(Ids::NETHER_WART_BLOCK, fn() => Blocks::NETHER_WART_BLOCK());
- $this->mapSimple(Ids::NETHERITE_BLOCK, fn() => Blocks::NETHERITE());
- $this->mapSimple(Ids::NETHERRACK, fn() => Blocks::NETHERRACK());
- $this->mapSimple(Ids::NETHERREACTOR, fn() => Blocks::NETHER_REACTOR_CORE());
- $this->mapSimple(Ids::NOTEBLOCK, fn() => Blocks::NOTE_BLOCK());
- $this->mapSimple(Ids::OBSIDIAN, fn() => Blocks::OBSIDIAN());
- $this->mapSimple(Ids::PACKED_ICE, fn() => Blocks::PACKED_ICE());
- $this->mapSimple(Ids::PACKED_MUD, fn() => Blocks::PACKED_MUD());
- $this->mapSimple(Ids::PODZOL, fn() => Blocks::PODZOL());
- $this->mapSimple(Ids::POLISHED_ANDESITE, fn() => Blocks::POLISHED_ANDESITE());
- $this->mapSimple(Ids::POLISHED_BLACKSTONE, fn() => Blocks::POLISHED_BLACKSTONE());
- $this->mapSimple(Ids::POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::POLISHED_BLACKSTONE_BRICKS());
- $this->mapSimple(Ids::POLISHED_DEEPSLATE, fn() => Blocks::POLISHED_DEEPSLATE());
- $this->mapSimple(Ids::POLISHED_DIORITE, fn() => Blocks::POLISHED_DIORITE());
- $this->mapSimple(Ids::POLISHED_GRANITE, fn() => Blocks::POLISHED_GRANITE());
- $this->mapSimple(Ids::POLISHED_TUFF, fn() => Blocks::POLISHED_TUFF());
- $this->mapSimple(Ids::PRISMARINE, fn() => Blocks::PRISMARINE());
- $this->mapSimple(Ids::PRISMARINE_BRICKS, fn() => Blocks::PRISMARINE_BRICKS());
- $this->mapSimple(Ids::QUARTZ_BRICKS, fn() => Blocks::QUARTZ_BRICKS());
- $this->mapSimple(Ids::QUARTZ_ORE, fn() => Blocks::NETHER_QUARTZ_ORE());
- $this->mapSimple(Ids::RAW_COPPER_BLOCK, fn() => Blocks::RAW_COPPER());
- $this->mapSimple(Ids::RAW_GOLD_BLOCK, fn() => Blocks::RAW_GOLD());
- $this->mapSimple(Ids::RAW_IRON_BLOCK, fn() => Blocks::RAW_IRON());
- $this->mapSimple(Ids::RED_MUSHROOM, fn() => Blocks::RED_MUSHROOM());
- $this->mapSimple(Ids::RED_NETHER_BRICK, fn() => Blocks::RED_NETHER_BRICKS());
- $this->mapSimple(Ids::RED_SAND, fn() => Blocks::RED_SAND());
- $this->mapSimple(Ids::RED_SANDSTONE, fn() => Blocks::RED_SANDSTONE());
- $this->mapSimple(Ids::REDSTONE_BLOCK, fn() => Blocks::REDSTONE());
- $this->mapSimple(Ids::REINFORCED_DEEPSLATE, fn() => Blocks::REINFORCED_DEEPSLATE());
- $this->mapSimple(Ids::RESERVED6, fn() => Blocks::RESERVED6());
- $this->mapSimple(Ids::RESIN_BLOCK, fn() => Blocks::RESIN());
- $this->mapSimple(Ids::RESIN_BRICKS, fn() => Blocks::RESIN_BRICKS());
- $this->mapSimple(Ids::SAND, fn() => Blocks::SAND());
- $this->mapSimple(Ids::SANDSTONE, fn() => Blocks::SANDSTONE());
- $this->mapSimple(Ids::SCULK, fn() => Blocks::SCULK());
- $this->mapSimple(Ids::SEA_LANTERN, fn() => Blocks::SEA_LANTERN());
- $this->mapSimple(Ids::SHORT_GRASS, fn() => Blocks::TALL_GRASS()); //no, this is not a typo - tall_grass is now the double block, just to be confusing :(
- $this->mapSimple(Ids::SHROOMLIGHT, fn() => Blocks::SHROOMLIGHT());
- $this->mapSimple(Ids::SLIME, fn() => Blocks::SLIME());
- $this->mapSimple(Ids::SMITHING_TABLE, fn() => Blocks::SMITHING_TABLE());
- $this->mapSimple(Ids::SMOOTH_BASALT, fn() => Blocks::SMOOTH_BASALT());
- $this->mapSimple(Ids::SMOOTH_RED_SANDSTONE, fn() => Blocks::SMOOTH_RED_SANDSTONE());
- $this->mapSimple(Ids::SMOOTH_SANDSTONE, fn() => Blocks::SMOOTH_SANDSTONE());
- $this->mapSimple(Ids::SMOOTH_STONE, fn() => Blocks::SMOOTH_STONE());
- $this->mapSimple(Ids::SNOW, fn() => Blocks::SNOW());
- $this->mapSimple(Ids::SOUL_SAND, fn() => Blocks::SOUL_SAND());
- $this->mapSimple(Ids::SOUL_SOIL, fn() => Blocks::SOUL_SOIL());
- $this->mapSimple(Ids::SPORE_BLOSSOM, fn() => Blocks::SPORE_BLOSSOM());
- $this->mapSimple(Ids::SPONGE, fn() => Blocks::SPONGE());
- $this->mapSimple(Ids::STONE, fn() => Blocks::STONE());
- $this->mapSimple(Ids::STONECUTTER, fn() => Blocks::LEGACY_STONECUTTER());
- $this->mapSimple(Ids::STONE_BRICKS, fn() => Blocks::STONE_BRICKS());
- $this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS());
- $this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER());
- $this->mapSimple(Ids::TUFF, fn() => Blocks::TUFF());
- $this->mapSimple(Ids::TUFF_BRICKS, fn() => Blocks::TUFF_BRICKS());
- $this->mapSimple(Ids::UNDYED_SHULKER_BOX, fn() => Blocks::SHULKER_BOX());
- $this->mapSimple(Ids::WARPED_WART_BLOCK, fn() => Blocks::WARPED_WART_BLOCK());
- $this->mapSimple(Ids::WARPED_ROOTS, fn() => Blocks::WARPED_ROOTS());
- $this->mapSimple(Ids::WATERLILY, fn() => Blocks::LILY_PAD());
- $this->mapSimple(Ids::WEB, fn() => Blocks::COBWEB());
- $this->mapSimple(Ids::WET_SPONGE, fn() => Blocks::SPONGE()->setWet(true));
- $this->mapSimple(Ids::WITHER_ROSE, fn() => Blocks::WITHER_ROSE());
- $this->mapSimple(Ids::DANDELION, fn() => Blocks::DANDELION());
-
- $this->mapSimple(Ids::ALLIUM, fn() => Blocks::ALLIUM());
- $this->mapSimple(Ids::CORNFLOWER, fn() => Blocks::CORNFLOWER());
- $this->mapSimple(Ids::AZURE_BLUET, fn() => Blocks::AZURE_BLUET());
- $this->mapSimple(Ids::LILY_OF_THE_VALLEY, fn() => Blocks::LILY_OF_THE_VALLEY());
- $this->mapSimple(Ids::BLUE_ORCHID, fn() => Blocks::BLUE_ORCHID());
- $this->mapSimple(Ids::OXEYE_DAISY, fn() => Blocks::OXEYE_DAISY());
- $this->mapSimple(Ids::POPPY, fn() => Blocks::POPPY());
- $this->mapSimple(Ids::ORANGE_TULIP, fn() => Blocks::ORANGE_TULIP());
- $this->mapSimple(Ids::PINK_TULIP, fn() => Blocks::PINK_TULIP());
- $this->mapSimple(Ids::RED_TULIP, fn() => Blocks::RED_TULIP());
- $this->mapSimple(Ids::WHITE_TULIP, fn() => Blocks::WHITE_TULIP());
- }
-
- private function registerDeserializers() : void{
- $this->map(Ids::ACTIVATOR_RAIL, function(Reader $in) : Block{
- return Blocks::ACTIVATOR_RAIL()
- ->setPowered($in->readBool(StateNames::RAIL_DATA_BIT))
- ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5));
- });
- $this->map(Ids::AMETHYST_CLUSTER, function(Reader $in) : Block{
- return Blocks::AMETHYST_CLUSTER()
- ->setStage(AmethystCluster::STAGE_CLUSTER)
- ->setFacing($in->readBlockFace());
- });
- $this->mapSlab(Ids::ANDESITE_SLAB, Ids::ANDESITE_DOUBLE_SLAB, fn() => Blocks::ANDESITE_SLAB());
- $this->mapStairs(Ids::ANDESITE_STAIRS, fn() => Blocks::ANDESITE_STAIRS());
- $this->map(Ids::ANDESITE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::ANDESITE_WALL(), $in));
- $this->map(Ids::ANVIL, function(Reader $in) : Block{
- return Blocks::ANVIL()
- ->setDamage(Anvil::UNDAMAGED)
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::CHIPPED_ANVIL, function(Reader $in) : Block{
- return Blocks::ANVIL()
- ->setDamage(Anvil::SLIGHTLY_DAMAGED)
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::DAMAGED_ANVIL, function(Reader $in) : Block{
- return Blocks::ANVIL()
- ->setDamage(Anvil::VERY_DAMAGED)
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::BAMBOO, function(Reader $in) : Block{
- return Blocks::BAMBOO()
- ->setLeafSize(match($value = $in->readString(StateNames::BAMBOO_LEAF_SIZE)){
- StringValues::BAMBOO_LEAF_SIZE_NO_LEAVES => Bamboo::NO_LEAVES,
- StringValues::BAMBOO_LEAF_SIZE_SMALL_LEAVES => Bamboo::SMALL_LEAVES,
- StringValues::BAMBOO_LEAF_SIZE_LARGE_LEAVES => Bamboo::LARGE_LEAVES,
- default => throw $in->badValueException(StateNames::BAMBOO_LEAF_SIZE, $value),
- })
- ->setReady($in->readBool(StateNames::AGE_BIT))
- ->setThick(match($value = $in->readString(StateNames::BAMBOO_STALK_THICKNESS)){
- StringValues::BAMBOO_STALK_THICKNESS_THIN => false,
- StringValues::BAMBOO_STALK_THICKNESS_THICK => true,
- default => throw $in->badValueException(StateNames::BAMBOO_STALK_THICKNESS, $value),
- });
- });
- $this->map(Ids::BAMBOO_SAPLING, function(Reader $in) : Block{
- return Blocks::BAMBOO_SAPLING()->setReady($in->readBool(StateNames::AGE_BIT));
- });
- $this->map(Ids::BARREL, function(Reader $in) : Block{
- return Blocks::BARREL()
- ->setFacing($in->readFacingDirection())
- ->setOpen($in->readBool(StateNames::OPEN_BIT));
- });
- $this->map(Ids::BASALT, function(Reader $in){
- return Blocks::BASALT()
- ->setAxis($in->readPillarAxis());
- });
- $this->map(Ids::BED, function(Reader $in) : Block{
- return Blocks::BED()
- ->setFacing($in->readLegacyHorizontalFacing())
- ->setHead($in->readBool(StateNames::HEAD_PIECE_BIT))
- ->setOccupied($in->readBool(StateNames::OCCUPIED_BIT));
- });
- $this->map(Ids::BEDROCK, function(Reader $in) : Block{
- return Blocks::BEDROCK()
- ->setBurnsForever($in->readBool(StateNames::INFINIBURN_BIT));
- });
- $this->map(Ids::BEETROOT, fn(Reader $in) => Helper::decodeCrops(Blocks::BEETROOTS(), $in));
- $this->map(Ids::BELL, function(Reader $in) : Block{
- $in->ignored(StateNames::TOGGLE_BIT); //only useful at runtime
- return Blocks::BELL()
- ->setFacing($in->readLegacyHorizontalFacing())
- ->setAttachmentType($in->readBellAttachmentType());
- });
- $this->map(Ids::BIG_DRIPLEAF, function(Reader $in) : Block{
- if($in->readBool(StateNames::BIG_DRIPLEAF_HEAD)){
- return Blocks::BIG_DRIPLEAF_HEAD()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLeafState(match($type = $in->readString(StateNames::BIG_DRIPLEAF_TILT)){
- StringValues::BIG_DRIPLEAF_TILT_NONE => DripleafState::STABLE,
- StringValues::BIG_DRIPLEAF_TILT_UNSTABLE => DripleafState::UNSTABLE,
- StringValues::BIG_DRIPLEAF_TILT_PARTIAL_TILT => DripleafState::PARTIAL_TILT,
- StringValues::BIG_DRIPLEAF_TILT_FULL_TILT => DripleafState::FULL_TILT,
- default => throw $in->badValueException(StateNames::BIG_DRIPLEAF_TILT, $type),
- });
- }else{
- $in->ignored(StateNames::BIG_DRIPLEAF_TILT);
- return Blocks::BIG_DRIPLEAF_STEM()->setFacing($in->readCardinalHorizontalFacing());
- }
- });
- $this->mapSlab(Ids::BLACKSTONE_SLAB, Ids::BLACKSTONE_DOUBLE_SLAB, fn() => Blocks::BLACKSTONE_SLAB());
- $this->mapStairs(Ids::BLACKSTONE_STAIRS, fn() => Blocks::BLACKSTONE_STAIRS());
- $this->map(Ids::BLACKSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::BLACKSTONE_WALL(), $in));
- $this->map(Ids::BLAST_FURNACE, function(Reader $in) : Block{
- return Blocks::BLAST_FURNACE()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(false);
- });
- $this->map(Ids::BONE_BLOCK, function(Reader $in) : Block{
- $in->ignored(StateNames::DEPRECATED);
- return Blocks::BONE_BLOCK()->setAxis($in->readPillarAxis());
- });
- $this->map(Ids::BREWING_STAND, function(Reader $in) : Block{
- return Blocks::BREWING_STAND()
- ->setSlot(BrewingStandSlot::EAST, $in->readBool(StateNames::BREWING_STAND_SLOT_A_BIT))
- ->setSlot(BrewingStandSlot::SOUTHWEST, $in->readBool(StateNames::BREWING_STAND_SLOT_B_BIT))
- ->setSlot(BrewingStandSlot::NORTHWEST, $in->readBool(StateNames::BREWING_STAND_SLOT_C_BIT));
- });
- $this->mapSlab(Ids::BRICK_SLAB, Ids::BRICK_DOUBLE_SLAB, fn() => Blocks::BRICK_SLAB());
- $this->mapStairs(Ids::BRICK_STAIRS, fn() => Blocks::BRICK_STAIRS());
- $this->map(Ids::BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::BRICK_WALL(), $in));
- $this->map(Ids::MUSHROOM_STEM, fn(Reader $in) => match($in->readBoundedInt(StateNames::HUGE_MUSHROOM_BITS, 0, 15)){
- BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM => Blocks::ALL_SIDED_MUSHROOM_STEM(),
- BlockLegacyMetadata::MUSHROOM_BLOCK_STEM => Blocks::MUSHROOM_STEM(),
- default => throw new BlockStateDeserializeException("This state does not exist"),
- });
- $this->map(Ids::BROWN_MUSHROOM_BLOCK, fn(Reader $in) => Helper::decodeMushroomBlock(Blocks::BROWN_MUSHROOM_BLOCK(), $in));
- $this->map(Ids::CACTUS, function(Reader $in) : Block{
- return Blocks::CACTUS()
- ->setAge($in->readBoundedInt(StateNames::AGE, 0, 15));
- });
- $this->map(Ids::CAKE, function(Reader $in) : Block{
- return Blocks::CAKE()
- ->setBites($in->readBoundedInt(StateNames::BITE_COUNTER, 0, 6));
- });
- $this->map(Ids::CAMPFIRE, function(Reader $in) : Block{
- return Blocks::CAMPFIRE()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(!$in->readBool(StateNames::EXTINGUISHED));
- });
- $this->map(Ids::CARROTS, fn(Reader $in) => Helper::decodeCrops(Blocks::CARROTS(), $in));
- $this->map(Ids::CARVED_PUMPKIN, function(Reader $in) : Block{
- return Blocks::CARVED_PUMPKIN()
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::CAVE_VINES, function(Reader $in) : CaveVines{
- return Blocks::CAVE_VINES()
- ->setBerries(false)
- ->setHead(false)
- ->setAge($in->readBoundedInt(StateNames::GROWING_PLANT_AGE, 0, 25));
- });
- $this->map(Ids::CAVE_VINES_BODY_WITH_BERRIES, function(Reader $in) : CaveVines{
- return Blocks::CAVE_VINES()
- ->setBerries(true)
- ->setHead(false)
- ->setAge($in->readBoundedInt(StateNames::GROWING_PLANT_AGE, 0, 25));
- });
- $this->map(Ids::CAVE_VINES_HEAD_WITH_BERRIES, function(Reader $in) : CaveVines{
- return Blocks::CAVE_VINES()
- ->setBerries(true)
- ->setHead(true)
- ->setAge($in->readBoundedInt(StateNames::GROWING_PLANT_AGE, 0, 25));
- });
- $this->map(Ids::CHAIN, function(Reader $in) : Block{
- return Blocks::CHAIN()
- ->setAxis($in->readPillarAxis());
- });
- $this->map(Ids::CHISELED_BOOKSHELF, function(Reader $in) : Block{
- $block = Blocks::CHISELED_BOOKSHELF()
- ->setFacing($in->readLegacyHorizontalFacing());
-
- //we don't use API constant for bounds here as the data bounds might be different to what we support internally
- $flags = $in->readBoundedInt(StateNames::BOOKS_STORED, 0, (1 << 6) - 1);
- foreach(ChiseledBookshelfSlot::cases() as $slot){
- $block->setSlot($slot, ($flags & (1 << $slot->value)) !== 0);
- }
-
- return $block;
- });
- $this->map(Ids::CHISELED_QUARTZ_BLOCK, function(Reader $in) : Block{
- return Blocks::CHISELED_QUARTZ()
- ->setAxis($in->readPillarAxis());
- });
- $this->map(Ids::CHEST, function(Reader $in) : Block{
- return Blocks::CHEST()
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::CHORUS_FLOWER, function(Reader $in) : Block{
- return Blocks::CHORUS_FLOWER()
- ->setAge($in->readBoundedInt(StateNames::AGE, ChorusFlower::MIN_AGE, ChorusFlower::MAX_AGE));
- });
- $this->map(Ids::COARSE_DIRT, fn() => Blocks::DIRT()->setDirtType(DirtType::COARSE));
- $this->mapSlab(Ids::COBBLED_DEEPSLATE_SLAB, Ids::COBBLED_DEEPSLATE_DOUBLE_SLAB, fn() => Blocks::COBBLED_DEEPSLATE_SLAB());
- $this->mapStairs(Ids::COBBLED_DEEPSLATE_STAIRS, fn() => Blocks::COBBLED_DEEPSLATE_STAIRS());
- $this->map(Ids::COBBLED_DEEPSLATE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::COBBLED_DEEPSLATE_WALL(), $in));
- $this->mapSlab(Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB, fn() => Blocks::COBBLESTONE_SLAB());
- $this->map(Ids::COBBLESTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::COBBLESTONE_WALL(), $in));
- $this->map(Ids::COCOA, function(Reader $in) : Block{
- return Blocks::COCOA_POD()
- ->setAge($in->readBoundedInt(StateNames::AGE, 0, 2))
- ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()));
- });
- $this->map(Ids::COLORED_TORCH_BLUE, fn(Reader $in) => Blocks::BLUE_TORCH()->setFacing($in->readTorchFacing()));
- $this->map(Ids::COLORED_TORCH_GREEN, fn(Reader $in) => Blocks::GREEN_TORCH()->setFacing($in->readTorchFacing()));
- $this->map(Ids::COLORED_TORCH_PURPLE, fn(Reader $in) => Blocks::PURPLE_TORCH()->setFacing($in->readTorchFacing()));
- $this->map(Ids::COLORED_TORCH_RED, fn(Reader $in) => Blocks::RED_TORCH()->setFacing($in->readTorchFacing()));
- $this->map(Ids::COMPOUND_CREATOR, fn(Reader $in) => Blocks::COMPOUND_CREATOR()
- ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
- );
- $this->mapSlab(Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_RED_SANDSTONE_SLAB());
- $this->mapSlab(Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_SANDSTONE_SLAB());
- $this->mapSlab(Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB, fn() => Blocks::DARK_PRISMARINE_SLAB());
- $this->mapStairs(Ids::DARK_PRISMARINE_STAIRS, fn() => Blocks::DARK_PRISMARINE_STAIRS());
- $this->map(Ids::DAYLIGHT_DETECTOR, fn(Reader $in) => Helper::decodeDaylightSensor(Blocks::DAYLIGHT_SENSOR(), $in)
- ->setInverted(false));
- $this->map(Ids::DAYLIGHT_DETECTOR_INVERTED, fn(Reader $in) => Helper::decodeDaylightSensor(Blocks::DAYLIGHT_SENSOR(), $in)
- ->setInverted(true));
- $this->map(Ids::DEEPSLATE, function(Reader $in) : Block{
- return Blocks::DEEPSLATE()
- ->setAxis($in->readPillarAxis());
- });
- $this->mapSlab(Ids::DEEPSLATE_BRICK_SLAB, Ids::DEEPSLATE_BRICK_DOUBLE_SLAB, fn() => Blocks::DEEPSLATE_BRICK_SLAB());
- $this->mapStairs(Ids::DEEPSLATE_BRICK_STAIRS, fn() => Blocks::DEEPSLATE_BRICK_STAIRS());
- $this->map(Ids::DEEPSLATE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::DEEPSLATE_BRICK_WALL(), $in));
- $this->map(Ids::DEEPSLATE_REDSTONE_ORE, fn() => Blocks::DEEPSLATE_REDSTONE_ORE()->setLit(false));
- $this->mapSlab(Ids::DEEPSLATE_TILE_SLAB, Ids::DEEPSLATE_TILE_DOUBLE_SLAB, fn() => Blocks::DEEPSLATE_TILE_SLAB());
- $this->mapStairs(Ids::DEEPSLATE_TILE_STAIRS, fn() => Blocks::DEEPSLATE_TILE_STAIRS());
- $this->map(Ids::DEEPSLATE_TILE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::DEEPSLATE_TILE_WALL(), $in));
- $this->map(Ids::DETECTOR_RAIL, function(Reader $in) : Block{
- return Blocks::DETECTOR_RAIL()
- ->setActivated($in->readBool(StateNames::RAIL_DATA_BIT))
- ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5));
- });
- $this->mapSlab(Ids::DIORITE_SLAB, Ids::DIORITE_DOUBLE_SLAB, fn() => Blocks::DIORITE_SLAB());
- $this->mapStairs(Ids::DIORITE_STAIRS, fn() => Blocks::DIORITE_STAIRS());
- $this->map(Ids::DIORITE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::DIORITE_WALL(), $in));
- $this->map(Ids::DIRT, fn() => Blocks::DIRT()->setDirtType(DirtType::NORMAL));
- $this->map(Ids::DIRT_WITH_ROOTS, fn() => Blocks::DIRT()->setDirtType(DirtType::ROOTED));
- $this->map(Ids::LARGE_FERN, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::LARGE_FERN(), $in));
- $this->map(Ids::TALL_GRASS, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::DOUBLE_TALLGRASS(), $in));
- $this->map(Ids::PEONY, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::PEONY(), $in));
- $this->map(Ids::ROSE_BUSH, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::ROSE_BUSH(), $in));
- $this->map(Ids::SUNFLOWER, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::SUNFLOWER(), $in));
- $this->map(Ids::LILAC, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::LILAC(), $in));
- $this->map(Ids::ELEMENT_CONSTRUCTOR, fn(Reader $in) => Blocks::ELEMENT_CONSTRUCTOR()
- ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
- );
- $this->mapStairs(Ids::END_BRICK_STAIRS, fn() => Blocks::END_STONE_BRICK_STAIRS());
- $this->map(Ids::END_STONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::END_STONE_BRICK_WALL(), $in));
- $this->map(Ids::END_PORTAL_FRAME, function(Reader $in) : Block{
- return Blocks::END_PORTAL_FRAME()
- ->setEye($in->readBool(StateNames::END_PORTAL_EYE_BIT))
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::END_ROD, function(Reader $in) : Block{
- return Blocks::END_ROD()
- ->setFacing($in->readEndRodFacingDirection());
- });
- $this->mapSlab(Ids::END_STONE_BRICK_SLAB, Ids::END_STONE_BRICK_DOUBLE_SLAB, fn() => Blocks::END_STONE_BRICK_SLAB());
- $this->map(Ids::ENDER_CHEST, function(Reader $in) : Block{
- return Blocks::ENDER_CHEST()
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::FARMLAND, function(Reader $in) : Block{
- return Blocks::FARMLAND()
- ->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7));
- });
- $this->map(Ids::FIRE, function(Reader $in) : Block{
- return Blocks::FIRE()
- ->setAge($in->readBoundedInt(StateNames::AGE, 0, 15));
- });
- $this->map(Ids::FLOWER_POT, function(Reader $in) : Block{
- $in->ignored(StateNames::UPDATE_BIT);
- return Blocks::FLOWER_POT();
- });
- $this->map(Ids::FLOWING_LAVA, fn(Reader $in) => Helper::decodeFlowingLiquid(Blocks::LAVA(), $in));
- $this->map(Ids::FLOWING_WATER, fn(Reader $in) => Helper::decodeFlowingLiquid(Blocks::WATER(), $in));
- $this->map(Ids::FRAME, fn(Reader $in) => Helper::decodeItemFrame(Blocks::ITEM_FRAME(), $in));
- $this->map(Ids::FROSTED_ICE, function(Reader $in) : Block{
- return Blocks::FROSTED_ICE()
- ->setAge($in->readBoundedInt(StateNames::AGE, 0, 3));
- });
- $this->map(Ids::FURNACE, function(Reader $in) : Block{
- return Blocks::FURNACE()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(false);
- });
- $this->map(Ids::GLOW_LICHEN, fn(Reader $in) => Blocks::GLOW_LICHEN()->setFaces($in->readFacingFlags()));
- $this->map(Ids::GLOW_FRAME, fn(Reader $in) => Helper::decodeItemFrame(Blocks::GLOWING_ITEM_FRAME(), $in));
- $this->map(Ids::GOLDEN_RAIL, function(Reader $in) : Block{
- return Blocks::POWERED_RAIL()
- ->setPowered($in->readBool(StateNames::RAIL_DATA_BIT))
- ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5));
- });
- $this->mapSlab(Ids::GRANITE_SLAB, Ids::GRANITE_DOUBLE_SLAB, fn() => Blocks::GRANITE_SLAB());
- $this->mapStairs(Ids::GRANITE_STAIRS, fn() => Blocks::GRANITE_STAIRS());
- $this->map(Ids::GRANITE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::GRANITE_WALL(), $in));
- $this->map(Ids::HAY_BLOCK, function(Reader $in) : Block{
- $in->ignored(StateNames::DEPRECATED);
- return Blocks::HAY_BALE()->setAxis($in->readPillarAxis());
- });
- $this->map(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeWeightedPressurePlate(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), $in));
- $this->map(Ids::HOPPER, function(Reader $in) : Block{
- return Blocks::HOPPER()
- ->setFacing($in->readFacingWithoutUp())
- ->setPowered($in->readBool(StateNames::TOGGLE_BIT));
- });
- $this->map(Ids::IRON_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::IRON_DOOR(), $in));
- $this->map(Ids::IRON_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::IRON_TRAPDOOR(), $in));
- $this->map(Ids::LAB_TABLE, fn(Reader $in) => Blocks::LAB_TABLE()
- ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
- );
- $this->map(Ids::LADDER, function(Reader $in) : Block{
- return Blocks::LADDER()
- ->setFacing($in->readHorizontalFacing());
- });
- $this->map(Ids::LANTERN, function(Reader $in) : Block{
- return Blocks::LANTERN()
- ->setHanging($in->readBool(StateNames::HANGING));
- });
- $this->map(Ids::LARGE_AMETHYST_BUD, function(Reader $in) : Block{
- return Blocks::AMETHYST_CLUSTER()
- ->setStage(AmethystCluster::STAGE_LARGE_BUD)
- ->setFacing($in->readBlockFace());
- });
- $this->map(Ids::LAVA, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::LAVA(), $in));
- $this->map(Ids::LECTERN, function(Reader $in) : Block{
- return Blocks::LECTERN()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setProducingSignal($in->readBool(StateNames::POWERED_BIT));
- });
- $this->map(Ids::LEVER, function(Reader $in) : Block{
- return Blocks::LEVER()
- ->setActivated($in->readBool(StateNames::OPEN_BIT))
- ->setFacing(match($value = $in->readString(StateNames::LEVER_DIRECTION)){
- StringValues::LEVER_DIRECTION_DOWN_NORTH_SOUTH => LeverFacing::DOWN_AXIS_Z,
- StringValues::LEVER_DIRECTION_DOWN_EAST_WEST => LeverFacing::DOWN_AXIS_X,
- StringValues::LEVER_DIRECTION_UP_NORTH_SOUTH => LeverFacing::UP_AXIS_Z,
- StringValues::LEVER_DIRECTION_UP_EAST_WEST => LeverFacing::UP_AXIS_X,
- StringValues::LEVER_DIRECTION_NORTH => LeverFacing::NORTH,
- StringValues::LEVER_DIRECTION_SOUTH => LeverFacing::SOUTH,
- StringValues::LEVER_DIRECTION_WEST => LeverFacing::WEST,
- StringValues::LEVER_DIRECTION_EAST => LeverFacing::EAST,
- default => throw $in->badValueException(StateNames::LEVER_DIRECTION, $value),
- });
- });
- $this->map(Ids::LIGHTNING_ROD, function(Reader $in) : Block{
- return Blocks::LIGHTNING_ROD()
- ->setFacing($in->readFacingDirection());
- });
- $this->map(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeWeightedPressurePlate(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), $in));
- $this->map(Ids::LIT_BLAST_FURNACE, function(Reader $in) : Block{
- return Blocks::BLAST_FURNACE()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(true);
- });
- $this->map(Ids::LIT_DEEPSLATE_REDSTONE_ORE, fn() => Blocks::DEEPSLATE_REDSTONE_ORE()->setLit(true));
- $this->map(Ids::LIT_FURNACE, function(Reader $in) : Block{
- return Blocks::FURNACE()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(true);
- });
- $this->map(Ids::LIT_PUMPKIN, function(Reader $in) : Block{
- return Blocks::LIT_PUMPKIN()
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::LIT_REDSTONE_LAMP, function() : Block{
- return Blocks::REDSTONE_LAMP()
- ->setPowered(true);
- });
- $this->map(Ids::LIT_REDSTONE_ORE, function() : Block{
- return Blocks::REDSTONE_ORE()
- ->setLit(true);
- });
- $this->map(Ids::LIT_SMOKER, function(Reader $in) : Block{
- return Blocks::SMOKER()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(true);
- });
- $this->map(Ids::LOOM, function(Reader $in) : Block{
- return Blocks::LOOM()
- ->setFacing($in->readLegacyHorizontalFacing());
- });
- $this->map(Ids::MATERIAL_REDUCER, fn(Reader $in) => Blocks::MATERIAL_REDUCER()
- ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
- );
- $this->map(Ids::MEDIUM_AMETHYST_BUD, function(Reader $in) : Block{
- return Blocks::AMETHYST_CLUSTER()
- ->setStage(AmethystCluster::STAGE_MEDIUM_BUD)
- ->setFacing($in->readBlockFace());
- });
- $this->map(Ids::MELON_STEM, fn(Reader $in) => Helper::decodeStem(Blocks::MELON_STEM(), $in));
- $this->mapSlab(Ids::MOSSY_COBBLESTONE_SLAB, Ids::MOSSY_COBBLESTONE_DOUBLE_SLAB, fn() => Blocks::MOSSY_COBBLESTONE_SLAB());
- $this->mapStairs(Ids::MOSSY_COBBLESTONE_STAIRS, fn() => Blocks::MOSSY_COBBLESTONE_STAIRS());
- $this->map(Ids::MOSSY_COBBLESTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::MOSSY_COBBLESTONE_WALL(), $in));
- $this->mapSlab(Ids::MOSSY_STONE_BRICK_SLAB, Ids::MOSSY_STONE_BRICK_DOUBLE_SLAB, fn() => Blocks::MOSSY_STONE_BRICK_SLAB());
- $this->mapStairs(Ids::MOSSY_STONE_BRICK_STAIRS, fn() => Blocks::MOSSY_STONE_BRICK_STAIRS());
- $this->map(Ids::MOSSY_STONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::MOSSY_STONE_BRICK_WALL(), $in));
- $this->mapSlab(Ids::MUD_BRICK_SLAB, Ids::MUD_BRICK_DOUBLE_SLAB, fn() => Blocks::MUD_BRICK_SLAB());
- $this->mapStairs(Ids::MUD_BRICK_STAIRS, fn() => Blocks::MUD_BRICK_STAIRS());
- $this->map(Ids::MUD_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::MUD_BRICK_WALL(), $in));
- $this->map(Ids::MUDDY_MANGROVE_ROOTS, function(Reader $in) : Block{
- return Blocks::MUDDY_MANGROVE_ROOTS()
- ->setAxis($in->readPillarAxis());
- });
- $this->mapSlab(Ids::NETHER_BRICK_SLAB, Ids::NETHER_BRICK_DOUBLE_SLAB, fn() => Blocks::NETHER_BRICK_SLAB());
- $this->mapStairs(Ids::NETHER_BRICK_STAIRS, fn() => Blocks::NETHER_BRICK_STAIRS());
- $this->map(Ids::NETHER_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::NETHER_BRICK_WALL(), $in));
- $this->map(Ids::NETHER_WART, function(Reader $in) : Block{
- return Blocks::NETHER_WART()
- ->setAge($in->readBoundedInt(StateNames::AGE, 0, 3));
- });
- $this->mapSlab(Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB, fn() => Blocks::STONE_SLAB());
- $this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS());
- $this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE)->setAxis($in->readPillarAxis()));
- $this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT)->setAxis($in->readPillarAxis()));
- $this->mapSlab(Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB, fn() => Blocks::FAKE_WOODEN_SLAB());
- $this->map(Ids::PINK_PETALS, function(Reader $in) : Block{
- //Pink petals only uses 0-3, but GROWTH state can go up to 7
- $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7);
- return Blocks::PINK_PETALS()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setCount(min($growth + 1, PinkPetals::MAX_COUNT));
- });
- $this->map(Ids::PITCHER_CROP, function(Reader $in) : Block{
- $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7);
- $top = $in->readBool(StateNames::UPPER_BLOCK_BIT);
- if($growth <= PitcherCrop::MAX_AGE){
- //top pitcher crop with age 0-2 is an invalid state
- //only the bottom half should exist in this case
- return $top ? Blocks::AIR() : Blocks::PITCHER_CROP()->setAge($growth);
- }
- return Blocks::DOUBLE_PITCHER_CROP()
- ->setAge(min($growth - PitcherCrop::MAX_AGE - 1, DoublePitcherCrop::MAX_AGE))
- ->setTop($top);
- });
- $this->map(Ids::PITCHER_PLANT, function(Reader $in) : Block{
- return Blocks::PITCHER_PLANT()
- ->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT));
- });
- $this->mapSlab(Ids::POLISHED_ANDESITE_SLAB, Ids::POLISHED_ANDESITE_DOUBLE_SLAB, fn() => Blocks::POLISHED_ANDESITE_SLAB());
- $this->mapStairs(Ids::POLISHED_ANDESITE_STAIRS, fn() => Blocks::POLISHED_ANDESITE_STAIRS());
- $this->map(Ids::POLISHED_BASALT, function(Reader $in) : Block{
- return Blocks::POLISHED_BASALT()
- ->setAxis($in->readPillarAxis());
- });
- $this->map(Ids::POLISHED_BLACKSTONE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::POLISHED_BLACKSTONE_BUTTON(), $in));
- $this->mapSlab(Ids::POLISHED_BLACKSTONE_SLAB, Ids::POLISHED_BLACKSTONE_DOUBLE_SLAB, fn() => Blocks::POLISHED_BLACKSTONE_SLAB());
- $this->map(Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::POLISHED_BLACKSTONE_PRESSURE_PLATE(), $in));
- $this->mapStairs(Ids::POLISHED_BLACKSTONE_STAIRS, fn() => Blocks::POLISHED_BLACKSTONE_STAIRS());
- $this->map(Ids::POLISHED_BLACKSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_BLACKSTONE_WALL(), $in));
- $this->mapSlab(Ids::POLISHED_BLACKSTONE_BRICK_SLAB, Ids::POLISHED_BLACKSTONE_BRICK_DOUBLE_SLAB, fn() => Blocks::POLISHED_BLACKSTONE_BRICK_SLAB());
- $this->mapStairs(Ids::POLISHED_BLACKSTONE_BRICK_STAIRS, fn() => Blocks::POLISHED_BLACKSTONE_BRICK_STAIRS());
- $this->map(Ids::POLISHED_BLACKSTONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_BLACKSTONE_BRICK_WALL(), $in));
- $this->mapSlab(Ids::POLISHED_DEEPSLATE_SLAB, Ids::POLISHED_DEEPSLATE_DOUBLE_SLAB, fn() => Blocks::POLISHED_DEEPSLATE_SLAB());
- $this->mapStairs(Ids::POLISHED_DEEPSLATE_STAIRS, fn() => Blocks::POLISHED_DEEPSLATE_STAIRS());
- $this->map(Ids::POLISHED_DEEPSLATE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_DEEPSLATE_WALL(), $in));
- $this->mapSlab(Ids::POLISHED_DIORITE_SLAB, Ids::POLISHED_DIORITE_DOUBLE_SLAB, fn() => Blocks::POLISHED_DIORITE_SLAB());
- $this->mapStairs(Ids::POLISHED_DIORITE_STAIRS, fn() => Blocks::POLISHED_DIORITE_STAIRS());
- $this->mapSlab(Ids::POLISHED_GRANITE_SLAB, Ids::POLISHED_GRANITE_DOUBLE_SLAB, fn() => Blocks::POLISHED_GRANITE_SLAB());
- $this->mapStairs(Ids::POLISHED_GRANITE_STAIRS, fn() => Blocks::POLISHED_GRANITE_STAIRS());
- $this->mapSlab(Ids::POLISHED_TUFF_SLAB, Ids::POLISHED_TUFF_DOUBLE_SLAB, fn() => Blocks::POLISHED_TUFF_SLAB());
- $this->mapStairs(Ids::POLISHED_TUFF_STAIRS, fn() => Blocks::POLISHED_TUFF_STAIRS());
- $this->map(Ids::POLISHED_TUFF_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_TUFF_WALL(), $in));
- $this->map(Ids::PORTAL, function(Reader $in) : Block{
- return Blocks::NETHER_PORTAL()
- ->setAxis(match($value = $in->readString(StateNames::PORTAL_AXIS)){
- StringValues::PORTAL_AXIS_UNKNOWN => Axis::X,
- StringValues::PORTAL_AXIS_X => Axis::X,
- StringValues::PORTAL_AXIS_Z => Axis::Z,
- default => throw $in->badValueException(StateNames::PORTAL_AXIS, $value),
- });
- });
- $this->map(Ids::POTATOES, fn(Reader $in) => Helper::decodeCrops(Blocks::POTATOES(), $in));
- $this->map(Ids::POWERED_COMPARATOR, fn(Reader $in) => Helper::decodeComparator(Blocks::REDSTONE_COMPARATOR(), $in));
- $this->map(Ids::POWERED_REPEATER, fn(Reader $in) => Helper::decodeRepeater(Blocks::REDSTONE_REPEATER(), $in)
- ->setPowered(true));
- $this->mapSlab(Ids::PRISMARINE_BRICK_SLAB, Ids::PRISMARINE_BRICK_DOUBLE_SLAB, fn() => Blocks::PRISMARINE_BRICKS_SLAB());
- $this->mapStairs(Ids::PRISMARINE_BRICKS_STAIRS, fn() => Blocks::PRISMARINE_BRICKS_STAIRS());
- $this->map(Ids::PRISMARINE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::PRISMARINE_WALL(), $in));
- $this->mapSlab(Ids::PRISMARINE_SLAB, Ids::PRISMARINE_DOUBLE_SLAB, fn() => Blocks::PRISMARINE_SLAB());
- $this->mapStairs(Ids::PRISMARINE_STAIRS, fn() => Blocks::PRISMARINE_STAIRS());
- $this->map(Ids::PUMPKIN, function(Reader $in) : Block{
- $in->ignored(StateNames::MC_CARDINAL_DIRECTION); //obsolete
- return Blocks::PUMPKIN();
- });
- $this->map(Ids::PUMPKIN_STEM, fn(Reader $in) => Helper::decodeStem(Blocks::PUMPKIN_STEM(), $in));
- $this->map(Ids::PURPUR_BLOCK, function(Reader $in) : Block{
- $in->ignored(StateNames::PILLAR_AXIS); //???
- return Blocks::PURPUR();
- });
- $this->map(Ids::PURPUR_PILLAR, fn(Reader $in) => Blocks::PURPUR_PILLAR()->setAxis($in->readPillarAxis()));
- $this->mapSlab(Ids::PURPUR_SLAB, Ids::PURPUR_DOUBLE_SLAB, fn() => Blocks::PURPUR_SLAB());
- $this->mapStairs(Ids::PURPUR_STAIRS, fn() => Blocks::PURPUR_STAIRS());
- $this->map(Ids::QUARTZ_BLOCK, function(Reader $in) : Opaque{
- $in->ignored(StateNames::PILLAR_AXIS);
- return Blocks::QUARTZ();
- });
- $this->map(Ids::QUARTZ_PILLAR, function(Reader $in) : Block{
- return Blocks::QUARTZ_PILLAR()
- ->setAxis($in->readPillarAxis());
- });
- $this->mapSlab(Ids::QUARTZ_SLAB, Ids::QUARTZ_DOUBLE_SLAB, fn() => Blocks::QUARTZ_SLAB());
- $this->mapStairs(Ids::QUARTZ_STAIRS, fn() => Blocks::QUARTZ_STAIRS());
- $this->map(Ids::RAIL, function(Reader $in) : Block{
- return Blocks::RAIL()
- ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 9));
- });
- $this->map(Ids::RED_MUSHROOM_BLOCK, fn(Reader $in) => Helper::decodeMushroomBlock(Blocks::RED_MUSHROOM_BLOCK(), $in));
- $this->mapSlab(Ids::RED_NETHER_BRICK_SLAB, Ids::RED_NETHER_BRICK_DOUBLE_SLAB, fn() => Blocks::RED_NETHER_BRICK_SLAB());
- $this->mapStairs(Ids::RED_NETHER_BRICK_STAIRS, fn() => Blocks::RED_NETHER_BRICK_STAIRS());
- $this->map(Ids::RED_NETHER_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RED_NETHER_BRICK_WALL(), $in));
- $this->mapSlab(Ids::RED_SANDSTONE_SLAB, Ids::RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::RED_SANDSTONE_SLAB());
- $this->mapStairs(Ids::RED_SANDSTONE_STAIRS, fn() => Blocks::RED_SANDSTONE_STAIRS());
- $this->map(Ids::RED_SANDSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RED_SANDSTONE_WALL(), $in));
- $this->map(Ids::REDSTONE_LAMP, function() : Block{
- return Blocks::REDSTONE_LAMP()
- ->setPowered(false);
- });
- $this->map(Ids::REDSTONE_ORE, function() : Block{
- return Blocks::REDSTONE_ORE()
- ->setLit(false);
- });
- $this->map(Ids::REDSTONE_TORCH, function(Reader $in) : Block{
- return Blocks::REDSTONE_TORCH()
- ->setFacing($in->readTorchFacing())
- ->setLit(true);
- });
- $this->map(Ids::REDSTONE_WIRE, function(Reader $in) : Block{
- return Blocks::REDSTONE_WIRE()
- ->setOutputSignalStrength($in->readBoundedInt(StateNames::REDSTONE_SIGNAL, 0, 15));
- });
- $this->map(Ids::REEDS, function(Reader $in) : Block{
- return Blocks::SUGARCANE()
- ->setAge($in->readBoundedInt(StateNames::AGE, 0, 15));
- });
- $this->mapSlab(Ids::RESIN_BRICK_SLAB, Ids::RESIN_BRICK_DOUBLE_SLAB, fn() => Blocks::RESIN_BRICK_SLAB());
- $this->mapStairs(Ids::RESIN_BRICK_STAIRS, fn() => Blocks::RESIN_BRICK_STAIRS());
- $this->map(Ids::RESIN_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RESIN_BRICK_WALL(), $in));
- $this->map(Ids::RESIN_CLUMP, fn(Reader $in) => Blocks::RESIN_CLUMP()->setFaces($in->readFacingFlags()));
- $this->map(Ids::RESPAWN_ANCHOR, function(Reader $in) : Block{
- return Blocks::RESPAWN_ANCHOR()
- ->setCharges($in->readBoundedInt(StateNames::RESPAWN_ANCHOR_CHARGE, 0, 4));
- });
- $this->mapSlab(Ids::SANDSTONE_SLAB, Ids::SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SANDSTONE_SLAB());
- $this->mapStairs(Ids::SANDSTONE_STAIRS, fn() => Blocks::SANDSTONE_STAIRS());
- $this->map(Ids::SANDSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::SANDSTONE_WALL(), $in));
- $this->map(Ids::SEA_PICKLE, function(Reader $in) : Block{
- return Blocks::SEA_PICKLE()
- ->setCount($in->readBoundedInt(StateNames::CLUSTER_COUNT, 0, 3) + 1)
- ->setUnderwater(!$in->readBool(StateNames::DEAD_BIT));
- });
- $this->map(Ids::SMOKER, function(Reader $in) : Block{
- return Blocks::SMOKER()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(false);
- });
- $this->map(Ids::SMALL_AMETHYST_BUD, function(Reader $in) : Block{
- return Blocks::AMETHYST_CLUSTER()
- ->setStage(AmethystCluster::STAGE_SMALL_BUD)
- ->setFacing($in->readBlockFace());
- });
- $this->map(Ids::SMALL_DRIPLEAF_BLOCK, function(Reader $in) : Block{
- return Blocks::SMALL_DRIPLEAF()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT));
- });
- $this->map(Ids::SMOOTH_QUARTZ, function(Reader $in) : Block{
- $in->ignored(StateNames::PILLAR_AXIS);
- return Blocks::SMOOTH_QUARTZ();
- });
- $this->mapSlab(Ids::SMOOTH_QUARTZ_SLAB, Ids::SMOOTH_QUARTZ_DOUBLE_SLAB, fn() => Blocks::SMOOTH_QUARTZ_SLAB());
- $this->mapStairs(Ids::SMOOTH_QUARTZ_STAIRS, fn() => Blocks::SMOOTH_QUARTZ_STAIRS());
- $this->mapSlab(Ids::SMOOTH_RED_SANDSTONE_SLAB, Ids::SMOOTH_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SMOOTH_RED_SANDSTONE_SLAB());
- $this->mapStairs(Ids::SMOOTH_RED_SANDSTONE_STAIRS, fn() => Blocks::SMOOTH_RED_SANDSTONE_STAIRS());
- $this->mapSlab(Ids::SMOOTH_SANDSTONE_SLAB, Ids::SMOOTH_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SMOOTH_SANDSTONE_SLAB());
- $this->mapStairs(Ids::SMOOTH_SANDSTONE_STAIRS, fn() => Blocks::SMOOTH_SANDSTONE_STAIRS());
- $this->mapSlab(Ids::SMOOTH_STONE_SLAB, Ids::SMOOTH_STONE_DOUBLE_SLAB, fn() => Blocks::SMOOTH_STONE_SLAB());
- $this->map(Ids::SNOW_LAYER, function(Reader $in) : Block{
- $in->ignored(StateNames::COVERED_BIT); //seems to be useless
- return Blocks::SNOW_LAYER()->setLayers($in->readBoundedInt(StateNames::HEIGHT, 0, 7) + 1);
- });
- $this->map(Ids::SOUL_CAMPFIRE, function(Reader $in) : Block{
- return Blocks::SOUL_CAMPFIRE()
- ->setFacing($in->readCardinalHorizontalFacing())
- ->setLit(!$in->readBool(StateNames::EXTINGUISHED));
- });
- $this->map(Ids::SOUL_FIRE, function(Reader $in) : Block{
- $in->ignored(StateNames::AGE); //this is useless for soul fire, since it doesn't have the logic associated
- return Blocks::SOUL_FIRE();
- });
- $this->map(Ids::SOUL_LANTERN, function(Reader $in) : Block{
- return Blocks::SOUL_LANTERN()
- ->setHanging($in->readBool(StateNames::HANGING));
- });
- $this->map(Ids::SOUL_TORCH, function(Reader $in) : Block{
- return Blocks::SOUL_TORCH()
- ->setFacing($in->readTorchFacing());
- });
- $this->map(Ids::STANDING_BANNER, function(Reader $in) : Block{
- return Blocks::BANNER()
- ->setRotation($in->readBoundedInt(StateNames::GROUND_SIGN_DIRECTION, 0, 15));
- });
- $this->mapSlab(Ids::STONE_BRICK_SLAB, Ids::STONE_BRICK_DOUBLE_SLAB, fn() => Blocks::STONE_BRICK_SLAB());
- $this->mapStairs(Ids::STONE_BRICK_STAIRS, fn() => Blocks::STONE_BRICK_STAIRS());
- $this->map(Ids::STONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::STONE_BRICK_WALL(), $in));
- $this->map(Ids::STONE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::STONE_BUTTON(), $in));
- $this->map(Ids::STONE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::STONE_PRESSURE_PLATE(), $in));
- $this->mapStairs(Ids::STONE_STAIRS, fn() => Blocks::COBBLESTONE_STAIRS());
- $this->map(Ids::STONECUTTER_BLOCK, function(Reader $in) : Block{
- return Blocks::STONECUTTER()
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::SWEET_BERRY_BUSH, function(Reader $in) : Block{
- //berry bush only wants 0-3, but it can be bigger in MCPE due to misuse of GROWTH state which goes up to 7
- $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7);
- return Blocks::SWEET_BERRY_BUSH()
- ->setAge(min($growth, SweetBerryBush::STAGE_MATURE));
- });
- $this->map(Ids::TNT, function(Reader $in) : Block{
- return Blocks::TNT()
- ->setUnstable($in->readBool(StateNames::EXPLODE_BIT))
- ->setWorksUnderwater(false);
- });
- $this->map(Ids::TORCH, function(Reader $in) : Block{
- return Blocks::TORCH()
- ->setFacing($in->readTorchFacing());
- });
- $this->map(Ids::TORCHFLOWER_CROP, function(Reader $in) : Block{
- return Blocks::TORCHFLOWER_CROP()
- //this property can have values 0-7, but only 0-1 are valid
- ->setReady($in->readBoundedInt(StateNames::GROWTH, 0, 7) !== 0);
- });
- $this->map(Ids::TRAPPED_CHEST, function(Reader $in) : Block{
- return Blocks::TRAPPED_CHEST()
- ->setFacing($in->readCardinalHorizontalFacing());
- });
- $this->map(Ids::TRIP_WIRE, function(Reader $in) : Block{
- return Blocks::TRIPWIRE()
- ->setConnected($in->readBool(StateNames::ATTACHED_BIT))
- ->setDisarmed($in->readBool(StateNames::DISARMED_BIT))
- ->setSuspended($in->readBool(StateNames::SUSPENDED_BIT))
- ->setTriggered($in->readBool(StateNames::POWERED_BIT));
- });
- $this->map(Ids::TRIPWIRE_HOOK, function(Reader $in) : Block{
- return Blocks::TRIPWIRE_HOOK()
- ->setConnected($in->readBool(StateNames::ATTACHED_BIT))
- ->setFacing($in->readLegacyHorizontalFacing())
- ->setPowered($in->readBool(StateNames::POWERED_BIT));
- });
- $this->mapSlab(Ids::TUFF_BRICK_SLAB, Ids::TUFF_BRICK_DOUBLE_SLAB, fn() => Blocks::TUFF_BRICK_SLAB());
- $this->mapStairs(Ids::TUFF_BRICK_STAIRS, fn() => Blocks::TUFF_BRICK_STAIRS());
- $this->map(Ids::TUFF_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::TUFF_BRICK_WALL(), $in));
- $this->mapSlab(Ids::TUFF_SLAB, Ids::TUFF_DOUBLE_SLAB, fn() => Blocks::TUFF_SLAB());
- $this->mapStairs(Ids::TUFF_STAIRS, fn() => Blocks::TUFF_STAIRS());
- $this->map(Ids::TUFF_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::TUFF_WALL(), $in));
- $this->map(Ids::TWISTING_VINES, function(Reader $in) : Block{
- return Blocks::TWISTING_VINES()
- ->setAge($in->readBoundedInt(StateNames::TWISTING_VINES_AGE, 0, 25));
- });
- $this->map(Ids::UNDERWATER_TNT, function(Reader $in) : Block{
- return Blocks::TNT()
- ->setUnstable($in->readBool(StateNames::EXPLODE_BIT))
- ->setWorksUnderwater(true);
- });
- $this->map(Ids::UNDERWATER_TORCH, function(Reader $in) : Block{
- return Blocks::UNDERWATER_TORCH()
- ->setFacing($in->readTorchFacing());
- });
- $this->map(Ids::UNLIT_REDSTONE_TORCH, function(Reader $in) : Block{
- return Blocks::REDSTONE_TORCH()
- ->setFacing($in->readTorchFacing())
- ->setLit(false);
- });
- $this->map(Ids::UNPOWERED_COMPARATOR, fn(Reader $in) => Helper::decodeComparator(Blocks::REDSTONE_COMPARATOR(), $in));
- $this->map(Ids::UNPOWERED_REPEATER, fn(Reader $in) => Helper::decodeRepeater(Blocks::REDSTONE_REPEATER(), $in)
- ->setPowered(false));
- $this->map(Ids::VERDANT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::VERDANT)->setAxis($in->readPillarAxis()));
- $this->map(Ids::VINE, function(Reader $in) : Block{
- $vineDirectionFlags = $in->readBoundedInt(StateNames::VINE_DIRECTION_BITS, 0, 15);
- return Blocks::VINES()
- ->setFace(Facing::NORTH, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_NORTH) !== 0)
- ->setFace(Facing::SOUTH, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_SOUTH) !== 0)
- ->setFace(Facing::WEST, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_WEST) !== 0)
- ->setFace(Facing::EAST, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_EAST) !== 0);
- });
- $this->map(Ids::WALL_BANNER, function(Reader $in) : Block{
- return Blocks::WALL_BANNER()
- ->setFacing($in->readHorizontalFacing());
- });
- $this->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in));
-
- $this->map(Ids::WEEPING_VINES, function(Reader $in) : Block{
- return Blocks::WEEPING_VINES()
- ->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25));
- });
- $this->map(Ids::WHEAT, fn(Reader $in) => Helper::decodeCrops(Blocks::WHEAT(), $in));
- }
-
/** @throws BlockStateDeserializeException */
public function deserializeBlock(BlockStateData $blockStateData) : Block{
$id = $blockStateData->getName();
diff --git a/src/data/bedrock/block/convert/BlockStateWriter.php b/src/data/bedrock/block/convert/BlockStateWriter.php
index 63af92d10..0119bd02e 100644
--- a/src/data/bedrock/block/convert/BlockStateWriter.php
+++ b/src/data/bedrock/block/convert/BlockStateWriter.php
@@ -31,6 +31,9 @@ use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateSerializeException;
use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
+use pocketmine\data\bedrock\block\convert\property\EnumFromRawStateMap;
+use pocketmine\data\bedrock\block\convert\property\IntFromRawStateMap;
+use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\nbt\tag\ByteTag;
@@ -73,35 +76,47 @@ final class BlockStateWriter{
return $this;
}
- /** @return $this */
- public function writeFacingDirection(int $value) : self{
- $this->writeInt(BlockStateNames::FACING_DIRECTION, match($value){
- Facing::DOWN => 0,
- Facing::UP => 1,
- Facing::NORTH => 2,
- Facing::SOUTH => 3,
- Facing::WEST => 4,
- Facing::EAST => 5,
- default => throw new BlockStateSerializeException("Invalid Facing $value")
- });
- return $this;
- }
-
- /** @return $this */
- public function writeBlockFace(int $value) : self{
- $this->writeString(BlockStateNames::MC_BLOCK_FACE, match($value){
- Facing::DOWN => StringValues::MC_BLOCK_FACE_DOWN,
- Facing::UP => StringValues::MC_BLOCK_FACE_UP,
- Facing::NORTH => StringValues::MC_BLOCK_FACE_NORTH,
- Facing::SOUTH => StringValues::MC_BLOCK_FACE_SOUTH,
- Facing::WEST => StringValues::MC_BLOCK_FACE_WEST,
- Facing::EAST => StringValues::MC_BLOCK_FACE_EAST,
- default => throw new BlockStateSerializeException("Invalid Facing $value")
- });
+ /**
+ * @deprecated
+ * @phpstan-param IntFromRawStateMap $map
+ * @return $this
+ */
+ public function mapIntToString(string $name, IntFromRawStateMap $map, int $value) : self{
+ $raw = $map->valueToRaw($value);
+ $this->writeString($name, $raw);
return $this;
}
/**
+ * @deprecated
+ * @phpstan-param IntFromRawStateMap $map
+ * @return $this
+ */
+ public function mapIntToInt(string $name, IntFromRawStateMap $map, int $value) : self{
+ $raw = $map->valueToRaw($value);
+ $this->writeInt($name, $raw);
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @return $this
+ */
+ public function writeFacingDirection(int $value) : self{
+ return $this->mapIntToInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->facing, $value);
+ }
+
+ /**
+ * @deprecated
+ * @return $this
+ */
+ public function writeBlockFace(int $value) : self{
+ $this->mapIntToString(BlockStateNames::MC_BLOCK_FACE, ValueMappings::getInstance()->blockFace, $value);
+ return $this;
+ }
+
+ /**
+ * @deprecated
* @param int[] $faces
* @phpstan-param array $faces
* @return $this
@@ -123,86 +138,69 @@ final class BlockStateWriter{
return $this->writeInt(BlockStateNames::MULTI_FACE_DIRECTION_BITS, $result);
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeEndRodFacingDirection(int $value) : self{
//end rods are stupid in bedrock and have everything except up/down the wrong way round
return $this->writeFacingDirection(Facing::axis($value) !== Axis::Y ? Facing::opposite($value) : $value);
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeHorizontalFacing(int $value) : self{
- if($value === Facing::UP || $value === Facing::DOWN){
- throw new BlockStateSerializeException("Y-axis facing is not allowed");
- }
-
- return $this->writeFacingDirection($value);
- }
-
- /** @return $this */
- public function writeWeirdoHorizontalFacing(int $value) : self{
- $this->writeInt(BlockStateNames::WEIRDO_DIRECTION, match($value){
- Facing::EAST => 0,
- Facing::WEST => 1,
- Facing::SOUTH => 2,
- Facing::NORTH => 3,
- default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
- });
- return $this;
- }
-
- /** @return $this */
- public function writeLegacyHorizontalFacing(int $value) : self{
- $this->writeInt(BlockStateNames::DIRECTION, match($value){
- Facing::SOUTH => 0,
- Facing::WEST => 1,
- Facing::NORTH => 2,
- Facing::EAST => 3,
- default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
- });
- return $this;
+ return $this->mapIntToInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->horizontalFacingClassic, $value);
}
/**
+ * @deprecated
+ * @return $this
+ */
+ public function writeWeirdoHorizontalFacing(int $value) : self{
+ return $this->mapIntToInt(BlockStateNames::WEIRDO_DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus, $value);
+ }
+
+ /**
+ * @deprecated
+ * @return $this
+ */
+ public function writeLegacyHorizontalFacing(int $value) : self{
+ return $this->mapIntToInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacingSWNE, $value);
+ }
+
+ /**
+ * @deprecated
* This is for trapdoors, because Mojang botched the conversion in 1.13
* @return $this
*/
public function write5MinusHorizontalFacing(int $value) : self{
- return $this->writeInt(BlockStateNames::DIRECTION, match($value){
- Facing::EAST => 0,
- Facing::WEST => 1,
- Facing::SOUTH => 2,
- Facing::NORTH => 3,
- default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
- });
+ return $this->mapIntToInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus, $value);
}
/**
+ * @deprecated
* Used by pumpkins as of 1.20.0.23 beta
* @return $this
*/
public function writeCardinalHorizontalFacing(int $value) : self{
- return $this->writeString(BlockStateNames::MC_CARDINAL_DIRECTION, match($value){
- Facing::SOUTH => StringValues::MC_CARDINAL_DIRECTION_SOUTH,
- Facing::WEST => StringValues::MC_CARDINAL_DIRECTION_WEST,
- Facing::NORTH => StringValues::MC_CARDINAL_DIRECTION_NORTH,
- Facing::EAST => StringValues::MC_CARDINAL_DIRECTION_EAST,
- default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
- });
+ return $this->mapIntToString(BlockStateNames::MC_CARDINAL_DIRECTION, ValueMappings::getInstance()->cardinalDirection, $value);
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeCoralFacing(int $value) : self{
- $this->writeInt(BlockStateNames::CORAL_DIRECTION, match($value){
- Facing::WEST => 0,
- Facing::EAST => 1,
- Facing::NORTH => 2,
- Facing::SOUTH => 3,
- default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
- });
- return $this;
+ return $this->mapIntToInt(BlockStateNames::CORAL_DIRECTION, ValueMappings::getInstance()->horizontalFacingCoral, $value);
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeFacingWithoutDown(int $value) : self{
if($value === Facing::DOWN){
throw new BlockStateSerializeException("Invalid facing DOWN");
@@ -211,7 +209,10 @@ final class BlockStateWriter{
return $this;
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeFacingWithoutUp(int $value) : self{
if($value === Facing::UP){
throw new BlockStateSerializeException("Invalid facing UP");
@@ -220,18 +221,19 @@ final class BlockStateWriter{
return $this;
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writePillarAxis(int $axis) : self{
- $this->writeString(BlockStateNames::PILLAR_AXIS, match($axis){
- Axis::X => StringValues::PILLAR_AXIS_X,
- Axis::Y => StringValues::PILLAR_AXIS_Y,
- Axis::Z => StringValues::PILLAR_AXIS_Z,
- default => throw new BlockStateSerializeException("Invalid axis $axis")
- });
+ $this->mapIntToString(BlockStateNames::PILLAR_AXIS, ValueMappings::getInstance()->pillarAxis, $axis);
return $this;
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeSlabPosition(SlabType $slabType) : self{
$this->writeString(BlockStateNames::MC_VERTICAL_HALF, match($slabType){
SlabType::TOP => StringValues::MC_VERTICAL_HALF_TOP,
@@ -241,32 +243,27 @@ final class BlockStateWriter{
return $this;
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeTorchFacing(int $facing) : self{
- //TODO: horizontal directions are flipped (MCPE bug: https://bugs.mojang.com/browse/MCPE-152036)
- $this->writeString(BlockStateNames::TORCH_FACING_DIRECTION, match($facing){
- Facing::UP => StringValues::TORCH_FACING_DIRECTION_TOP,
- Facing::SOUTH => StringValues::TORCH_FACING_DIRECTION_NORTH,
- Facing::NORTH => StringValues::TORCH_FACING_DIRECTION_SOUTH,
- Facing::EAST => StringValues::TORCH_FACING_DIRECTION_WEST,
- Facing::WEST => StringValues::TORCH_FACING_DIRECTION_EAST,
- default => throw new BlockStateSerializeException("Invalid Torch facing $facing")
- });
+ $this->mapIntToString(BlockStateNames::TORCH_FACING_DIRECTION, ValueMappings::getInstance()->torchFacing, $facing);
return $this;
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeBellAttachmentType(BellAttachmentType $attachmentType) : self{
- $this->writeString(BlockStateNames::ATTACHMENT, match($attachmentType){
- BellAttachmentType::FLOOR => StringValues::ATTACHMENT_STANDING,
- BellAttachmentType::CEILING => StringValues::ATTACHMENT_HANGING,
- BellAttachmentType::ONE_WALL => StringValues::ATTACHMENT_SIDE,
- BellAttachmentType::TWO_WALLS => StringValues::ATTACHMENT_MULTIPLE,
- });
- return $this;
+ return $this->writeUnitEnum(BlockStateNames::ATTACHMENT, ValueMappings::getInstance()->bellAttachmentType, $attachmentType);
}
- /** @return $this */
+ /**
+ * @deprecated
+ * @return $this
+ */
public function writeWallConnectionType(string $name, ?WallConnectionType $wallConnectionType) : self{
$this->writeString($name, match($wallConnectionType){
null => StringValues::WALL_CONNECTION_TYPE_EAST_NONE,
@@ -276,6 +273,21 @@ final class BlockStateWriter{
return $this;
}
+ /**
+ * @deprecated
+ * @phpstan-template TEnum of \UnitEnum
+ * @phpstan-param EnumFromRawStateMap $map
+ * @phpstan-param TEnum $case
+ *
+ * @return $this
+ */
+ public function writeUnitEnum(string $name, EnumFromRawStateMap $map, \UnitEnum $case) : self{
+ $value = $map->valueToRaw($case);
+ $this->writeString($name, $value);
+
+ return $this;
+ }
+
public function getBlockStateData() : BlockStateData{
return BlockStateData::current($this->id, $this->states);
}
diff --git a/src/data/bedrock/block/convert/FlattenedIdModel.php b/src/data/bedrock/block/convert/FlattenedIdModel.php
new file mode 100644
index 000000000..50bf5cdd9
--- /dev/null
+++ b/src/data/bedrock/block/convert/FlattenedIdModel.php
@@ -0,0 +1,107 @@
+>
+ */
+ private array $idComponents = [];
+
+ /**
+ * @var Property[]
+ * @phpstan-var list>
+ */
+ private array $properties = [];
+
+ /**
+ * @phpstan-param TBlock $block
+ */
+ private function __construct(
+ private Block $block
+ ){}
+
+ /**
+ * @phpstan-template TBlock_ of Block
+ * @phpstan-param TBlock_ $block
+ * @return self
+ */
+ public static function create(Block $block) : self{
+ /** @phpstan-var self $result */
+ $result = new self($block);
+ return $result;
+ }
+
+ /** @phpstan-return TBlock */
+ public function getBlock() : Block{ return $this->block; }
+
+ /**
+ * @return string[]|StringProperty[]
+ * @phpstan-return list>
+ */
+ public function getIdComponents() : array{ return $this->idComponents; }
+
+ /**
+ * @return Property[]
+ * @phpstan-return list>
+ */
+ public function getProperties() : array{ return $this->properties; }
+
+ /**
+ * @param string[]|StringProperty[] $components
+ * @phpstan-param non-empty-list> $components
+ * @return $this
+ * @phpstan-this-out self
+ */
+ public function idComponents(array $components) : self{
+ $this->idComponents = $components;
+ return $this;
+ }
+
+ /**
+ * @param Property[] $properties
+ * @phpstan-param non-empty-list> $properties
+ * @return $this
+ * @phpstan-this-out self
+ */
+ public function properties(array $properties) : self{
+ $this->properties = $properties;
+ return $this;
+ }
+}
diff --git a/src/data/bedrock/block/convert/Model.php b/src/data/bedrock/block/convert/Model.php
new file mode 100644
index 000000000..3474a8932
--- /dev/null
+++ b/src/data/bedrock/block/convert/Model.php
@@ -0,0 +1,82 @@
+>
+ */
+ private array $properties = [];
+
+ /**
+ * @phpstan-param TBlock $block
+ */
+ private function __construct(
+ private Block $block,
+ private string $id
+ ){}
+
+ /** @phpstan-return TBlock */
+ public function getBlock() : Block{ return $this->block; }
+
+ public function getId() : string{ return $this->id; }
+
+ /**
+ * @return Property[]
+ * @phpstan-return list>
+ */
+ public function getProperties() : array{ return $this->properties; }
+
+ /**
+ * @phpstan-template TBlock_ of Block
+ * @phpstan-param TBlock_ $block
+ * @phpstan-return self
+ */
+ public static function create(Block $block, string $id) : self{
+ return new self($block, $id);
+ }
+
+ /**
+ * @param Property[] $properties
+ * @phpstan-param list> $properties
+ * @phpstan-return $this
+ */
+ public function properties(array $properties) : self{
+ $this->properties = $properties;
+ return $this;
+ }
+}
diff --git a/src/data/bedrock/block/convert/StringEnumMap.php b/src/data/bedrock/block/convert/StringEnumMap.php
deleted file mode 100644
index 6171c0e71..000000000
--- a/src/data/bedrock/block/convert/StringEnumMap.php
+++ /dev/null
@@ -1,78 +0,0 @@
-
- */
- private array $enumToValue = [];
-
- /**
- * @var \UnitEnum[]
- * @phpstan-var array
- */
- private array $valueToEnum = [];
-
- /**
- * @phpstan-param class-string $class
- * @phpstan-param \Closure(TEnum) : string $mapper
- */
- public function __construct(
- private string $class,
- \Closure $mapper
- ){
- foreach($class::cases() as $case){
- $string = $mapper($case);
- $this->valueToEnum[$string] = $case;
- $this->enumToValue[spl_object_id($case)] = $string;
- }
- }
-
- /**
- * @phpstan-param TEnum $enum
- */
- public function enumToValue(\UnitEnum $enum) : string{
- return $this->enumToValue[spl_object_id($enum)];
- }
-
- public function valueToEnum(string $string) : ?\UnitEnum{
- return $this->valueToEnum[$string] ?? throw new BlockStateDeserializeException("No $this->class enum mapping for \"$string\"");
- }
-
- /**
- * @return \UnitEnum[]
- * @phpstan-return array
- */
- public function getValueToEnum() : array{
- return $this->valueToEnum;
- }
-}
diff --git a/src/data/bedrock/block/convert/ValueMappings.php b/src/data/bedrock/block/convert/ValueMappings.php
deleted file mode 100644
index df57d6f53..000000000
--- a/src/data/bedrock/block/convert/ValueMappings.php
+++ /dev/null
@@ -1,83 +0,0 @@
-, StringEnumMap>
- */
- private array $enumMappings = [];
-
- public function __construct(){
- $this->addEnum(DyeColor::class, fn(DyeColor $case) => match ($case) {
- DyeColor::BLACK => "black",
- DyeColor::BLUE => "blue",
- DyeColor::BROWN => "brown",
- DyeColor::CYAN => "cyan",
- DyeColor::GRAY => "gray",
- DyeColor::GREEN => "green",
- DyeColor::LIGHT_BLUE => "light_blue",
- DyeColor::LIGHT_GRAY => "light_gray",
- DyeColor::LIME => "lime",
- DyeColor::MAGENTA => "magenta",
- DyeColor::ORANGE => "orange",
- DyeColor::PINK => "pink",
- DyeColor::PURPLE => "purple",
- DyeColor::RED => "red",
- DyeColor::WHITE => "white",
- DyeColor::YELLOW => "yellow"
- });
- }
-
- /**
- * @phpstan-template TEnum of \UnitEnum
- * @phpstan-param class-string $class
- * @phpstan-param \Closure(TEnum): string $mapper
- */
- private function addEnum(string $class, \Closure $mapper) : void{
- $this->enumMappings[$class] = new StringEnumMap($class, $mapper);
- }
-
- /**
- * @phpstan-template TEnum of \UnitEnum
- * @phpstan-param class-string $class
- * @phpstan-return StringEnumMap
- */
- public function getEnumMap(string $class) : StringEnumMap{
- if(!isset($this->enumMappings[$class])){
- throw new \InvalidArgumentException("No enum mapping found for class: $class");
- }
- /**
- * @phpstan-var StringEnumMap $map
- */
- $map = $this->enumMappings[$class];
- return $map;
- }
-}
diff --git a/src/data/bedrock/block/convert/VanillaBlockMappings.php b/src/data/bedrock/block/convert/VanillaBlockMappings.php
new file mode 100644
index 000000000..16ae1e244
--- /dev/null
+++ b/src/data/bedrock/block/convert/VanillaBlockMappings.php
@@ -0,0 +1,1561 @@
+mapSimple(Blocks::AIR(), Ids::AIR);
+ $reg->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
+ $reg->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS);
+ $reg->mapSimple(Blocks::ANDESITE(), Ids::ANDESITE);
+ $reg->mapSimple(Blocks::BARRIER(), Ids::BARRIER);
+ $reg->mapSimple(Blocks::BEACON(), Ids::BEACON);
+ $reg->mapSimple(Blocks::BLACKSTONE(), Ids::BLACKSTONE);
+ $reg->mapSimple(Blocks::BLUE_ICE(), Ids::BLUE_ICE);
+ $reg->mapSimple(Blocks::BOOKSHELF(), Ids::BOOKSHELF);
+ $reg->mapSimple(Blocks::BRICKS(), Ids::BRICK_BLOCK);
+ $reg->mapSimple(Blocks::BROWN_MUSHROOM(), Ids::BROWN_MUSHROOM);
+ $reg->mapSimple(Blocks::BUDDING_AMETHYST(), Ids::BUDDING_AMETHYST);
+ $reg->mapSimple(Blocks::CALCITE(), Ids::CALCITE);
+ $reg->mapSimple(Blocks::CARTOGRAPHY_TABLE(), Ids::CARTOGRAPHY_TABLE);
+ $reg->mapSimple(Blocks::CHEMICAL_HEAT(), Ids::CHEMICAL_HEAT);
+ $reg->mapSimple(Blocks::CHISELED_DEEPSLATE(), Ids::CHISELED_DEEPSLATE);
+ $reg->mapSimple(Blocks::CHISELED_NETHER_BRICKS(), Ids::CHISELED_NETHER_BRICKS);
+ $reg->mapSimple(Blocks::CHISELED_POLISHED_BLACKSTONE(), Ids::CHISELED_POLISHED_BLACKSTONE);
+ $reg->mapSimple(Blocks::CHISELED_RED_SANDSTONE(), Ids::CHISELED_RED_SANDSTONE);
+ $reg->mapSimple(Blocks::CHISELED_RESIN_BRICKS(), Ids::CHISELED_RESIN_BRICKS);
+ $reg->mapSimple(Blocks::CHISELED_SANDSTONE(), Ids::CHISELED_SANDSTONE);
+ $reg->mapSimple(Blocks::CHISELED_STONE_BRICKS(), Ids::CHISELED_STONE_BRICKS);
+ $reg->mapSimple(Blocks::CHISELED_TUFF(), Ids::CHISELED_TUFF);
+ $reg->mapSimple(Blocks::CHISELED_TUFF_BRICKS(), Ids::CHISELED_TUFF_BRICKS);
+ $reg->mapSimple(Blocks::CHORUS_PLANT(), Ids::CHORUS_PLANT);
+ $reg->mapSimple(Blocks::CLAY(), Ids::CLAY);
+ $reg->mapSimple(Blocks::COAL(), Ids::COAL_BLOCK);
+ $reg->mapSimple(Blocks::COAL_ORE(), Ids::COAL_ORE);
+ $reg->mapSimple(Blocks::COBBLED_DEEPSLATE(), Ids::COBBLED_DEEPSLATE);
+ $reg->mapSimple(Blocks::COBBLESTONE(), Ids::COBBLESTONE);
+ $reg->mapSimple(Blocks::COBWEB(), Ids::WEB);
+ $reg->mapSimple(Blocks::COPPER_ORE(), Ids::COPPER_ORE);
+ $reg->mapSimple(Blocks::CRACKED_DEEPSLATE_BRICKS(), Ids::CRACKED_DEEPSLATE_BRICKS);
+ $reg->mapSimple(Blocks::CRACKED_DEEPSLATE_TILES(), Ids::CRACKED_DEEPSLATE_TILES);
+ $reg->mapSimple(Blocks::CRACKED_NETHER_BRICKS(), Ids::CRACKED_NETHER_BRICKS);
+ $reg->mapSimple(Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS(), Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS);
+ $reg->mapSimple(Blocks::CRACKED_STONE_BRICKS(), Ids::CRACKED_STONE_BRICKS);
+ $reg->mapSimple(Blocks::CRAFTING_TABLE(), Ids::CRAFTING_TABLE);
+ $reg->mapSimple(Blocks::CRIMSON_ROOTS(), Ids::CRIMSON_ROOTS);
+ $reg->mapSimple(Blocks::CRYING_OBSIDIAN(), Ids::CRYING_OBSIDIAN);
+ $reg->mapSimple(Blocks::DANDELION(), Ids::DANDELION);
+ $reg->mapSimple(Blocks::CUT_RED_SANDSTONE(), Ids::CUT_RED_SANDSTONE);
+ $reg->mapSimple(Blocks::CUT_SANDSTONE(), Ids::CUT_SANDSTONE);
+ $reg->mapSimple(Blocks::DARK_PRISMARINE(), Ids::DARK_PRISMARINE);
+ $reg->mapSimple(Blocks::DEAD_BUSH(), Ids::DEADBUSH);
+ $reg->mapSimple(Blocks::DEEPSLATE_BRICKS(), Ids::DEEPSLATE_BRICKS);
+ $reg->mapSimple(Blocks::DEEPSLATE_COAL_ORE(), Ids::DEEPSLATE_COAL_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_COPPER_ORE(), Ids::DEEPSLATE_COPPER_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_DIAMOND_ORE(), Ids::DEEPSLATE_DIAMOND_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_EMERALD_ORE(), Ids::DEEPSLATE_EMERALD_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_GOLD_ORE(), Ids::DEEPSLATE_GOLD_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_IRON_ORE(), Ids::DEEPSLATE_IRON_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_LAPIS_LAZULI_ORE(), Ids::DEEPSLATE_LAPIS_ORE);
+ $reg->mapSimple(Blocks::DEEPSLATE_TILES(), Ids::DEEPSLATE_TILES);
+ $reg->mapSimple(Blocks::DIAMOND(), Ids::DIAMOND_BLOCK);
+ $reg->mapSimple(Blocks::DIAMOND_ORE(), Ids::DIAMOND_ORE);
+ $reg->mapSimple(Blocks::DIORITE(), Ids::DIORITE);
+ $reg->mapSimple(Blocks::DRAGON_EGG(), Ids::DRAGON_EGG);
+ $reg->mapSimple(Blocks::DRIED_KELP(), Ids::DRIED_KELP_BLOCK);
+ $reg->mapSimple(Blocks::ELEMENT_ACTINIUM(), Ids::ELEMENT_89);
+ $reg->mapSimple(Blocks::ELEMENT_ALUMINUM(), Ids::ELEMENT_13);
+ $reg->mapSimple(Blocks::ELEMENT_AMERICIUM(), Ids::ELEMENT_95);
+ $reg->mapSimple(Blocks::ELEMENT_ANTIMONY(), Ids::ELEMENT_51);
+ $reg->mapSimple(Blocks::ELEMENT_ARGON(), Ids::ELEMENT_18);
+ $reg->mapSimple(Blocks::ELEMENT_ARSENIC(), Ids::ELEMENT_33);
+ $reg->mapSimple(Blocks::ELEMENT_ASTATINE(), Ids::ELEMENT_85);
+ $reg->mapSimple(Blocks::ELEMENT_BARIUM(), Ids::ELEMENT_56);
+ $reg->mapSimple(Blocks::ELEMENT_BERKELIUM(), Ids::ELEMENT_97);
+ $reg->mapSimple(Blocks::ELEMENT_BERYLLIUM(), Ids::ELEMENT_4);
+ $reg->mapSimple(Blocks::ELEMENT_BISMUTH(), Ids::ELEMENT_83);
+ $reg->mapSimple(Blocks::ELEMENT_BOHRIUM(), Ids::ELEMENT_107);
+ $reg->mapSimple(Blocks::ELEMENT_BORON(), Ids::ELEMENT_5);
+ $reg->mapSimple(Blocks::ELEMENT_BROMINE(), Ids::ELEMENT_35);
+ $reg->mapSimple(Blocks::ELEMENT_CADMIUM(), Ids::ELEMENT_48);
+ $reg->mapSimple(Blocks::ELEMENT_CALCIUM(), Ids::ELEMENT_20);
+ $reg->mapSimple(Blocks::ELEMENT_CALIFORNIUM(), Ids::ELEMENT_98);
+ $reg->mapSimple(Blocks::ELEMENT_CARBON(), Ids::ELEMENT_6);
+ $reg->mapSimple(Blocks::ELEMENT_CERIUM(), Ids::ELEMENT_58);
+ $reg->mapSimple(Blocks::ELEMENT_CESIUM(), Ids::ELEMENT_55);
+ $reg->mapSimple(Blocks::ELEMENT_CHLORINE(), Ids::ELEMENT_17);
+ $reg->mapSimple(Blocks::ELEMENT_CHROMIUM(), Ids::ELEMENT_24);
+ $reg->mapSimple(Blocks::ELEMENT_COBALT(), Ids::ELEMENT_27);
+ $reg->mapSimple(Blocks::ELEMENT_COPERNICIUM(), Ids::ELEMENT_112);
+ $reg->mapSimple(Blocks::ELEMENT_COPPER(), Ids::ELEMENT_29);
+ $reg->mapSimple(Blocks::ELEMENT_CURIUM(), Ids::ELEMENT_96);
+ $reg->mapSimple(Blocks::ELEMENT_DARMSTADTIUM(), Ids::ELEMENT_110);
+ $reg->mapSimple(Blocks::ELEMENT_DUBNIUM(), Ids::ELEMENT_105);
+ $reg->mapSimple(Blocks::ELEMENT_DYSPROSIUM(), Ids::ELEMENT_66);
+ $reg->mapSimple(Blocks::ELEMENT_EINSTEINIUM(), Ids::ELEMENT_99);
+ $reg->mapSimple(Blocks::ELEMENT_ERBIUM(), Ids::ELEMENT_68);
+ $reg->mapSimple(Blocks::ELEMENT_EUROPIUM(), Ids::ELEMENT_63);
+ $reg->mapSimple(Blocks::ELEMENT_FERMIUM(), Ids::ELEMENT_100);
+ $reg->mapSimple(Blocks::ELEMENT_FLEROVIUM(), Ids::ELEMENT_114);
+ $reg->mapSimple(Blocks::ELEMENT_FLUORINE(), Ids::ELEMENT_9);
+ $reg->mapSimple(Blocks::ELEMENT_FRANCIUM(), Ids::ELEMENT_87);
+ $reg->mapSimple(Blocks::ELEMENT_GADOLINIUM(), Ids::ELEMENT_64);
+ $reg->mapSimple(Blocks::ELEMENT_GALLIUM(), Ids::ELEMENT_31);
+ $reg->mapSimple(Blocks::ELEMENT_GERMANIUM(), Ids::ELEMENT_32);
+ $reg->mapSimple(Blocks::ELEMENT_GOLD(), Ids::ELEMENT_79);
+ $reg->mapSimple(Blocks::ELEMENT_HAFNIUM(), Ids::ELEMENT_72);
+ $reg->mapSimple(Blocks::ELEMENT_HASSIUM(), Ids::ELEMENT_108);
+ $reg->mapSimple(Blocks::ELEMENT_HELIUM(), Ids::ELEMENT_2);
+ $reg->mapSimple(Blocks::ELEMENT_HOLMIUM(), Ids::ELEMENT_67);
+ $reg->mapSimple(Blocks::ELEMENT_HYDROGEN(), Ids::ELEMENT_1);
+ $reg->mapSimple(Blocks::ELEMENT_INDIUM(), Ids::ELEMENT_49);
+ $reg->mapSimple(Blocks::ELEMENT_IODINE(), Ids::ELEMENT_53);
+ $reg->mapSimple(Blocks::ELEMENT_IRIDIUM(), Ids::ELEMENT_77);
+ $reg->mapSimple(Blocks::ELEMENT_IRON(), Ids::ELEMENT_26);
+ $reg->mapSimple(Blocks::ELEMENT_KRYPTON(), Ids::ELEMENT_36);
+ $reg->mapSimple(Blocks::ELEMENT_LANTHANUM(), Ids::ELEMENT_57);
+ $reg->mapSimple(Blocks::ELEMENT_LAWRENCIUM(), Ids::ELEMENT_103);
+ $reg->mapSimple(Blocks::ELEMENT_LEAD(), Ids::ELEMENT_82);
+ $reg->mapSimple(Blocks::ELEMENT_LITHIUM(), Ids::ELEMENT_3);
+ $reg->mapSimple(Blocks::ELEMENT_LIVERMORIUM(), Ids::ELEMENT_116);
+ $reg->mapSimple(Blocks::ELEMENT_LUTETIUM(), Ids::ELEMENT_71);
+ $reg->mapSimple(Blocks::ELEMENT_MAGNESIUM(), Ids::ELEMENT_12);
+ $reg->mapSimple(Blocks::ELEMENT_MANGANESE(), Ids::ELEMENT_25);
+ $reg->mapSimple(Blocks::ELEMENT_MEITNERIUM(), Ids::ELEMENT_109);
+ $reg->mapSimple(Blocks::ELEMENT_MENDELEVIUM(), Ids::ELEMENT_101);
+ $reg->mapSimple(Blocks::ELEMENT_MERCURY(), Ids::ELEMENT_80);
+ $reg->mapSimple(Blocks::ELEMENT_MOLYBDENUM(), Ids::ELEMENT_42);
+ $reg->mapSimple(Blocks::ELEMENT_MOSCOVIUM(), Ids::ELEMENT_115);
+ $reg->mapSimple(Blocks::ELEMENT_NEODYMIUM(), Ids::ELEMENT_60);
+ $reg->mapSimple(Blocks::ELEMENT_NEON(), Ids::ELEMENT_10);
+ $reg->mapSimple(Blocks::ELEMENT_NEPTUNIUM(), Ids::ELEMENT_93);
+ $reg->mapSimple(Blocks::ELEMENT_NICKEL(), Ids::ELEMENT_28);
+ $reg->mapSimple(Blocks::ELEMENT_NIHONIUM(), Ids::ELEMENT_113);
+ $reg->mapSimple(Blocks::ELEMENT_NIOBIUM(), Ids::ELEMENT_41);
+ $reg->mapSimple(Blocks::ELEMENT_NITROGEN(), Ids::ELEMENT_7);
+ $reg->mapSimple(Blocks::ELEMENT_NOBELIUM(), Ids::ELEMENT_102);
+ $reg->mapSimple(Blocks::ELEMENT_OGANESSON(), Ids::ELEMENT_118);
+ $reg->mapSimple(Blocks::ELEMENT_OSMIUM(), Ids::ELEMENT_76);
+ $reg->mapSimple(Blocks::ELEMENT_OXYGEN(), Ids::ELEMENT_8);
+ $reg->mapSimple(Blocks::ELEMENT_PALLADIUM(), Ids::ELEMENT_46);
+ $reg->mapSimple(Blocks::ELEMENT_PHOSPHORUS(), Ids::ELEMENT_15);
+ $reg->mapSimple(Blocks::ELEMENT_PLATINUM(), Ids::ELEMENT_78);
+ $reg->mapSimple(Blocks::ELEMENT_PLUTONIUM(), Ids::ELEMENT_94);
+ $reg->mapSimple(Blocks::ELEMENT_POLONIUM(), Ids::ELEMENT_84);
+ $reg->mapSimple(Blocks::ELEMENT_POTASSIUM(), Ids::ELEMENT_19);
+ $reg->mapSimple(Blocks::ELEMENT_PRASEODYMIUM(), Ids::ELEMENT_59);
+ $reg->mapSimple(Blocks::ELEMENT_PROMETHIUM(), Ids::ELEMENT_61);
+ $reg->mapSimple(Blocks::ELEMENT_PROTACTINIUM(), Ids::ELEMENT_91);
+ $reg->mapSimple(Blocks::ELEMENT_RADIUM(), Ids::ELEMENT_88);
+ $reg->mapSimple(Blocks::ELEMENT_RADON(), Ids::ELEMENT_86);
+ $reg->mapSimple(Blocks::ELEMENT_RHENIUM(), Ids::ELEMENT_75);
+ $reg->mapSimple(Blocks::ELEMENT_RHODIUM(), Ids::ELEMENT_45);
+ $reg->mapSimple(Blocks::ELEMENT_ROENTGENIUM(), Ids::ELEMENT_111);
+ $reg->mapSimple(Blocks::ELEMENT_RUBIDIUM(), Ids::ELEMENT_37);
+ $reg->mapSimple(Blocks::ELEMENT_RUTHENIUM(), Ids::ELEMENT_44);
+ $reg->mapSimple(Blocks::ELEMENT_RUTHERFORDIUM(), Ids::ELEMENT_104);
+ $reg->mapSimple(Blocks::ELEMENT_SAMARIUM(), Ids::ELEMENT_62);
+ $reg->mapSimple(Blocks::ELEMENT_SCANDIUM(), Ids::ELEMENT_21);
+ $reg->mapSimple(Blocks::ELEMENT_SEABORGIUM(), Ids::ELEMENT_106);
+ $reg->mapSimple(Blocks::ELEMENT_SELENIUM(), Ids::ELEMENT_34);
+ $reg->mapSimple(Blocks::ELEMENT_SILICON(), Ids::ELEMENT_14);
+ $reg->mapSimple(Blocks::ELEMENT_SILVER(), Ids::ELEMENT_47);
+ $reg->mapSimple(Blocks::ELEMENT_SODIUM(), Ids::ELEMENT_11);
+ $reg->mapSimple(Blocks::ELEMENT_STRONTIUM(), Ids::ELEMENT_38);
+ $reg->mapSimple(Blocks::ELEMENT_SULFUR(), Ids::ELEMENT_16);
+ $reg->mapSimple(Blocks::ELEMENT_TANTALUM(), Ids::ELEMENT_73);
+ $reg->mapSimple(Blocks::ELEMENT_TECHNETIUM(), Ids::ELEMENT_43);
+ $reg->mapSimple(Blocks::ELEMENT_TELLURIUM(), Ids::ELEMENT_52);
+ $reg->mapSimple(Blocks::ELEMENT_TENNESSINE(), Ids::ELEMENT_117);
+ $reg->mapSimple(Blocks::ELEMENT_TERBIUM(), Ids::ELEMENT_65);
+ $reg->mapSimple(Blocks::ELEMENT_THALLIUM(), Ids::ELEMENT_81);
+ $reg->mapSimple(Blocks::ELEMENT_THORIUM(), Ids::ELEMENT_90);
+ $reg->mapSimple(Blocks::ELEMENT_THULIUM(), Ids::ELEMENT_69);
+ $reg->mapSimple(Blocks::ELEMENT_TIN(), Ids::ELEMENT_50);
+ $reg->mapSimple(Blocks::ELEMENT_TITANIUM(), Ids::ELEMENT_22);
+ $reg->mapSimple(Blocks::ELEMENT_TUNGSTEN(), Ids::ELEMENT_74);
+ $reg->mapSimple(Blocks::ELEMENT_URANIUM(), Ids::ELEMENT_92);
+ $reg->mapSimple(Blocks::ELEMENT_VANADIUM(), Ids::ELEMENT_23);
+ $reg->mapSimple(Blocks::ELEMENT_XENON(), Ids::ELEMENT_54);
+ $reg->mapSimple(Blocks::ELEMENT_YTTERBIUM(), Ids::ELEMENT_70);
+ $reg->mapSimple(Blocks::ELEMENT_YTTRIUM(), Ids::ELEMENT_39);
+ $reg->mapSimple(Blocks::ELEMENT_ZERO(), Ids::ELEMENT_0);
+ $reg->mapSimple(Blocks::ELEMENT_ZINC(), Ids::ELEMENT_30);
+ $reg->mapSimple(Blocks::ELEMENT_ZIRCONIUM(), Ids::ELEMENT_40);
+ $reg->mapSimple(Blocks::EMERALD(), Ids::EMERALD_BLOCK);
+ $reg->mapSimple(Blocks::EMERALD_ORE(), Ids::EMERALD_ORE);
+ $reg->mapSimple(Blocks::ENCHANTING_TABLE(), Ids::ENCHANTING_TABLE);
+ $reg->mapSimple(Blocks::END_STONE(), Ids::END_STONE);
+ $reg->mapSimple(Blocks::END_STONE_BRICKS(), Ids::END_BRICKS);
+ $reg->mapSimple(Blocks::FERN(), Ids::FERN);
+ $reg->mapSimple(Blocks::FLETCHING_TABLE(), Ids::FLETCHING_TABLE);
+ $reg->mapSimple(Blocks::GILDED_BLACKSTONE(), Ids::GILDED_BLACKSTONE);
+ $reg->mapSimple(Blocks::GLASS(), Ids::GLASS);
+ $reg->mapSimple(Blocks::GLASS_PANE(), Ids::GLASS_PANE);
+ $reg->mapSimple(Blocks::GLOWING_OBSIDIAN(), Ids::GLOWINGOBSIDIAN);
+ $reg->mapSimple(Blocks::GLOWSTONE(), Ids::GLOWSTONE);
+ $reg->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK);
+ $reg->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE);
+ $reg->mapSimple(Blocks::GRANITE(), Ids::GRANITE);
+ $reg->mapSimple(Blocks::GRASS(), Ids::GRASS_BLOCK);
+ $reg->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH);
+ $reg->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL);
+ $reg->mapSimple(Blocks::HANGING_ROOTS(), Ids::HANGING_ROOTS);
+ $reg->mapSimple(Blocks::HARDENED_CLAY(), Ids::HARDENED_CLAY);
+ $reg->mapSimple(Blocks::HARDENED_GLASS(), Ids::HARD_GLASS);
+ $reg->mapSimple(Blocks::HARDENED_GLASS_PANE(), Ids::HARD_GLASS_PANE);
+ $reg->mapSimple(Blocks::HONEYCOMB(), Ids::HONEYCOMB_BLOCK);
+ $reg->mapSimple(Blocks::ICE(), Ids::ICE);
+ $reg->mapSimple(Blocks::INFESTED_CHISELED_STONE_BRICK(), Ids::INFESTED_CHISELED_STONE_BRICKS);
+ $reg->mapSimple(Blocks::INFESTED_COBBLESTONE(), Ids::INFESTED_COBBLESTONE);
+ $reg->mapSimple(Blocks::INFESTED_CRACKED_STONE_BRICK(), Ids::INFESTED_CRACKED_STONE_BRICKS);
+ $reg->mapSimple(Blocks::INFESTED_MOSSY_STONE_BRICK(), Ids::INFESTED_MOSSY_STONE_BRICKS);
+ $reg->mapSimple(Blocks::INFESTED_STONE(), Ids::INFESTED_STONE);
+ $reg->mapSimple(Blocks::INFESTED_STONE_BRICK(), Ids::INFESTED_STONE_BRICKS);
+ $reg->mapSimple(Blocks::INFO_UPDATE(), Ids::INFO_UPDATE);
+ $reg->mapSimple(Blocks::INFO_UPDATE2(), Ids::INFO_UPDATE2);
+ $reg->mapSimple(Blocks::INVISIBLE_BEDROCK(), Ids::INVISIBLE_BEDROCK);
+ $reg->mapSimple(Blocks::IRON(), Ids::IRON_BLOCK);
+ $reg->mapSimple(Blocks::IRON_BARS(), Ids::IRON_BARS);
+ $reg->mapSimple(Blocks::IRON_ORE(), Ids::IRON_ORE);
+ $reg->mapSimple(Blocks::JUKEBOX(), Ids::JUKEBOX);
+ $reg->mapSimple(Blocks::LAPIS_LAZULI(), Ids::LAPIS_BLOCK);
+ $reg->mapSimple(Blocks::LAPIS_LAZULI_ORE(), Ids::LAPIS_ORE);
+ $reg->mapSimple(Blocks::LEGACY_STONECUTTER(), Ids::STONECUTTER);
+ $reg->mapSimple(Blocks::LILY_PAD(), Ids::WATERLILY);
+ $reg->mapSimple(Blocks::MAGMA(), Ids::MAGMA);
+ $reg->mapSimple(Blocks::MANGROVE_ROOTS(), Ids::MANGROVE_ROOTS);
+ $reg->mapSimple(Blocks::MELON(), Ids::MELON_BLOCK);
+ $reg->mapSimple(Blocks::MONSTER_SPAWNER(), Ids::MOB_SPAWNER);
+ $reg->mapSimple(Blocks::MOSSY_COBBLESTONE(), Ids::MOSSY_COBBLESTONE);
+ $reg->mapSimple(Blocks::MOSSY_STONE_BRICKS(), Ids::MOSSY_STONE_BRICKS);
+ $reg->mapSimple(Blocks::MUD(), Ids::MUD);
+ $reg->mapSimple(Blocks::MUD_BRICKS(), Ids::MUD_BRICKS);
+ $reg->mapSimple(Blocks::MYCELIUM(), Ids::MYCELIUM);
+ $reg->mapSimple(Blocks::NETHERITE(), Ids::NETHERITE_BLOCK);
+ $reg->mapSimple(Blocks::NETHERRACK(), Ids::NETHERRACK);
+ $reg->mapSimple(Blocks::NETHER_BRICKS(), Ids::NETHER_BRICK);
+ $reg->mapSimple(Blocks::NETHER_BRICK_FENCE(), Ids::NETHER_BRICK_FENCE);
+ $reg->mapSimple(Blocks::NETHER_GOLD_ORE(), Ids::NETHER_GOLD_ORE);
+ $reg->mapSimple(Blocks::NETHER_QUARTZ_ORE(), Ids::QUARTZ_ORE);
+ $reg->mapSimple(Blocks::NETHER_REACTOR_CORE(), Ids::NETHERREACTOR);
+ $reg->mapSimple(Blocks::NETHER_WART_BLOCK(), Ids::NETHER_WART_BLOCK);
+ $reg->mapSimple(Blocks::NOTE_BLOCK(), Ids::NOTEBLOCK);
+ $reg->mapSimple(Blocks::OBSIDIAN(), Ids::OBSIDIAN);
+ $reg->mapSimple(Blocks::PACKED_ICE(), Ids::PACKED_ICE);
+ $reg->mapSimple(Blocks::PACKED_MUD(), Ids::PACKED_MUD);
+ $reg->mapSimple(Blocks::PODZOL(), Ids::PODZOL);
+ $reg->mapSimple(Blocks::POLISHED_ANDESITE(), Ids::POLISHED_ANDESITE);
+ $reg->mapSimple(Blocks::POLISHED_BLACKSTONE(), Ids::POLISHED_BLACKSTONE);
+ $reg->mapSimple(Blocks::POLISHED_BLACKSTONE_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS);
+ $reg->mapSimple(Blocks::POLISHED_DEEPSLATE(), Ids::POLISHED_DEEPSLATE);
+ $reg->mapSimple(Blocks::POLISHED_DIORITE(), Ids::POLISHED_DIORITE);
+ $reg->mapSimple(Blocks::POLISHED_GRANITE(), Ids::POLISHED_GRANITE);
+ $reg->mapSimple(Blocks::POLISHED_TUFF(), Ids::POLISHED_TUFF);
+ $reg->mapSimple(Blocks::PRISMARINE(), Ids::PRISMARINE);
+ $reg->mapSimple(Blocks::PRISMARINE_BRICKS(), Ids::PRISMARINE_BRICKS);
+ $reg->mapSimple(Blocks::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS);
+ $reg->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK);
+ $reg->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK);
+ $reg->mapSimple(Blocks::RAW_IRON(), Ids::RAW_IRON_BLOCK);
+ $reg->mapSimple(Blocks::REDSTONE(), Ids::REDSTONE_BLOCK);
+ $reg->mapSimple(Blocks::RED_MUSHROOM(), Ids::RED_MUSHROOM);
+ $reg->mapSimple(Blocks::RED_NETHER_BRICKS(), Ids::RED_NETHER_BRICK);
+ $reg->mapSimple(Blocks::RED_SAND(), Ids::RED_SAND);
+ $reg->mapSimple(Blocks::RED_SANDSTONE(), Ids::RED_SANDSTONE);
+ $reg->mapSimple(Blocks::REINFORCED_DEEPSLATE(), Ids::REINFORCED_DEEPSLATE);
+ $reg->mapSimple(Blocks::RESERVED6(), Ids::RESERVED6);
+ $reg->mapSimple(Blocks::RESIN(), Ids::RESIN_BLOCK);
+ $reg->mapSimple(Blocks::RESIN_BRICKS(), Ids::RESIN_BRICKS);
+ $reg->mapSimple(Blocks::SAND(), Ids::SAND);
+ $reg->mapSimple(Blocks::SANDSTONE(), Ids::SANDSTONE);
+ $reg->mapSimple(Blocks::SCULK(), Ids::SCULK);
+ $reg->mapSimple(Blocks::SEA_LANTERN(), Ids::SEA_LANTERN);
+ $reg->mapSimple(Blocks::SHROOMLIGHT(), Ids::SHROOMLIGHT);
+ $reg->mapSimple(Blocks::SHULKER_BOX(), Ids::UNDYED_SHULKER_BOX);
+ $reg->mapSimple(Blocks::SLIME(), Ids::SLIME);
+ $reg->mapSimple(Blocks::SMITHING_TABLE(), Ids::SMITHING_TABLE);
+ $reg->mapSimple(Blocks::SMOOTH_BASALT(), Ids::SMOOTH_BASALT);
+ $reg->mapSimple(Blocks::SMOOTH_RED_SANDSTONE(), Ids::SMOOTH_RED_SANDSTONE);
+ $reg->mapSimple(Blocks::SMOOTH_SANDSTONE(), Ids::SMOOTH_SANDSTONE);
+ $reg->mapSimple(Blocks::SMOOTH_STONE(), Ids::SMOOTH_STONE);
+ $reg->mapSimple(Blocks::SNOW(), Ids::SNOW);
+ $reg->mapSimple(Blocks::SOUL_SAND(), Ids::SOUL_SAND);
+ $reg->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL);
+ $reg->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM);
+ $reg->mapSimple(Blocks::STONE(), Ids::STONE);
+ $reg->mapSimple(Blocks::STONE_BRICKS(), Ids::STONE_BRICKS);
+ $reg->mapSimple(Blocks::TALL_GRASS(), Ids::SHORT_GRASS); //no, this is not a typo - tall_grass is now the double block, just to be confusing :(
+ $reg->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS);
+ $reg->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER);
+ $reg->mapSimple(Blocks::TUFF(), Ids::TUFF);
+ $reg->mapSimple(Blocks::TUFF_BRICKS(), Ids::TUFF_BRICKS);
+ $reg->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK);
+ $reg->mapSimple(Blocks::WARPED_ROOTS(), Ids::WARPED_ROOTS);
+ $reg->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE);
+
+ $reg->mapSimple(Blocks::ALLIUM(), Ids::ALLIUM);
+ $reg->mapSimple(Blocks::CORNFLOWER(), Ids::CORNFLOWER);
+ $reg->mapSimple(Blocks::AZURE_BLUET(), Ids::AZURE_BLUET);
+ $reg->mapSimple(Blocks::LILY_OF_THE_VALLEY(), Ids::LILY_OF_THE_VALLEY);
+ $reg->mapSimple(Blocks::BLUE_ORCHID(), Ids::BLUE_ORCHID);
+ $reg->mapSimple(Blocks::OXEYE_DAISY(), Ids::OXEYE_DAISY);
+ $reg->mapSimple(Blocks::POPPY(), Ids::POPPY);
+ $reg->mapSimple(Blocks::ORANGE_TULIP(), Ids::ORANGE_TULIP);
+ $reg->mapSimple(Blocks::PINK_TULIP(), Ids::PINK_TULIP);
+ $reg->mapSimple(Blocks::RED_TULIP(), Ids::RED_TULIP);
+ $reg->mapSimple(Blocks::WHITE_TULIP(), Ids::WHITE_TULIP);
+ }
+
+ private static function registerColoredMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ $reg->mapColored(Blocks::STAINED_HARDENED_GLASS(), "minecraft:hard_", "_stained_glass");
+ $reg->mapColored(Blocks::STAINED_HARDENED_GLASS_PANE(), "minecraft:hard_", "_stained_glass_pane");
+
+ $reg->mapColored(Blocks::CARPET(), "minecraft:", "_carpet");
+ $reg->mapColored(Blocks::CONCRETE(), "minecraft:", "_concrete");
+ $reg->mapColored(Blocks::CONCRETE_POWDER(), "minecraft:", "_concrete_powder");
+ $reg->mapColored(Blocks::DYED_SHULKER_BOX(), "minecraft:", "_shulker_box");
+ $reg->mapColored(Blocks::STAINED_CLAY(), "minecraft:", "_terracotta");
+ $reg->mapColored(Blocks::STAINED_GLASS(), "minecraft:", "_stained_glass");
+ $reg->mapColored(Blocks::STAINED_GLASS_PANE(), "minecraft:", "_stained_glass_pane");
+ $reg->mapColored(Blocks::WOOL(), "minecraft:", "_wool");
+
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::GLAZED_TERRACOTTA())
+ ->idComponents([
+ "minecraft:",
+ new ValueFromStringProperty("color", ValueMappings::getInstance()->dyeColorWithSilver, fn(GlazedTerracotta $b) => $b->getColor(), fn(GlazedTerracotta $b, DyeColor $v) => $b->setColor($v)),
+ "_glazed_terracotta"
+ ])
+ ->properties([$commonProperties->horizontalFacingClassic])
+ );
+ }
+
+ private static function registerCandleMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ $candleProperties = [
+ $commonProperties->lit,
+ new IntProperty(StateNames::CANDLES, 0, 3, fn(Candle $b) => $b->getCount(), fn(Candle $b, int $v) => $b->setCount($v), offset: 1),
+ ];
+ $cakeWithCandleProperties = [$commonProperties->lit];
+ $reg->mapModel(Model::create(Blocks::CANDLE(), Ids::CANDLE)->properties($candleProperties));
+ $reg->mapModel(Model::create(Blocks::CAKE_WITH_CANDLE(), Ids::CANDLE_CAKE)->properties($cakeWithCandleProperties));
+
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::DYED_CANDLE())
+ ->idComponents([
+ "minecraft:",
+ $commonProperties->dyeColorIdInfix,
+ "_candle"
+ ])
+ ->properties($candleProperties)
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CAKE_WITH_DYED_CANDLE())
+ ->idComponents([
+ "minecraft:",
+ $commonProperties->dyeColorIdInfix,
+ "_candle_cake"
+ ])
+ ->properties($cakeWithCandleProperties)
+ );
+ }
+
+ private static function registerLeavesMappings(BlockSerializerDeserializerRegistrar $reg) : void{
+ $properties = [
+ new BoolProperty(StateNames::PERSISTENT_BIT, fn(Leaves $b) => $b->isNoDecay(), fn(Leaves $b, bool $v) => $b->setNoDecay($v)),
+ new BoolProperty(StateNames::UPDATE_BIT, fn(Leaves $b) => $b->isCheckDecay(), fn(Leaves $b, bool $v) => $b->setCheckDecay($v)),
+ ];
+ foreach([
+ Ids::ACACIA_LEAVES => Blocks::ACACIA_LEAVES(),
+ Ids::AZALEA_LEAVES => Blocks::AZALEA_LEAVES(),
+ Ids::AZALEA_LEAVES_FLOWERED => Blocks::FLOWERING_AZALEA_LEAVES(),
+ Ids::BIRCH_LEAVES => Blocks::BIRCH_LEAVES(),
+ Ids::CHERRY_LEAVES => Blocks::CHERRY_LEAVES(),
+ Ids::DARK_OAK_LEAVES => Blocks::DARK_OAK_LEAVES(),
+ Ids::JUNGLE_LEAVES => Blocks::JUNGLE_LEAVES(),
+ Ids::MANGROVE_LEAVES => Blocks::MANGROVE_LEAVES(),
+ Ids::OAK_LEAVES => Blocks::OAK_LEAVES(),
+ Ids::PALE_OAK_LEAVES => Blocks::PALE_OAK_LEAVES(),
+ Ids::SPRUCE_LEAVES => Blocks::SPRUCE_LEAVES()
+ ] as $id => $block){
+ $reg->mapModel(Model::create($block, $id)->properties($properties));
+ }
+ }
+
+ private static function registerSaplingMappings(BlockSerializerDeserializerRegistrar $reg) : void{
+ $properties = [
+ new BoolProperty(StateNames::AGE_BIT, fn(Sapling $b) => $b->isReady(), fn(Sapling $b, bool $v) => $b->setReady($v)),
+ ];
+ foreach([
+ Ids::ACACIA_SAPLING => Blocks::ACACIA_SAPLING(),
+ Ids::BIRCH_SAPLING => Blocks::BIRCH_SAPLING(),
+ Ids::DARK_OAK_SAPLING => Blocks::DARK_OAK_SAPLING(),
+ Ids::JUNGLE_SAPLING => Blocks::JUNGLE_SAPLING(),
+ Ids::OAK_SAPLING => Blocks::OAK_SAPLING(),
+ Ids::SPRUCE_SAPLING => Blocks::SPRUCE_SAPLING(),
+ ] as $id => $block){
+ $reg->mapModel(Model::create($block, $id)->properties($properties));
+ }
+ }
+
+ private static function registerPlantMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ $reg->mapModel(Model::create(Blocks::BEETROOTS(), Ids::BEETROOT)->properties([$commonProperties->cropAgeMax7]));
+ $reg->mapModel(Model::create(Blocks::CARROTS(), Ids::CARROTS)->properties([$commonProperties->cropAgeMax7]));
+ $reg->mapModel(Model::create(Blocks::POTATOES(), Ids::POTATOES)->properties([$commonProperties->cropAgeMax7]));
+ $reg->mapModel(Model::create(Blocks::WHEAT(), Ids::WHEAT)->properties([$commonProperties->cropAgeMax7]));
+
+ $reg->mapModel(Model::create(Blocks::MELON_STEM(), Ids::MELON_STEM)->properties($commonProperties->stemProperties));
+ $reg->mapModel(Model::create(Blocks::PUMPKIN_STEM(), Ids::PUMPKIN_STEM)->properties($commonProperties->stemProperties));
+
+ foreach([
+ [Blocks::DOUBLE_TALLGRASS(), Ids::TALL_GRASS],
+ [Blocks::LARGE_FERN(), Ids::LARGE_FERN],
+ [Blocks::LILAC(), Ids::LILAC],
+ [Blocks::PEONY(), Ids::PEONY],
+ [Blocks::ROSE_BUSH(), Ids::ROSE_BUSH],
+ [Blocks::SUNFLOWER(), Ids::SUNFLOWER],
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->doublePlantHalf]));
+ }
+
+ foreach([
+ [Blocks::BROWN_MUSHROOM_BLOCK(), Ids::BROWN_MUSHROOM_BLOCK],
+ [Blocks::RED_MUSHROOM_BLOCK(), Ids::RED_MUSHROOM_BLOCK]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties([
+ new ValueFromIntProperty(StateNames::HUGE_MUSHROOM_BITS, ValueMappings::getInstance()->mushroomBlockType, fn(RedMushroomBlock $b) => $b->getMushroomBlockType(), fn(RedMushroomBlock $b, MushroomBlockType $v) => $b->setMushroomBlockType($v)),
+ ]));
+ }
+
+ $reg->mapModel(Model::create(Blocks::GLOW_LICHEN(), Ids::GLOW_LICHEN)->properties([$commonProperties->multiFacingFlags]));
+ $reg->mapModel(Model::create(Blocks::RESIN_CLUMP(), Ids::RESIN_CLUMP)->properties([$commonProperties->multiFacingFlags]));
+
+ $reg->mapModel(Model::create(Blocks::VINES(), Ids::VINE)->properties([
+ new OptionSetFromIntProperty(
+ StateNames::VINE_DIRECTION_BITS,
+ IntFromRawStateMap::int([
+ Facing::NORTH => BlockLegacyMetadata::VINE_FLAG_NORTH,
+ Facing::SOUTH => BlockLegacyMetadata::VINE_FLAG_SOUTH,
+ Facing::WEST => BlockLegacyMetadata::VINE_FLAG_WEST,
+ Facing::EAST => BlockLegacyMetadata::VINE_FLAG_EAST,
+ ]),
+ fn(Vine $b) => $b->getFaces(),
+ fn(Vine $b, array $v) => $b->setFaces($v)
+ )
+ ]));
+
+ $reg->mapModel(Model::create(Blocks::SWEET_BERRY_BUSH(), Ids::SWEET_BERRY_BUSH)->properties([
+ //TODO: berry bush only wants 0-3, but it can be bigger in MCPE due to misuse of GROWTH state which goes up to 7
+ new IntProperty(StateNames::GROWTH, 0, 7, fn(SweetBerryBush $b) => $b->getAge(), fn(SweetBerryBush $b, int $v) => $b->setAge(min($v, SweetBerryBush::STAGE_MATURE)))
+ ]));
+ $reg->mapModel(Model::create(Blocks::TORCHFLOWER_CROP(), Ids::TORCHFLOWER_CROP)->properties([
+ //TODO: this property can have values 0-7, but only 0-1 are valid
+ new IntProperty(StateNames::GROWTH, 0, 7, fn(TorchflowerCrop $b) => $b->isReady() ? 1 : 0, fn(TorchflowerCrop $b, int $v) => $b->setReady($v !== 0))
+ ]));
+ }
+
+ private static function registerCoralMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CORAL())->idComponents([...$commonProperties->coralIdPrefixes, "_coral"]));
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CORAL_BLOCK())->idComponents([...$commonProperties->coralIdPrefixes, "_coral_block"]));
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CORAL_FAN())
+ ->idComponents([...$commonProperties->coralIdPrefixes, "_coral_fan"])
+ ->properties([
+ new ValueFromIntProperty(StateNames::CORAL_FAN_DIRECTION, ValueMappings::getInstance()->coralAxis, fn(FloorCoralFan $b) => $b->getAxis(), fn(FloorCoralFan $b, int $v) => $b->setAxis($v))
+ ])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::WALL_CORAL_FAN())
+ ->idComponents([...$commonProperties->coralIdPrefixes, "_coral_wall_fan"])
+ ->properties([
+ new ValueFromIntProperty(StateNames::CORAL_DIRECTION, ValueMappings::getInstance()->horizontalFacingCoral, fn(HorizontalFacing $b) => $b->getFacing(), fn(HorizontalFacing $b, int $v) => $b->setFacing($v)),
+ ])
+ );
+ }
+
+ private static function registerCopperMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_BULB())
+ ->idComponents([...$commonProperties->copperIdPrefixes, "copper_bulb"])
+ ->properties([
+ $commonProperties->lit,
+ new BoolProperty(StateNames::POWERED_BIT, fn(PoweredByRedstone $b) => $b->isPowered(), fn(PoweredByRedstone $b, bool $v) => $b->setPowered($v)),
+ ])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER())
+ ->idComponents([
+ ...$commonProperties->copperIdPrefixes,
+ "copper",
+ //HACK: the non-waxed, non-oxidised variant has a _block suffix, but none of the others do
+ new BoolFromStringProperty("bruhhhh", "", "_block", fn(Copper $b) => !$b->isWaxed() && $b->getOxidation() === CopperOxidation::NONE, fn() => null)
+ ])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CHISELED_COPPER())->idComponents([...$commonProperties->copperIdPrefixes, "chiseled_copper"]));
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_GRATE())->idComponents([...$commonProperties->copperIdPrefixes, "copper_grate"]));
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CUT_COPPER())->idComponents([...$commonProperties->copperIdPrefixes, "cut_copper"]));
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CUT_COPPER_STAIRS())
+ ->idComponents([...$commonProperties->copperIdPrefixes, "cut_copper_stairs"])
+ ->properties($commonProperties->stairProperties)
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_TRAPDOOR())
+ ->idComponents([...$commonProperties->copperIdPrefixes, "copper_trapdoor"])
+ ->properties($commonProperties->trapdoorProperties)
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_DOOR())
+ ->idComponents([...$commonProperties->copperIdPrefixes, "copper_door"])
+ ->properties($commonProperties->doorProperties)
+ );
+
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CUT_COPPER_SLAB())
+ ->idComponents([
+ ...$commonProperties->copperIdPrefixes,
+ $commonProperties->slabIdInfix,
+ "cut_copper_slab"
+ ])
+ ->properties([$commonProperties->slabPositionProperty])
+ );
+ }
+
+ private static function registerFlattenedEnumMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ //A
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::ANVIL())
+ ->idComponents([
+ new ValueFromStringProperty("id", IntFromRawStateMap::string([
+ 0 => Ids::ANVIL,
+ 1 => Ids::CHIPPED_ANVIL,
+ 2 => Ids::DAMAGED_ANVIL,
+ ]), fn(Anvil $b) => $b->getDamage(), fn(Anvil $b, int $v) => $b->setDamage($v))
+ ])
+ ->properties([$commonProperties->horizontalFacingCardinal])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::AMETHYST_CLUSTER())
+ ->idComponents([
+ new ValueFromStringProperty("id", IntFromRawStateMap::string([
+ AmethystCluster::STAGE_SMALL_BUD => Ids::SMALL_AMETHYST_BUD,
+ AmethystCluster::STAGE_MEDIUM_BUD => Ids::MEDIUM_AMETHYST_BUD,
+ AmethystCluster::STAGE_LARGE_BUD => Ids::LARGE_AMETHYST_BUD,
+ AmethystCluster::STAGE_CLUSTER => Ids::AMETHYST_CLUSTER
+ ]), fn(AmethystCluster $b) => $b->getStage(), fn(AmethystCluster $b, int $v) => $b->setStage($v))
+ ])
+ ->properties([$commonProperties->blockFace])
+ );
+
+ //C
+ //This one is a special offender :<
+ //I have no idea why this only has 3 IDs - there are 4 in Java and 4 visually distinct states in Bedrock
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CAVE_VINES())
+ ->idComponents([
+ "minecraft:cave_vines",
+ new ValueFromStringProperty(
+ "variant",
+ EnumFromRawStateMap::string(FlattenedCaveVinesVariant::class, fn(FlattenedCaveVinesVariant $case) => $case->value),
+ fn(CaveVines $b) => $b->hasBerries() ?
+ ($b->isHead() ?
+ FlattenedCaveVinesVariant::HEAD_WITH_BERRIES :
+ FlattenedCaveVinesVariant::BODY_WITH_BERRIES) :
+ FlattenedCaveVinesVariant::NO_BERRIES,
+ fn(CaveVines $b, FlattenedCaveVinesVariant $v) => match($v){
+ FlattenedCaveVinesVariant::HEAD_WITH_BERRIES => $b->setBerries(true)->setHead(true),
+ FlattenedCaveVinesVariant::BODY_WITH_BERRIES => $b->setBerries(true)->setHead(false),
+ FlattenedCaveVinesVariant::NO_BERRIES => $b->setBerries(false)->setHead(false), //assume this isn't a head, since we don't have enough information
+ }
+ )
+ ])
+ ->properties([
+ new IntProperty(StateNames::GROWING_PLANT_AGE, 0, 25, fn(CaveVines $b) => $b->getAge(), fn(CaveVines $b, int $v) => $b->setAge($v)),
+ ])
+ );
+
+ //D
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::DIRT())
+ ->idComponents([
+ new ValueFromStringProperty("id", EnumFromRawStateMap::string(DirtType::class, fn(DirtType $case) => match ($case) {
+ DirtType::NORMAL => Ids::DIRT,
+ DirtType::COARSE => Ids::COARSE_DIRT,
+ DirtType::ROOTED => Ids::DIRT_WITH_ROOTS,
+ }), fn(Dirt $b) => $b->getDirtType(), fn(Dirt $b, DirtType $v) => $b->setDirtType($v))
+ ])
+ );
+
+ //F
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::FROGLIGHT())
+ ->idComponents([
+ new ValueFromStringProperty("id", ValueMappings::getInstance()->froglightType, fn(Froglight $b) => $b->getFroglightType(), fn(Froglight $b, FroglightType $v) => $b->setFroglightType($v)),
+ ])
+ ->properties([$commonProperties->pillarAxis])
+ );
+
+ //L
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::LIGHT())
+ ->idComponents([
+ "minecraft:light_block_",
+ //this is a bit shit but it's easier than adapting IntProperty to support flattening :D
+ new ValueFromStringProperty(
+ "light_level",
+ IntFromRawStateMap::string(array_map(strval(...), range(0, 15))),
+ fn(Light $b) => $b->getLightLevel(),
+ fn(Light $b, int $v) => $b->setLightLevel($v)
+ )
+ ])
+ );
+
+ //M
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::MOB_HEAD())
+ ->idComponents([
+ new ValueFromStringProperty("id", ValueMappings::getInstance()->mobHeadType, fn(MobHead $b) => $b->getMobHeadType(), fn(MobHead $b, MobHeadType $v) => $b->setMobHeadType($v)),
+ ])
+ ->properties([
+ new ValueFromIntProperty(StateNames::FACING_DIRECTION, ValueMappings::getInstance()->facingExceptDown, fn(MobHead $b) => $b->getFacing(), fn(MobHead $b, int $v) => $b->setFacing($v))
+ ])
+ );
+
+ foreach([
+ [Blocks::LAVA(), "lava"],
+ [Blocks::WATER(), "water"]
+ ] as [$block, $idSuffix]){
+ $reg->mapFlattenedId(FlattenedIdModel::create($block)
+ ->idComponents([...$commonProperties->liquidIdPrefixes, $idSuffix])
+ ->properties([$commonProperties->liquidData])
+ );
+ }
+ }
+
+ private static function registerFlattenedBoolMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ foreach([
+ [Blocks::BLAST_FURNACE(), "blast_furnace"],
+ [Blocks::FURNACE(), "furnace"],
+ [Blocks::SMOKER(), "smoker"]
+ ] as [$block, $idSuffix]){
+ $reg->mapFlattenedId(FlattenedIdModel::create($block)
+ ->idComponents([...$commonProperties->furnaceIdPrefixes, $idSuffix])
+ ->properties([$commonProperties->horizontalFacingCardinal])
+ );
+ }
+
+ foreach([
+ [Blocks::REDSTONE_LAMP(), "redstone_lamp"],
+ [Blocks::REDSTONE_ORE(), "redstone_ore"],
+ [Blocks::DEEPSLATE_REDSTONE_ORE(), "deepslate_redstone_ore"]
+ ] as [$block, $idSuffix]){
+ $reg->mapFlattenedId(FlattenedIdModel::create($block)->idComponents(["minecraft:", $commonProperties->litIdInfix, $idSuffix]));
+ }
+
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::DAYLIGHT_SENSOR())
+ ->idComponents([
+ "minecraft:daylight_detector",
+ new BoolFromStringProperty("inverted", "", "_inverted", fn(DaylightSensor $b) => $b->isInverted(), fn(DaylightSensor $b, bool $v) => $b->setInverted($v))
+ ])
+ ->properties([$commonProperties->analogRedstoneSignal])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::REDSTONE_REPEATER())
+ ->idComponents([
+ "minecraft:",
+ new BoolFromStringProperty("powered", "un", "", fn(RedstoneRepeater $b) => $b->isPowered(), fn(RedstoneRepeater $b, bool $v) => $b->setPowered($v)),
+ "powered_repeater"
+ ])
+ ->properties([
+ $commonProperties->horizontalFacingCardinal,
+ new IntProperty(StateNames::REPEATER_DELAY, 0, 3, fn(RedstoneRepeater $b) => $b->getDelay(), fn(RedstoneRepeater $b, int $v) => $b->setDelay($v), offset: 1),
+ ])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::REDSTONE_COMPARATOR())
+ ->idComponents([
+ "minecraft:",
+ //this property also appears in the state, so we ignore it in the ID
+ //this is baked here purely to keep minecraft happy
+ new BoolFromStringProperty("dummy_powered", "un", "", fn(RedstoneComparator $b) => $b->isPowered(), fn() => null),
+ "powered_comparator"
+ ])
+ ->properties([
+ $commonProperties->horizontalFacingCardinal,
+ new BoolProperty(StateNames::OUTPUT_LIT_BIT, fn(RedstoneComparator $b) => $b->isPowered(), fn(RedstoneComparator $b, bool $v) => $b->setPowered($v)),
+ new BoolProperty(StateNames::OUTPUT_SUBTRACT_BIT, fn(RedstoneComparator $b) => $b->isSubtractMode(), fn(RedstoneComparator $b, bool $v) => $b->setSubtractMode($v)),
+ ])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::REDSTONE_TORCH())
+ ->idComponents([
+ "minecraft:",
+ new BoolFromStringProperty("lit", "unlit_", "", fn(RedstoneTorch $b) => $b->isLit(), fn(RedstoneTorch $b, bool $v) => $b->setLit($v)),
+ "redstone_torch"
+ ])
+ ->properties([$commonProperties->torchFacing])
+ );
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::SPONGE())->idComponents([
+ "minecraft:",
+ new BoolFromStringProperty("wet", "", "wet_", fn(Sponge $b) => $b->isWet(), fn(Sponge $b, bool $v) => $b->setWet($v)),
+ "sponge"
+ ]));
+ $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::TNT())
+ ->idComponents([
+ "minecraft:",
+ new BoolFromStringProperty("underwater", "", "underwater_", fn(TNT $b) => $b->worksUnderwater(), fn(TNT $b, bool $v) => $b->setWorksUnderwater($v)),
+ "tnt"
+ ])
+ ->properties([
+ new BoolProperty(StateNames::EXPLODE_BIT, fn(TNT $b) => $b->isUnstable(), fn(TNT $b, bool $v) => $b->setUnstable($v)),
+ ])
+ );
+ }
+
+ private static function registerStoneLikeSlabMappings(BlockSerializerDeserializerRegistrar $reg) : void{
+ $reg->mapSlab(Blocks::ANDESITE_SLAB(), "andesite");
+ $reg->mapSlab(Blocks::BLACKSTONE_SLAB(), "blackstone");
+ $reg->mapSlab(Blocks::BRICK_SLAB(), "brick");
+ $reg->mapSlab(Blocks::COBBLED_DEEPSLATE_SLAB(), "cobbled_deepslate");
+ $reg->mapSlab(Blocks::COBBLESTONE_SLAB(), "cobblestone");
+ $reg->mapSlab(Blocks::CUT_RED_SANDSTONE_SLAB(), "cut_red_sandstone");
+ $reg->mapSlab(Blocks::CUT_SANDSTONE_SLAB(), "cut_sandstone");
+ $reg->mapSlab(Blocks::DARK_PRISMARINE_SLAB(), "dark_prismarine");
+ $reg->mapSlab(Blocks::DEEPSLATE_BRICK_SLAB(), "deepslate_brick");
+ $reg->mapSlab(Blocks::DEEPSLATE_TILE_SLAB(), "deepslate_tile");
+ $reg->mapSlab(Blocks::DIORITE_SLAB(), "diorite");
+ $reg->mapSlab(Blocks::END_STONE_BRICK_SLAB(), "end_stone_brick");
+ $reg->mapSlab(Blocks::FAKE_WOODEN_SLAB(), "petrified_oak");
+ $reg->mapSlab(Blocks::GRANITE_SLAB(), "granite");
+ $reg->mapSlab(Blocks::MOSSY_COBBLESTONE_SLAB(), "mossy_cobblestone");
+ $reg->mapSlab(Blocks::MOSSY_STONE_BRICK_SLAB(), "mossy_stone_brick");
+ $reg->mapSlab(Blocks::MUD_BRICK_SLAB(), "mud_brick");
+ $reg->mapSlab(Blocks::NETHER_BRICK_SLAB(), "nether_brick");
+ $reg->mapSlab(Blocks::POLISHED_ANDESITE_SLAB(), "polished_andesite");
+ $reg->mapSlab(Blocks::POLISHED_BLACKSTONE_BRICK_SLAB(), "polished_blackstone_brick");
+ $reg->mapSlab(Blocks::POLISHED_BLACKSTONE_SLAB(), "polished_blackstone");
+ $reg->mapSlab(Blocks::POLISHED_DEEPSLATE_SLAB(), "polished_deepslate");
+ $reg->mapSlab(Blocks::POLISHED_DIORITE_SLAB(), "polished_diorite");
+ $reg->mapSlab(Blocks::POLISHED_GRANITE_SLAB(), "polished_granite");
+ $reg->mapSlab(Blocks::POLISHED_TUFF_SLAB(), "polished_tuff");
+ $reg->mapSlab(Blocks::PRISMARINE_BRICKS_SLAB(), "prismarine_brick");
+ $reg->mapSlab(Blocks::PRISMARINE_SLAB(), "prismarine");
+ $reg->mapSlab(Blocks::PURPUR_SLAB(), "purpur");
+ $reg->mapSlab(Blocks::QUARTZ_SLAB(), "quartz");
+ $reg->mapSlab(Blocks::RED_NETHER_BRICK_SLAB(), "red_nether_brick");
+ $reg->mapSlab(Blocks::RED_SANDSTONE_SLAB(), "red_sandstone");
+ $reg->mapSlab(Blocks::RESIN_BRICK_SLAB(), "resin_brick");
+ $reg->mapSlab(Blocks::SANDSTONE_SLAB(), "sandstone");
+ $reg->mapSlab(Blocks::SMOOTH_QUARTZ_SLAB(), "smooth_quartz");
+ $reg->mapSlab(Blocks::SMOOTH_RED_SANDSTONE_SLAB(), "smooth_red_sandstone");
+ $reg->mapSlab(Blocks::SMOOTH_SANDSTONE_SLAB(), "smooth_sandstone");
+ $reg->mapSlab(Blocks::SMOOTH_STONE_SLAB(), "smooth_stone");
+ $reg->mapSlab(Blocks::STONE_BRICK_SLAB(), "stone_brick");
+ $reg->mapSlab(Blocks::STONE_SLAB(), "normal_stone");
+ $reg->mapSlab(Blocks::TUFF_BRICK_SLAB(), "tuff_brick");
+ $reg->mapSlab(Blocks::TUFF_SLAB(), "tuff");
+ }
+
+ private static function registerStoneLikeStairMappings(BlockSerializerDeserializerRegistrar $reg) : void{
+ $reg->mapStairs(Blocks::ANDESITE_STAIRS(), Ids::ANDESITE_STAIRS);
+ $reg->mapStairs(Blocks::BLACKSTONE_STAIRS(), Ids::BLACKSTONE_STAIRS);
+ $reg->mapStairs(Blocks::BRICK_STAIRS(), Ids::BRICK_STAIRS);
+ $reg->mapStairs(Blocks::COBBLED_DEEPSLATE_STAIRS(), Ids::COBBLED_DEEPSLATE_STAIRS);
+ $reg->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
+ $reg->mapStairs(Blocks::DARK_PRISMARINE_STAIRS(), Ids::DARK_PRISMARINE_STAIRS);
+ $reg->mapStairs(Blocks::DEEPSLATE_BRICK_STAIRS(), Ids::DEEPSLATE_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::DEEPSLATE_TILE_STAIRS(), Ids::DEEPSLATE_TILE_STAIRS);
+ $reg->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS);
+ $reg->mapStairs(Blocks::END_STONE_BRICK_STAIRS(), Ids::END_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS);
+ $reg->mapStairs(Blocks::MOSSY_COBBLESTONE_STAIRS(), Ids::MOSSY_COBBLESTONE_STAIRS);
+ $reg->mapStairs(Blocks::MOSSY_STONE_BRICK_STAIRS(), Ids::MOSSY_STONE_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::MUD_BRICK_STAIRS(), Ids::MUD_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::NETHER_BRICK_STAIRS(), Ids::NETHER_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_BLACKSTONE_BRICK_STAIRS(), Ids::POLISHED_BLACKSTONE_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_BLACKSTONE_STAIRS(), Ids::POLISHED_BLACKSTONE_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_DEEPSLATE_STAIRS(), Ids::POLISHED_DEEPSLATE_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS);
+ $reg->mapStairs(Blocks::POLISHED_TUFF_STAIRS(), Ids::POLISHED_TUFF_STAIRS);
+ $reg->mapStairs(Blocks::PRISMARINE_BRICKS_STAIRS(), Ids::PRISMARINE_BRICKS_STAIRS);
+ $reg->mapStairs(Blocks::PRISMARINE_STAIRS(), Ids::PRISMARINE_STAIRS);
+ $reg->mapStairs(Blocks::PURPUR_STAIRS(), Ids::PURPUR_STAIRS);
+ $reg->mapStairs(Blocks::QUARTZ_STAIRS(), Ids::QUARTZ_STAIRS);
+ $reg->mapStairs(Blocks::RED_NETHER_BRICK_STAIRS(), Ids::RED_NETHER_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::RED_SANDSTONE_STAIRS(), Ids::RED_SANDSTONE_STAIRS);
+ $reg->mapStairs(Blocks::RESIN_BRICK_STAIRS(), Ids::RESIN_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::SANDSTONE_STAIRS(), Ids::SANDSTONE_STAIRS);
+ $reg->mapStairs(Blocks::SMOOTH_QUARTZ_STAIRS(), Ids::SMOOTH_QUARTZ_STAIRS);
+ $reg->mapStairs(Blocks::SMOOTH_RED_SANDSTONE_STAIRS(), Ids::SMOOTH_RED_SANDSTONE_STAIRS);
+ $reg->mapStairs(Blocks::SMOOTH_SANDSTONE_STAIRS(), Ids::SMOOTH_SANDSTONE_STAIRS);
+ $reg->mapStairs(Blocks::STONE_BRICK_STAIRS(), Ids::STONE_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::STONE_STAIRS(), Ids::NORMAL_STONE_STAIRS);
+ $reg->mapStairs(Blocks::TUFF_BRICK_STAIRS(), Ids::TUFF_BRICK_STAIRS);
+ $reg->mapStairs(Blocks::TUFF_STAIRS(), Ids::TUFF_STAIRS);
+ }
+
+ private static function registerStoneLikeWallMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ foreach([
+ Ids::ANDESITE_WALL => Blocks::ANDESITE_WALL(),
+ Ids::BLACKSTONE_WALL => Blocks::BLACKSTONE_WALL(),
+ Ids::BRICK_WALL => Blocks::BRICK_WALL(),
+ Ids::COBBLED_DEEPSLATE_WALL => Blocks::COBBLED_DEEPSLATE_WALL(),
+ Ids::COBBLESTONE_WALL => Blocks::COBBLESTONE_WALL(),
+ Ids::DEEPSLATE_BRICK_WALL => Blocks::DEEPSLATE_BRICK_WALL(),
+ Ids::DEEPSLATE_TILE_WALL => Blocks::DEEPSLATE_TILE_WALL(),
+ Ids::DIORITE_WALL => Blocks::DIORITE_WALL(),
+ Ids::END_STONE_BRICK_WALL => Blocks::END_STONE_BRICK_WALL(),
+ Ids::GRANITE_WALL => Blocks::GRANITE_WALL(),
+ Ids::MOSSY_COBBLESTONE_WALL => Blocks::MOSSY_COBBLESTONE_WALL(),
+ Ids::MOSSY_STONE_BRICK_WALL => Blocks::MOSSY_STONE_BRICK_WALL(),
+ Ids::MUD_BRICK_WALL => Blocks::MUD_BRICK_WALL(),
+ Ids::NETHER_BRICK_WALL => Blocks::NETHER_BRICK_WALL(),
+ Ids::POLISHED_BLACKSTONE_BRICK_WALL => Blocks::POLISHED_BLACKSTONE_BRICK_WALL(),
+ Ids::POLISHED_BLACKSTONE_WALL => Blocks::POLISHED_BLACKSTONE_WALL(),
+ Ids::POLISHED_DEEPSLATE_WALL => Blocks::POLISHED_DEEPSLATE_WALL(),
+ Ids::POLISHED_TUFF_WALL => Blocks::POLISHED_TUFF_WALL(),
+ Ids::PRISMARINE_WALL => Blocks::PRISMARINE_WALL(),
+ Ids::RED_NETHER_BRICK_WALL => Blocks::RED_NETHER_BRICK_WALL(),
+ Ids::RED_SANDSTONE_WALL => Blocks::RED_SANDSTONE_WALL(),
+ Ids::RESIN_BRICK_WALL => Blocks::RESIN_BRICK_WALL(),
+ Ids::SANDSTONE_WALL => Blocks::SANDSTONE_WALL(),
+ Ids::STONE_BRICK_WALL => Blocks::STONE_BRICK_WALL(),
+ Ids::TUFF_BRICK_WALL => Blocks::TUFF_BRICK_WALL(),
+ Ids::TUFF_WALL => Blocks::TUFF_WALL()
+ ] as $id => $block){
+ $reg->mapModel(Model::create($block, $id)->properties($commonProperties->wallProperties));
+ }
+ }
+
+ private static function registerWoodMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ //buttons
+ foreach([
+ [Blocks::ACACIA_BUTTON(), Ids::ACACIA_BUTTON],
+ [Blocks::BIRCH_BUTTON(), Ids::BIRCH_BUTTON],
+ [Blocks::CHERRY_BUTTON(), Ids::CHERRY_BUTTON],
+ [Blocks::CRIMSON_BUTTON(), Ids::CRIMSON_BUTTON],
+ [Blocks::DARK_OAK_BUTTON(), Ids::DARK_OAK_BUTTON],
+ [Blocks::JUNGLE_BUTTON(), Ids::JUNGLE_BUTTON],
+ [Blocks::MANGROVE_BUTTON(), Ids::MANGROVE_BUTTON],
+ [Blocks::OAK_BUTTON(), Ids::WOODEN_BUTTON],
+ [Blocks::PALE_OAK_BUTTON(), Ids::PALE_OAK_BUTTON],
+ [Blocks::SPRUCE_BUTTON(), Ids::SPRUCE_BUTTON],
+ [Blocks::WARPED_BUTTON(), Ids::WARPED_BUTTON]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties($commonProperties->buttonProperties));
+ }
+
+ //doors
+ foreach([
+ [Blocks::ACACIA_DOOR(), Ids::ACACIA_DOOR],
+ [Blocks::BIRCH_DOOR(), Ids::BIRCH_DOOR],
+ [Blocks::CHERRY_DOOR(), Ids::CHERRY_DOOR],
+ [Blocks::CRIMSON_DOOR(), Ids::CRIMSON_DOOR],
+ [Blocks::DARK_OAK_DOOR(), Ids::DARK_OAK_DOOR],
+ [Blocks::JUNGLE_DOOR(), Ids::JUNGLE_DOOR],
+ [Blocks::MANGROVE_DOOR(), Ids::MANGROVE_DOOR],
+ [Blocks::OAK_DOOR(), Ids::WOODEN_DOOR],
+ [Blocks::PALE_OAK_DOOR(), Ids::PALE_OAK_DOOR],
+ [Blocks::SPRUCE_DOOR(), Ids::SPRUCE_DOOR],
+ [Blocks::WARPED_DOOR(), Ids::WARPED_DOOR]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties($commonProperties->doorProperties));
+ }
+
+ //fences
+ foreach([
+ [Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE],
+ [Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE],
+ [Blocks::CHERRY_FENCE(), Ids::CHERRY_FENCE],
+ [Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE],
+ [Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE],
+ [Blocks::MANGROVE_FENCE(), Ids::MANGROVE_FENCE],
+ [Blocks::OAK_FENCE(), Ids::OAK_FENCE],
+ [Blocks::PALE_OAK_FENCE(), Ids::PALE_OAK_FENCE],
+ [Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE],
+ [Blocks::CRIMSON_FENCE(), Ids::CRIMSON_FENCE],
+ [Blocks::WARPED_FENCE(), Ids::WARPED_FENCE]
+ ] as [$block, $id]){
+ $reg->mapSimple($block, $id);
+ }
+
+ foreach([
+ [Blocks::ACACIA_FENCE_GATE(), Ids::ACACIA_FENCE_GATE],
+ [Blocks::BIRCH_FENCE_GATE(), Ids::BIRCH_FENCE_GATE],
+ [Blocks::CHERRY_FENCE_GATE(), Ids::CHERRY_FENCE_GATE],
+ [Blocks::DARK_OAK_FENCE_GATE(), Ids::DARK_OAK_FENCE_GATE],
+ [Blocks::JUNGLE_FENCE_GATE(), Ids::JUNGLE_FENCE_GATE],
+ [Blocks::MANGROVE_FENCE_GATE(), Ids::MANGROVE_FENCE_GATE],
+ [Blocks::OAK_FENCE_GATE(), Ids::FENCE_GATE],
+ [Blocks::PALE_OAK_FENCE_GATE(), Ids::PALE_OAK_FENCE_GATE],
+ [Blocks::SPRUCE_FENCE_GATE(), Ids::SPRUCE_FENCE_GATE],
+ [Blocks::CRIMSON_FENCE_GATE(), Ids::CRIMSON_FENCE_GATE],
+ [Blocks::WARPED_FENCE_GATE(), Ids::WARPED_FENCE_GATE]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties($commonProperties->fenceGateProperties));
+ }
+
+ foreach([
+ [Blocks::ACACIA_SIGN(), Ids::ACACIA_STANDING_SIGN],
+ [Blocks::BIRCH_SIGN(), Ids::BIRCH_STANDING_SIGN],
+ [Blocks::CHERRY_SIGN(), Ids::CHERRY_STANDING_SIGN],
+ [Blocks::DARK_OAK_SIGN(), Ids::DARKOAK_STANDING_SIGN],
+ [Blocks::JUNGLE_SIGN(), Ids::JUNGLE_STANDING_SIGN],
+ [Blocks::MANGROVE_SIGN(), Ids::MANGROVE_STANDING_SIGN],
+ [Blocks::OAK_SIGN(), Ids::STANDING_SIGN],
+ [Blocks::PALE_OAK_SIGN(), Ids::PALE_OAK_STANDING_SIGN],
+ [Blocks::SPRUCE_SIGN(), Ids::SPRUCE_STANDING_SIGN],
+ [Blocks::CRIMSON_SIGN(), Ids::CRIMSON_STANDING_SIGN],
+ [Blocks::WARPED_SIGN(), Ids::WARPED_STANDING_SIGN]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->floorSignLikeRotation]));
+ }
+
+ //logs
+ foreach([
+ [Blocks::ACACIA_LOG(), "acacia_log"],
+ [Blocks::BIRCH_LOG(), "birch_log"],
+ [Blocks::CHERRY_LOG(), "cherry_log"],
+ [Blocks::DARK_OAK_LOG(), "dark_oak_log"],
+ [Blocks::JUNGLE_LOG(), "jungle_log"],
+ [Blocks::MANGROVE_LOG(), "mangrove_log"],
+ [Blocks::OAK_LOG(), "oak_log"],
+ [Blocks::PALE_OAK_LOG(), "pale_oak_log"],
+ [Blocks::SPRUCE_LOG(), "spruce_log"],
+ [Blocks::CRIMSON_STEM(), "crimson_stem"],
+ [Blocks::WARPED_STEM(), "warped_stem"],
+
+ //all-sided logs
+ [Blocks::ACACIA_WOOD(), "acacia_wood"],
+ [Blocks::BIRCH_WOOD(), "birch_wood"],
+ [Blocks::CHERRY_WOOD(), "cherry_wood"],
+ [Blocks::DARK_OAK_WOOD(), "dark_oak_wood"],
+ [Blocks::JUNGLE_WOOD(), "jungle_wood"],
+ [Blocks::MANGROVE_WOOD(), "mangrove_wood"],
+ [Blocks::OAK_WOOD(), "oak_wood"],
+ [Blocks::PALE_OAK_WOOD(), "pale_oak_wood"],
+ [Blocks::SPRUCE_WOOD(), "spruce_wood"],
+ [Blocks::CRIMSON_HYPHAE(), "crimson_hyphae"],
+ [Blocks::WARPED_HYPHAE(), "warped_hyphae"]
+ ] as [$block, $idSuffix]){
+ $reg->mapFlattenedId(FlattenedIdModel::create($block)
+ ->idComponents([...$commonProperties->woodIdPrefixes, $idSuffix])
+ ->properties([$commonProperties->pillarAxis])
+ );
+ }
+
+ //planks
+ foreach([
+ [Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS],
+ [Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS],
+ [Blocks::CHERRY_PLANKS(), Ids::CHERRY_PLANKS],
+ [Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS],
+ [Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS],
+ [Blocks::MANGROVE_PLANKS(), Ids::MANGROVE_PLANKS],
+ [Blocks::OAK_PLANKS(), Ids::OAK_PLANKS],
+ [Blocks::PALE_OAK_PLANKS(), Ids::PALE_OAK_PLANKS],
+ [Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS],
+ [Blocks::CRIMSON_PLANKS(), Ids::CRIMSON_PLANKS],
+ [Blocks::WARPED_PLANKS(), Ids::WARPED_PLANKS]
+ ] as [$block, $id]){
+ $reg->mapSimple($block, $id);
+ }
+
+ //pressure plates
+ foreach([
+ [Blocks::ACACIA_PRESSURE_PLATE(), Ids::ACACIA_PRESSURE_PLATE],
+ [Blocks::BIRCH_PRESSURE_PLATE(), Ids::BIRCH_PRESSURE_PLATE],
+ [Blocks::CHERRY_PRESSURE_PLATE(), Ids::CHERRY_PRESSURE_PLATE],
+ [Blocks::DARK_OAK_PRESSURE_PLATE(), Ids::DARK_OAK_PRESSURE_PLATE],
+ [Blocks::JUNGLE_PRESSURE_PLATE(), Ids::JUNGLE_PRESSURE_PLATE],
+ [Blocks::MANGROVE_PRESSURE_PLATE(), Ids::MANGROVE_PRESSURE_PLATE],
+ [Blocks::OAK_PRESSURE_PLATE(), Ids::WOODEN_PRESSURE_PLATE],
+ [Blocks::PALE_OAK_PRESSURE_PLATE(), Ids::PALE_OAK_PRESSURE_PLATE],
+ [Blocks::SPRUCE_PRESSURE_PLATE(), Ids::SPRUCE_PRESSURE_PLATE],
+ [Blocks::CRIMSON_PRESSURE_PLATE(), Ids::CRIMSON_PRESSURE_PLATE],
+ [Blocks::WARPED_PRESSURE_PLATE(), Ids::WARPED_PRESSURE_PLATE]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties($commonProperties->simplePressurePlateProperties));
+ }
+
+ //slabs
+ foreach([
+ [Blocks::ACACIA_SLAB(), "acacia"],
+ [Blocks::BIRCH_SLAB(), "birch"],
+ [Blocks::CHERRY_SLAB(), "cherry"],
+ [Blocks::DARK_OAK_SLAB(), "dark_oak"],
+ [Blocks::JUNGLE_SLAB(), "jungle"],
+ [Blocks::MANGROVE_SLAB(), "mangrove"],
+ [Blocks::OAK_SLAB(), "oak"],
+ [Blocks::PALE_OAK_SLAB(), "pale_oak"],
+ [Blocks::SPRUCE_SLAB(), "spruce"],
+ [Blocks::CRIMSON_SLAB(), "crimson"],
+ [Blocks::WARPED_SLAB(), "warped"]
+ ] as [$block, $type]){
+ $reg->mapSlab($block, $type);
+ }
+
+ //stairs
+ foreach([
+ [Blocks::ACACIA_STAIRS(), Ids::ACACIA_STAIRS],
+ [Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS],
+ [Blocks::CHERRY_STAIRS(), Ids::CHERRY_STAIRS],
+ [Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS],
+ [Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS],
+ [Blocks::MANGROVE_STAIRS(), Ids::MANGROVE_STAIRS],
+ [Blocks::OAK_STAIRS(), Ids::OAK_STAIRS],
+ [Blocks::PALE_OAK_STAIRS(), Ids::PALE_OAK_STAIRS],
+ [Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS],
+ [Blocks::CRIMSON_STAIRS(), Ids::CRIMSON_STAIRS],
+ [Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS]
+ ] as [$block, $id]){
+ $reg->mapStairs($block, $id);
+ }
+
+ //trapdoors
+ foreach([
+ [Blocks::ACACIA_TRAPDOOR(), Ids::ACACIA_TRAPDOOR],
+ [Blocks::BIRCH_TRAPDOOR(), Ids::BIRCH_TRAPDOOR],
+ [Blocks::CHERRY_TRAPDOOR(), Ids::CHERRY_TRAPDOOR],
+ [Blocks::DARK_OAK_TRAPDOOR(), Ids::DARK_OAK_TRAPDOOR],
+ [Blocks::JUNGLE_TRAPDOOR(), Ids::JUNGLE_TRAPDOOR],
+ [Blocks::MANGROVE_TRAPDOOR(), Ids::MANGROVE_TRAPDOOR],
+ [Blocks::OAK_TRAPDOOR(), Ids::TRAPDOOR],
+ [Blocks::PALE_OAK_TRAPDOOR(), Ids::PALE_OAK_TRAPDOOR],
+ [Blocks::SPRUCE_TRAPDOOR(), Ids::SPRUCE_TRAPDOOR],
+ [Blocks::CRIMSON_TRAPDOOR(), Ids::CRIMSON_TRAPDOOR],
+ [Blocks::WARPED_TRAPDOOR(), Ids::WARPED_TRAPDOOR]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties($commonProperties->trapdoorProperties));
+ }
+
+ //wall signs
+ foreach([
+ [Blocks::ACACIA_WALL_SIGN(), Ids::ACACIA_WALL_SIGN],
+ [Blocks::BIRCH_WALL_SIGN(), Ids::BIRCH_WALL_SIGN],
+ [Blocks::CHERRY_WALL_SIGN(), Ids::CHERRY_WALL_SIGN],
+ [Blocks::DARK_OAK_WALL_SIGN(), Ids::DARKOAK_WALL_SIGN],
+ [Blocks::JUNGLE_WALL_SIGN(), Ids::JUNGLE_WALL_SIGN],
+ [Blocks::MANGROVE_WALL_SIGN(), Ids::MANGROVE_WALL_SIGN],
+ [Blocks::OAK_WALL_SIGN(), Ids::WALL_SIGN],
+ [Blocks::PALE_OAK_WALL_SIGN(), Ids::PALE_OAK_WALL_SIGN],
+ [Blocks::SPRUCE_WALL_SIGN(), Ids::SPRUCE_WALL_SIGN],
+ [Blocks::CRIMSON_WALL_SIGN(), Ids::CRIMSON_WALL_SIGN],
+ [Blocks::WARPED_WALL_SIGN(), Ids::WARPED_WALL_SIGN]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->horizontalFacingClassic]));
+ }
+ }
+
+ private static function registerTorchMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ foreach([
+ [Blocks::BLUE_TORCH(), Ids::COLORED_TORCH_BLUE],
+ [Blocks::GREEN_TORCH(), Ids::COLORED_TORCH_GREEN],
+ [Blocks::PURPLE_TORCH(), Ids::COLORED_TORCH_PURPLE],
+ [Blocks::RED_TORCH(), Ids::COLORED_TORCH_RED],
+ [Blocks::SOUL_TORCH(), Ids::SOUL_TORCH],
+ [Blocks::TORCH(), Ids::TORCH],
+ [Blocks::UNDERWATER_TORCH(), Ids::UNDERWATER_TORCH]
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->torchFacing]));
+ }
+ }
+
+ private static function registerChemistryMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ foreach([
+ [Blocks::COMPOUND_CREATOR(), Ids::COMPOUND_CREATOR],
+ [Blocks::ELEMENT_CONSTRUCTOR(), Ids::ELEMENT_CONSTRUCTOR],
+ [Blocks::LAB_TABLE(), Ids::LAB_TABLE],
+ [Blocks::MATERIAL_REDUCER(), Ids::MATERIAL_REDUCER],
+ ] as [$block, $id]){
+ $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->horizontalFacingSWNEInverted]));
+ }
+ }
+
+ private static function register1to1CustomMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{
+ //TODO: some of these have repeated accessor refs, we might be able to deduplicate them
+ //A
+ $reg->mapModel(Model::create(Blocks::ACTIVATOR_RAIL(), Ids::ACTIVATOR_RAIL)->properties([
+ new BoolProperty(StateNames::RAIL_DATA_BIT, fn(ActivatorRail $b) => $b->isPowered(), fn(ActivatorRail $b, bool $v) => $b->setPowered($v)),
+ new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(ActivatorRail $b) => $b->getShape(), fn(ActivatorRail $b, int $v) => $b->setShape($v))
+ ]));
+
+ //B
+ $reg->mapModel(Model::create(Blocks::BAMBOO(), Ids::BAMBOO)->properties([
+ new ValueFromStringProperty(StateNames::BAMBOO_LEAF_SIZE, ValueMappings::getInstance()->bambooLeafSize, fn(Bamboo $b) => $b->getLeafSize(), fn(Bamboo $b, int $v) => $b->setLeafSize($v)),
+ new BoolProperty(StateNames::AGE_BIT, fn(Bamboo $b) => $b->isReady(), fn(Bamboo $b, bool $v) => $b->setReady($v)),
+ new BoolFromStringProperty(StateNames::BAMBOO_STALK_THICKNESS, StringValues::BAMBOO_STALK_THICKNESS_THIN, StringValues::BAMBOO_STALK_THICKNESS_THICK, fn(Bamboo $b) => $b->isThick(), fn(Bamboo $b, bool $v) => $b->setThick($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::BAMBOO_SAPLING(), Ids::BAMBOO_SAPLING)->properties([
+ new BoolProperty(StateNames::AGE_BIT, fn(BambooSapling $b) => $b->isReady(), fn(BambooSapling $b, bool $v) => $b->setReady($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::BANNER(), Ids::STANDING_BANNER)->properties([$commonProperties->floorSignLikeRotation]));
+ $reg->mapModel(Model::create(Blocks::BARREL(), Ids::BARREL)->properties([
+ $commonProperties->anyFacingClassic,
+ new BoolProperty(StateNames::OPEN_BIT, fn(Barrel $b) => $b->isOpen(), fn(Barrel $b, bool $v) => $b->setOpen($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::BASALT(), Ids::BASALT)->properties([$commonProperties->pillarAxis]));
+ $reg->mapModel(Model::create(Blocks::BED(), Ids::BED)->properties([
+ new BoolProperty(StateNames::HEAD_PIECE_BIT, fn(Bed $b) => $b->isHeadPart(), fn(Bed $b, bool $v) => $b->setHead($v)),
+ new BoolProperty(StateNames::OCCUPIED_BIT, fn(Bed $b) => $b->isOccupied(), fn(Bed $b, bool $v) => $b->setOccupied($v)),
+ $commonProperties->horizontalFacingSWNE
+ ]));
+ $reg->mapModel(Model::create(Blocks::BEDROCK(), Ids::BEDROCK)->properties([
+ new BoolProperty(StateNames::INFINIBURN_BIT, fn(Bedrock $b) => $b->burnsForever(), fn(Bedrock $b, bool $v) => $b->setBurnsForever($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::BELL(), Ids::BELL)->properties([
+ BoolProperty::unused(StateNames::TOGGLE_BIT, false),
+ new ValueFromStringProperty(StateNames::ATTACHMENT, ValueMappings::getInstance()->bellAttachmentType, fn(Bell $b) => $b->getAttachmentType(), fn(Bell $b, BellAttachmentType $v) => $b->setAttachmentType($v)),
+ $commonProperties->horizontalFacingSWNE
+ ]));
+ $reg->mapModel(Model::create(Blocks::BONE_BLOCK(), Ids::BONE_BLOCK)->properties([
+ IntProperty::unused(StateNames::DEPRECATED, 0),
+ $commonProperties->pillarAxis
+ ]));
+
+ $reg->mapModel(Model::create(Blocks::BREWING_STAND(), Ids::BREWING_STAND)->properties(array_map(fn(BrewingStandSlot $slot) => new BoolProperty(match ($slot) {
+ BrewingStandSlot::EAST => StateNames::BREWING_STAND_SLOT_A_BIT,
+ BrewingStandSlot::SOUTHWEST => StateNames::BREWING_STAND_SLOT_B_BIT,
+ BrewingStandSlot::NORTHWEST => StateNames::BREWING_STAND_SLOT_C_BIT
+ }, fn(BrewingStand $b) => $b->hasSlot($slot), fn(BrewingStand $b, bool $v) => $b->setSlot($slot, $v)), BrewingStandSlot::cases())));
+
+ //C
+ $reg->mapModel(Model::create(Blocks::CACTUS(), Ids::CACTUS)->properties([
+ new IntProperty(StateNames::AGE, 0, 15, fn(Cactus $b) => $b->getAge(), fn(Cactus $b, int $v) => $b->setAge($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::CAKE(), Ids::CAKE)->properties([
+ new IntProperty(StateNames::BITE_COUNTER, 0, 6, fn(Cake $b) => $b->getBites(), fn(Cake $b, int $v) => $b->setBites($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::CAMPFIRE(), Ids::CAMPFIRE)->properties($commonProperties->campfireProperties));
+ $reg->mapModel(Model::create(Blocks::CARVED_PUMPKIN(), Ids::CARVED_PUMPKIN)->properties([
+ $commonProperties->horizontalFacingCardinal
+ ]));
+ $reg->mapModel(Model::create(Blocks::CHAIN(), Ids::CHAIN)->properties([$commonProperties->pillarAxis]));
+ $reg->mapModel(Model::create(Blocks::CHISELED_BOOKSHELF(), Ids::CHISELED_BOOKSHELF)->properties([
+ $commonProperties->horizontalFacingSWNE,
+ new OptionSetFromIntProperty(
+ StateNames::BOOKS_STORED,
+ EnumFromRawStateMap::int(ChiseledBookshelfSlot::class, fn(ChiseledBookshelfSlot $case) => match($case){
+ //these are (currently) the same as the internal values, but it's best not to rely on those in case Mojang mess with the flags
+ ChiseledBookshelfSlot::TOP_LEFT => 1 << 0,
+ ChiseledBookshelfSlot::TOP_MIDDLE => 1 << 1,
+ ChiseledBookshelfSlot::TOP_RIGHT => 1 << 2,
+ ChiseledBookshelfSlot::BOTTOM_LEFT => 1 << 3,
+ ChiseledBookshelfSlot::BOTTOM_MIDDLE => 1 << 4,
+ ChiseledBookshelfSlot::BOTTOM_RIGHT => 1 << 5
+ }),
+ fn(ChiseledBookshelf $b) => $b->getSlots(),
+ fn(ChiseledBookshelf $b, array $v) => $b->setSlots($v)
+ )
+ ]));
+ $reg->mapModel(Model::create(Blocks::CHISELED_QUARTZ(), Ids::CHISELED_QUARTZ_BLOCK)->properties([$commonProperties->pillarAxis]));
+ $reg->mapModel(Model::create(Blocks::CHEST(), Ids::CHEST)->properties([$commonProperties->horizontalFacingCardinal]));
+ $reg->mapModel(Model::create(Blocks::CHORUS_FLOWER(), Ids::CHORUS_FLOWER)->properties([
+ new IntProperty(StateNames::AGE, ChorusFlower::MIN_AGE, ChorusFlower::MAX_AGE, fn(ChorusFlower $b) => $b->getAge(), fn(ChorusFlower $b, int $v) => $b->setAge($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::COCOA_POD(), Ids::COCOA)->properties([
+ new IntProperty(StateNames::AGE, 0, 2, fn(CocoaBlock $b) => $b->getAge(), fn(CocoaBlock $b, int $v) => $b->setAge($v)),
+ $commonProperties->horizontalFacingSWNEInverted
+ ]));
+
+ //D
+ $reg->mapModel(Model::create(Blocks::DEEPSLATE(), Ids::DEEPSLATE)->properties([$commonProperties->pillarAxis]));
+ $reg->mapModel(Model::create(Blocks::DETECTOR_RAIL(), Ids::DETECTOR_RAIL)->properties([
+ new BoolProperty(StateNames::RAIL_DATA_BIT, fn(DetectorRail $b) => $b->isActivated(), fn(DetectorRail $b, bool $v) => $b->setActivated($v)),
+ new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, int $v) => $b->setShape($v)) //TODO: shared with ActivatorRail
+ ]));
+
+ //E
+ $reg->mapModel(Model::create(Blocks::ENDER_CHEST(), Ids::ENDER_CHEST)->properties([$commonProperties->horizontalFacingCardinal]));
+ $reg->mapModel(Model::create(Blocks::END_PORTAL_FRAME(), Ids::END_PORTAL_FRAME)->properties([
+ new BoolProperty(StateNames::END_PORTAL_EYE_BIT, fn(EndPortalFrame $b) => $b->hasEye(), fn(EndPortalFrame $b, bool $v) => $b->setEye($v)),
+ $commonProperties->horizontalFacingCardinal
+ ]));
+ $reg->mapModel(Model::create(Blocks::END_ROD(), Ids::END_ROD)->properties([
+ new ValueFromIntProperty(StateNames::FACING_DIRECTION, ValueMappings::getInstance()->facingEndRod, fn(EndRod $b) => $b->getFacing(), fn(EndRod $b, int $v) => $b->setFacing($v)),
+ ]));
+
+ //F
+ $reg->mapModel(Model::create(Blocks::FARMLAND(), Ids::FARMLAND)->properties([
+ new IntProperty(StateNames::MOISTURIZED_AMOUNT, 0, 7, fn(Farmland $b) => $b->getWetness(), fn(Farmland $b, int $v) => $b->setWetness($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::FIRE(), Ids::FIRE)->properties([
+ new IntProperty(StateNames::AGE, 0, 15, fn(Fire $b) => $b->getAge(), fn(Fire $b, int $v) => $b->setAge($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::FLOWER_POT(), Ids::FLOWER_POT)->properties([
+ BoolProperty::unused(StateNames::UPDATE_BIT, false)
+ ]));
+ $reg->mapModel(Model::create(Blocks::FROSTED_ICE(), Ids::FROSTED_ICE)->properties([
+ new IntProperty(StateNames::AGE, 0, 3, fn(FrostedIce $b) => $b->getAge(), fn(FrostedIce $b, int $v) => $b->setAge($v))
+ ]));
+
+ //G
+ $reg->mapModel(Model::create(Blocks::GLOWING_ITEM_FRAME(), Ids::GLOW_FRAME)->properties($commonProperties->itemFrameProperties));
+
+ //H
+ $reg->mapModel(Model::create(Blocks::HAY_BALE(), Ids::HAY_BLOCK)->properties([
+ IntProperty::unused(StateNames::DEPRECATED, 0),
+ $commonProperties->pillarAxis
+ ]));
+ $reg->mapModel(Model::create(Blocks::HOPPER(), Ids::HOPPER)->properties([
+ //kinda weird this doesn't use powered_bit?
+ new BoolProperty(StateNames::TOGGLE_BIT, fn(PoweredByRedstone $b) => $b->isPowered(), fn(PoweredByRedstone $b, bool $v) => $b->setPowered($v)),
+ new ValueFromIntProperty(StateNames::FACING_DIRECTION, ValueMappings::getInstance()->facingExceptUp, fn(Hopper $b) => $b->getFacing(), fn(Hopper $b, int $v) => $b->setFacing($v)),
+ ]));
+
+ //I
+ $reg->mapModel(Model::create(Blocks::IRON_DOOR(), Ids::IRON_DOOR)->properties($commonProperties->doorProperties));
+ $reg->mapModel(Model::create(Blocks::IRON_TRAPDOOR(), Ids::IRON_TRAPDOOR)->properties($commonProperties->trapdoorProperties));
+ $reg->mapModel(Model::create(Blocks::ITEM_FRAME(), Ids::FRAME)->properties($commonProperties->itemFrameProperties));
+
+ //L
+ $reg->mapModel(Model::create(Blocks::LADDER(), Ids::LADDER)->properties([$commonProperties->horizontalFacingClassic]));
+ $reg->mapModel(Model::create(Blocks::LANTERN(), Ids::LANTERN)->properties([
+ new BoolProperty(StateNames::HANGING, fn(Lantern $b) => $b->isHanging(), fn(Lantern $b, bool $v) => $b->setHanging($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::LECTERN(), Ids::LECTERN)->properties([
+ new BoolProperty(StateNames::POWERED_BIT, fn(Lectern $b) => $b->isProducingSignal(), fn(Lectern $b, bool $v) => $b->setProducingSignal($v)),
+ $commonProperties->horizontalFacingCardinal,
+ ]));
+ $reg->mapModel(Model::create(Blocks::LEVER(), Ids::LEVER)->properties([
+ new ValueFromStringProperty(StateNames::LEVER_DIRECTION, ValueMappings::getInstance()->leverFacing, fn(Lever $b) => $b->getFacing(), fn(Lever $b, LeverFacing $v) => $b->setFacing($v)),
+ new BoolProperty(StateNames::OPEN_BIT, fn(Lever $b) => $b->isActivated(), fn(Lever $b, bool $v) => $b->setActivated($v)),
+ ]));
+ $reg->mapModel(Model::create(Blocks::LIGHTNING_ROD(), Ids::LIGHTNING_ROD)->properties([$commonProperties->anyFacingClassic]));
+ $reg->mapModel(Model::create(Blocks::LIT_PUMPKIN(), Ids::LIT_PUMPKIN)->properties([$commonProperties->horizontalFacingCardinal]));
+ $reg->mapModel(Model::create(Blocks::LOOM(), Ids::LOOM)->properties([$commonProperties->horizontalFacingSWNE]));
+
+ //M
+ $reg->mapModel(Model::create(Blocks::MUDDY_MANGROVE_ROOTS(), Ids::MUDDY_MANGROVE_ROOTS)->properties([$commonProperties->pillarAxis]));
+ $reg->mapModel(Model::create(Blocks::NETHER_WART(), Ids::NETHER_WART)->properties([
+ new IntProperty(StateNames::AGE, 0, 3, fn(NetherWartPlant $b) => $b->getAge(), fn(NetherWartPlant $b, int $v) => $b->setAge($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::NETHER_PORTAL(), Ids::PORTAL)->properties([
+ new ValueFromStringProperty(StateNames::PORTAL_AXIS, ValueMappings::getInstance()->portalAxis, fn(NetherPortal $b) => $b->getAxis(), fn(NetherPortal $b, int $v) => $b->setAxis($v))
+ ]));
+
+ //P
+ $reg->mapModel(Model::create(Blocks::PINK_PETALS(), Ids::PINK_PETALS)->properties([
+ //Pink petals only uses 0-3, but GROWTH state can go up to 7
+ new IntProperty(StateNames::GROWTH, 0, 7, fn(PinkPetals $b) => $b->getCount(), fn(PinkPetals $b, int $v) => $b->setCount(min($v, PinkPetals::MAX_COUNT)), offset: 1),
+ $commonProperties->horizontalFacingCardinal
+ ]));
+ $reg->mapModel(Model::create(Blocks::POWERED_RAIL(), Ids::GOLDEN_RAIL)->properties([
+ new BoolProperty(StateNames::RAIL_DATA_BIT, fn(PoweredRail $b) => $b->isPowered(), fn(PoweredRail $b, bool $v) => $b->setPowered($v)), //TODO: shared with ActivatorRail
+ new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, int $v) => $b->setShape($v)) //TODO: shared with ActivatorRail
+ ]));
+ $reg->mapModel(Model::create(Blocks::PITCHER_PLANT(), Ids::PITCHER_PLANT)->properties([
+ new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(DoublePlant $b) => $b->isTop(), fn(DoublePlant $b, bool $v) => $b->setTop($v)), //TODO: don't we have helpers for this?
+ ]));
+ $reg->mapModel(Model::create(Blocks::POLISHED_BASALT(), Ids::POLISHED_BASALT)->properties([$commonProperties->pillarAxis]));
+ $reg->mapModel(Model::create(Blocks::POLISHED_BLACKSTONE_BUTTON(), Ids::POLISHED_BLACKSTONE_BUTTON)->properties($commonProperties->buttonProperties));
+ $reg->mapModel(Model::create(Blocks::POLISHED_BLACKSTONE_PRESSURE_PLATE(), Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE)->properties($commonProperties->simplePressurePlateProperties));
+ $reg->mapModel(Model::create(Blocks::PUMPKIN(), Ids::PUMPKIN)->properties([
+ //not used, has no visible effect
+ $commonProperties->dummyCardinalDirection
+ ]));
+ $reg->mapModel(Model::create(Blocks::PURPUR(), Ids::PURPUR_BLOCK)->properties([
+ $commonProperties->dummyPillarAxis
+ ]));
+ $reg->mapModel(Model::create(Blocks::PURPUR_PILLAR(), Ids::PURPUR_PILLAR)->properties([$commonProperties->pillarAxis]));
+
+ //Q
+ $reg->mapModel(Model::create(Blocks::QUARTZ(), Ids::QUARTZ_BLOCK)->properties([
+ $commonProperties->dummyPillarAxis
+ ]));
+ $reg->mapModel(Model::create(Blocks::QUARTZ_PILLAR(), Ids::QUARTZ_PILLAR)->properties([$commonProperties->pillarAxis]));
+
+ //R
+ $reg->mapModel(Model::create(Blocks::RAIL(), Ids::RAIL)->properties([
+ new IntProperty(StateNames::RAIL_DIRECTION, 0, 9, fn(Rail $b) => $b->getShape(), fn(Rail $b, int $v) => $b->setShape($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::REDSTONE_WIRE(), Ids::REDSTONE_WIRE)->properties([$commonProperties->analogRedstoneSignal]));
+ $reg->mapModel(Model::create(Blocks::RESPAWN_ANCHOR(), Ids::RESPAWN_ANCHOR)->properties([
+ new IntProperty(StateNames::RESPAWN_ANCHOR_CHARGE, 0, 4, fn(RespawnAnchor $b) => $b->getCharges(), fn(RespawnAnchor $b, int $v) => $b->setCharges($v))
+ ]));
+
+ //S
+ $reg->mapModel(Model::create(Blocks::SEA_PICKLE(), Ids::SEA_PICKLE)->properties([
+ new IntProperty(StateNames::CLUSTER_COUNT, 0, 3, fn(SeaPickle $b) => $b->getCount(), fn(SeaPickle $b, int $v) => $b->setCount($v), offset: 1),
+ new BoolProperty(StateNames::DEAD_BIT, fn(SeaPickle $b) => $b->isUnderwater(), fn(SeaPickle $b, bool $v) => $b->setUnderwater($v), inverted: true)
+ ]));
+ $reg->mapModel(Model::create(Blocks::SMALL_DRIPLEAF(), Ids::SMALL_DRIPLEAF_BLOCK)->properties([
+ new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(SmallDripleaf $b) => $b->isTop(), fn(SmallDripleaf $b, bool $v) => $b->setTop($v)),
+ $commonProperties->horizontalFacingCardinal
+ ]));
+ $reg->mapModel(Model::create(Blocks::SMOOTH_QUARTZ(), Ids::SMOOTH_QUARTZ)->properties([
+ $commonProperties->dummyPillarAxis
+ ]));
+ $reg->mapModel(Model::create(Blocks::SNOW_LAYER(), Ids::SNOW_LAYER)->properties([
+ new DummyProperty(StateNames::COVERED_BIT, false),
+ new IntProperty(StateNames::HEIGHT, 0, 7, fn(SnowLayer $b) => $b->getLayers(), fn(SnowLayer $b, int $v) => $b->setLayers($v), offset: 1)
+ ]));
+ $reg->mapModel(Model::create(Blocks::SOUL_CAMPFIRE(), Ids::SOUL_CAMPFIRE)->properties($commonProperties->campfireProperties));
+ $reg->mapModel(Model::create(Blocks::SOUL_FIRE(), Ids::SOUL_FIRE)->properties([
+ new DummyProperty(StateNames::AGE, 0) //this is useless for soul fire, since it doesn't have the logic associated
+ ]));
+ $reg->mapModel(Model::create(Blocks::SOUL_LANTERN(), Ids::SOUL_LANTERN)->properties([
+ new BoolProperty(StateNames::HANGING, fn(Lantern $b) => $b->isHanging(), fn(Lantern $b, bool $v) => $b->setHanging($v)) //TODO: repeated
+ ]));
+ $reg->mapModel(Model::create(Blocks::STONE_BUTTON(), Ids::STONE_BUTTON)->properties($commonProperties->buttonProperties));
+ $reg->mapModel(Model::create(Blocks::STONE_PRESSURE_PLATE(), Ids::STONE_PRESSURE_PLATE)->properties($commonProperties->simplePressurePlateProperties));
+ $reg->mapModel(Model::create(Blocks::STONECUTTER(), Ids::STONECUTTER_BLOCK)->properties([
+ $commonProperties->horizontalFacingCardinal
+ ]));
+ $reg->mapModel(Model::create(Blocks::SUGARCANE(), Ids::REEDS)->properties([
+ new IntProperty(StateNames::AGE, 0, 15, fn(Sugarcane $b) => $b->getAge(), fn(Sugarcane $b, int $v) => $b->setAge($v))
+ ]));
+
+ //T
+ $reg->mapModel(Model::create(Blocks::TRAPPED_CHEST(), Ids::TRAPPED_CHEST)->properties([
+ $commonProperties->horizontalFacingCardinal
+ ]));
+ $reg->mapModel(Model::create(Blocks::TRIPWIRE(), Ids::TRIP_WIRE)->properties([
+ new BoolProperty(StateNames::ATTACHED_BIT, fn(Tripwire $b) => $b->isConnected(), fn(Tripwire $b, bool $v) => $b->setConnected($v)),
+ new BoolProperty(StateNames::DISARMED_BIT, fn(Tripwire $b) => $b->isDisarmed(), fn(Tripwire $b, bool $v) => $b->setDisarmed($v)),
+ new BoolProperty(StateNames::SUSPENDED_BIT, fn(Tripwire $b) => $b->isSuspended(), fn(Tripwire $b, bool $v) => $b->setSuspended($v)),
+ new BoolProperty(StateNames::POWERED_BIT, fn(Tripwire $b) => $b->isTriggered(), fn(Tripwire $b, bool $v) => $b->setTriggered($v)),
+ ]));
+ $reg->mapModel(Model::create(Blocks::TRIPWIRE_HOOK(), Ids::TRIPWIRE_HOOK)->properties([
+ new BoolProperty(StateNames::ATTACHED_BIT, fn(TripwireHook $b) => $b->isConnected(), fn(TripwireHook $b, bool $v) => $b->setConnected($v)),
+ new BoolProperty(StateNames::POWERED_BIT, fn(TripwireHook $b) => $b->isPowered(), fn(TripwireHook $b, bool $v) => $b->setPowered($v)),
+ $commonProperties->horizontalFacingSWNE
+ ]));
+
+ $reg->mapModel(Model::create(Blocks::TWISTING_VINES(), Ids::TWISTING_VINES)->properties([
+ new IntProperty(StateNames::TWISTING_VINES_AGE, 0, 25, fn(NetherVines $b) => $b->getAge(), fn(NetherVines $b, int $v) => $b->setAge($v))
+ ]));
+
+ //W
+ $reg->mapModel(Model::create(Blocks::WALL_BANNER(), Ids::WALL_BANNER)->properties([$commonProperties->horizontalFacingClassic]));
+ $reg->mapModel(Model::create(Blocks::WEEPING_VINES(), Ids::WEEPING_VINES)->properties([
+ new IntProperty(StateNames::WEEPING_VINES_AGE, 0, 25, fn(NetherVines $b) => $b->getAge(), fn(NetherVines $b, int $v) => $b->setAge($v))
+ ]));
+ $reg->mapModel(Model::create(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), Ids::HEAVY_WEIGHTED_PRESSURE_PLATE)->properties([$commonProperties->analogRedstoneSignal]));
+ $reg->mapModel(Model::create(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), Ids::LIGHT_WEIGHTED_PRESSURE_PLATE)->properties([$commonProperties->analogRedstoneSignal]));
+ }
+
+ /**
+ * All mappings that still use the split form of serializer/deserializer registration
+ * This is typically only used by blocks with one ID but multiple PM types (split by property)
+ * These currently can't be registered in a unified way, and due to their small number it may not be worth the
+ * effort to implement a unified way to deal with them
+ */
+ private static function registerSplitMappings(BlockSerializerDeserializerRegistrar $reg) : void{
+ //big dripleaf - split into head / stem variants, as stems don't have tilt or leaf state
+ $reg->serializer->map(Blocks::BIG_DRIPLEAF_HEAD(), function(BigDripleafHead $block) : Writer{
+ return Writer::create(Ids::BIG_DRIPLEAF)
+ ->writeCardinalHorizontalFacing($block->getFacing())
+ ->writeUnitEnum(StateNames::BIG_DRIPLEAF_TILT, ValueMappings::getInstance()->dripleafState, $block->getLeafState())
+ ->writeBool(StateNames::BIG_DRIPLEAF_HEAD, true);
+ });
+ $reg->serializer->map(Blocks::BIG_DRIPLEAF_STEM(), function(BigDripleafStem $block) : Writer{
+ return Writer::create(Ids::BIG_DRIPLEAF)
+ ->writeCardinalHorizontalFacing($block->getFacing())
+ ->writeString(StateNames::BIG_DRIPLEAF_TILT, StringValues::BIG_DRIPLEAF_TILT_NONE)
+ ->writeBool(StateNames::BIG_DRIPLEAF_HEAD, false);
+ });
+ $reg->deserializer->map(Ids::BIG_DRIPLEAF, function(Reader $in) : Block{
+ if($in->readBool(StateNames::BIG_DRIPLEAF_HEAD)){
+ return Blocks::BIG_DRIPLEAF_HEAD()
+ ->setFacing($in->readCardinalHorizontalFacing())
+ ->setLeafState($in->readUnitEnum(StateNames::BIG_DRIPLEAF_TILT, ValueMappings::getInstance()->dripleafState));
+ }else{
+ $in->ignored(StateNames::BIG_DRIPLEAF_TILT);
+ return Blocks::BIG_DRIPLEAF_STEM()->setFacing($in->readCardinalHorizontalFacing());
+ }
+ });
+
+ //cauldrons - split into liquid variants, as each have different behaviour
+ $reg->serializer->map(Blocks::CAULDRON(), Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, 0));
+ $reg->serializer->map(Blocks::LAVA_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_LAVA, $b->getFillLevel()));
+ //potion cauldrons store their real information in the block actor data
+ $reg->serializer->map(Blocks::POTION_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel()));
+ $reg->serializer->map(Blocks::WATER_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel()));
+ $reg->deserializer->map(Ids::CAULDRON, function(Reader $in) : Block{
+ $level = $in->readBoundedInt(StateNames::FILL_LEVEL, 0, 6);
+ if($level === 0){
+ $in->ignored(StateNames::CAULDRON_LIQUID);
+ return Blocks::CAULDRON();
+ }
+
+ return (match ($liquid = $in->readString(StateNames::CAULDRON_LIQUID)) {
+ StringValues::CAULDRON_LIQUID_WATER => Blocks::WATER_CAULDRON(),
+ StringValues::CAULDRON_LIQUID_LAVA => Blocks::LAVA_CAULDRON(),
+ StringValues::CAULDRON_LIQUID_POWDER_SNOW => throw new UnsupportedBlockStateException("Powder snow is not supported yet"),
+ default => throw $in->badValueException(StateNames::CAULDRON_LIQUID, $liquid)
+ })->setFillLevel($level);
+ });
+
+ //mushroom stems, split for consistency with all-sided logs vs normal logs
+ $reg->serializer->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM)
+ ->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM));
+ $reg->serializer->map(Blocks::MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM)
+ ->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_STEM));
+ $reg->deserializer->map(Ids::MUSHROOM_STEM, fn(Reader $in) => match ($in->readBoundedInt(StateNames::HUGE_MUSHROOM_BITS, 0, 15)) {
+ BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM => Blocks::ALL_SIDED_MUSHROOM_STEM(),
+ BlockLegacyMetadata::MUSHROOM_BLOCK_STEM => Blocks::MUSHROOM_STEM(),
+ default => throw new BlockStateDeserializeException("This state does not exist"),
+ });
+
+ //pitcher crop, split into single and double variants as double has different properties and behaviour
+ //this will probably be the most annoying to unify
+ $reg->serializer->map(Blocks::PITCHER_CROP(), function(PitcherCrop $block) : Writer{
+ return Writer::create(Ids::PITCHER_CROP)
+ ->writeInt(StateNames::GROWTH, $block->getAge())
+ ->writeBool(StateNames::UPPER_BLOCK_BIT, false);
+ });
+ $reg->serializer->map(Blocks::DOUBLE_PITCHER_CROP(), function(DoublePitcherCrop $block) : Writer{
+ return Writer::create(Ids::PITCHER_CROP)
+ ->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE)
+ ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
+ });
+ $reg->deserializer->map(Ids::PITCHER_CROP, function(Reader $in) : Block{
+ $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7);
+ $top = $in->readBool(StateNames::UPPER_BLOCK_BIT);
+ if($growth <= PitcherCrop::MAX_AGE){
+ //top pitcher crop with age 0-2 is an invalid state
+ //only the bottom half should exist in this case
+ return $top ? Blocks::AIR() : Blocks::PITCHER_CROP()->setAge($growth);
+ }
+ return Blocks::DOUBLE_PITCHER_CROP()
+ ->setAge(min($growth - PitcherCrop::MAX_AGE - 1, DoublePitcherCrop::MAX_AGE))
+ ->setTop($top);
+ });
+ }
+}
diff --git a/src/data/bedrock/block/convert/property/BoolFromStringProperty.php b/src/data/bedrock/block/convert/property/BoolFromStringProperty.php
new file mode 100644
index 000000000..89c64188d
--- /dev/null
+++ b/src/data/bedrock/block/convert/property/BoolFromStringProperty.php
@@ -0,0 +1,78 @@
+
+ */
+final class BoolFromStringProperty implements StringProperty{
+
+ /**
+ * @param \Closure(TBlock) : bool $getter
+ * @param \Closure(TBlock, bool) : mixed $setter
+ */
+ public function __construct(
+ private string $name,
+ private string $falseValue,
+ private string $trueValue,
+ private \Closure $getter,
+ private \Closure $setter
+ ){}
+
+ public function getName() : string{
+ return $this->name;
+ }
+
+ public function getPossibleValues() : array{
+ return [$this->falseValue, $this->trueValue];
+ }
+
+ public function deserialize(object $block, BlockStateReader $in) : void{
+ $this->deserializePlain($block, $in->readString($this->name));
+ }
+
+ public function deserializePlain(object $block, string $raw) : void{
+ $value = match($raw){
+ $this->falseValue => false,
+ $this->trueValue => true,
+ default => throw new BlockStateSerializeException("Invalid value for {$this->name}: $raw"),
+ };
+
+ ($this->setter)($block, $value);
+ }
+
+ public function serialize(object $block, BlockStateWriter $out) : void{
+ $out->writeString($this->name, $this->serializePlain($block));
+ }
+
+ public function serializePlain(object $block) : string{
+ $value = ($this->getter)($block);
+ return $value ? $this->trueValue : $this->falseValue;
+ }
+}
diff --git a/src/data/bedrock/block/convert/property/BoolProperty.php b/src/data/bedrock/block/convert/property/BoolProperty.php
new file mode 100644
index 000000000..299ec4076
--- /dev/null
+++ b/src/data/bedrock/block/convert/property/BoolProperty.php
@@ -0,0 +1,71 @@
+
+ */
+final class BoolProperty implements Property{
+ /**
+ * @phpstan-param \Closure(TBlock) : bool $getter
+ * @phpstan-param \Closure(TBlock, bool) : mixed $setter
+ */
+ public function __construct(
+ private string $name,
+ private \Closure $getter,
+ private \Closure $setter,
+ private bool $inverted = false //we don't *need* this, but it avoids accidentally forgetting a ! in the getter/setter closures (and makes it analysable)
+ ){}
+
+ /**
+ * @phpstan-return self