mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-06 11:57:10 +00:00
Merge branch 'minor-next' into stable
This commit is contained in:
commit
02ffb04b92
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\generate_item_serializer_ids;
|
||||
|
||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||
use pocketmine\network\mcpe\convert\ItemTypeDictionaryFromDataHelper;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
@ -45,10 +46,10 @@ function constifyMcId(string $id) : string{
|
||||
return strtoupper(explode(":", $id, 2)[1]);
|
||||
}
|
||||
|
||||
function generateItemIds(ItemTypeDictionary $dictionary) : void{
|
||||
function generateItemIds(ItemTypeDictionary $dictionary, BlockItemIdMap $blockItemIdMap) : void{
|
||||
$ids = [];
|
||||
foreach($dictionary->getEntries() as $entry){
|
||||
if($entry->getNumericId() < 256){ //blockitems are serialized via BlockStateSerializer
|
||||
if($entry->getStringId() === "minecraft:air" || $blockItemIdMap->lookupBlockId($entry->getStringId()) !== null){ //blockitems are serialized via BlockStateSerializer
|
||||
continue;
|
||||
}
|
||||
$ids[$entry->getStringId()] = $entry->getStringId();
|
||||
@ -92,6 +93,7 @@ if($raw === false){
|
||||
}
|
||||
|
||||
$dictionary = ItemTypeDictionaryFromDataHelper::loadFromString($raw);
|
||||
generateItemIds($dictionary);
|
||||
$blockItemIdMap = BlockItemIdMap::getInstance();
|
||||
generateItemIds($dictionary, $blockItemIdMap);
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
||||
|
@ -22,7 +22,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pmmpthread": "^6.0.1",
|
||||
"ext-pmmpthread": "^6.0.4",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
@ -34,7 +34,7 @@
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"fgrosse/phpasn1": "~2.5.0",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.2.999",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~2.2.0+bedrock-1.20.0",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~3.0.0",
|
||||
"pocketmine/bedrock-data": "~2.3.0+bedrock-1.20.0",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.3.0+bedrock-1.20.0",
|
||||
"pocketmine/bedrock-protocol": "~22.0.0+bedrock-1.20.0",
|
||||
|
16
composer.lock
generated
16
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "3b102702eabc31fd8b2651db6c259397",
|
||||
"content-hash": "ff0fa864a7853011bf4620d870c47ac7",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -198,16 +198,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
"version": "2.2.0",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||
"reference": "79bb3ad542ef19e828fdf1fa6adc54f1fa4b3bb5"
|
||||
"reference": "8b72c47109e174ac7f17c3ac546748f8e49a5fdf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/79bb3ad542ef19e828fdf1fa6adc54f1fa4b3bb5",
|
||||
"reference": "79bb3ad542ef19e828fdf1fa6adc54f1fa4b3bb5",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/8b72c47109e174ac7f17c3ac546748f8e49a5fdf",
|
||||
"reference": "8b72c47109e174ac7f17c3ac546748f8e49a5fdf",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -218,9 +218,9 @@
|
||||
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/2.2.0"
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.0.0"
|
||||
},
|
||||
"time": "2023-05-04T21:49:36+00:00"
|
||||
"time": "2023-07-03T16:35:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
@ -3020,7 +3020,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pmmpthread": "^6.0.1",
|
||||
"ext-pmmpthread": "^6.0.4",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
|
@ -120,8 +120,8 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
if(($pmmpthread_version = phpversion("pmmpthread")) !== false){
|
||||
if(version_compare($pmmpthread_version, "6.0.1") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.0.1 is required, while you have $pmmpthread_version.";
|
||||
if(version_compare($pmmpthread_version, "6.0.4") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.0.4 is required, while you have $pmmpthread_version.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.1.4";
|
||||
public const BASE_VERSION = "5.2.0";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -717,8 +717,24 @@ final class BlockTypeIds{
|
||||
public const FLOWERING_AZALEA_LEAVES = 10687;
|
||||
public const REINFORCED_DEEPSLATE = 10688;
|
||||
public const CAVE_VINES = 10689;
|
||||
public const GLOW_LICHEN = 10690;
|
||||
public const CHERRY_BUTTON = 10691;
|
||||
public const CHERRY_DOOR = 10692;
|
||||
public const CHERRY_FENCE = 10693;
|
||||
public const CHERRY_FENCE_GATE = 10694;
|
||||
public const CHERRY_LEAVES = 10695;
|
||||
public const CHERRY_LOG = 10696;
|
||||
public const CHERRY_PLANKS = 10697;
|
||||
public const CHERRY_PRESSURE_PLATE = 10698;
|
||||
public const CHERRY_SAPLING = 10699;
|
||||
public const CHERRY_SIGN = 10700;
|
||||
public const CHERRY_SLAB = 10701;
|
||||
public const CHERRY_STAIRS = 10702;
|
||||
public const CHERRY_TRAPDOOR = 10703;
|
||||
public const CHERRY_WALL_SIGN = 10704;
|
||||
public const CHERRY_WOOD = 10705;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10690;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10706;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
284
src/block/GlowLichen.php
Normal file
284
src/block/GlowLichen.php
Normal file
@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\World;
|
||||
use function array_key_first;
|
||||
use function count;
|
||||
use function shuffle;
|
||||
|
||||
class GlowLichen extends Transparent{
|
||||
|
||||
/** @var int[] */
|
||||
protected array $faces = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facingFlags($this->faces);
|
||||
}
|
||||
|
||||
/** @return int[] */
|
||||
public function getFaces() : array{ return $this->faces; }
|
||||
|
||||
public function hasFace(int $face) : bool{
|
||||
return isset($this->faces[$face]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
* @return $this
|
||||
*/
|
||||
public function setFaces(array $faces) : self{
|
||||
$uniqueFaces = [];
|
||||
foreach($faces as $face){
|
||||
Facing::validate($face);
|
||||
$uniqueFaces[$face] = $face;
|
||||
}
|
||||
$this->faces = $uniqueFaces;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setFace(int $face, bool $value) : self{
|
||||
Facing::validate($face);
|
||||
if($value){
|
||||
$this->faces[$face] = $face;
|
||||
}else{
|
||||
unset($this->faces[$face]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return 7;
|
||||
}
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->faces = $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
|
||||
$availableFaces = $this->getAvailableFaces();
|
||||
|
||||
if(count($availableFaces) === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$opposite = Facing::opposite($face);
|
||||
$placedFace = isset($availableFaces[$opposite]) ? $opposite : array_key_first($availableFaces);
|
||||
$this->faces[$placedFace] = $placedFace;
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$changed = false;
|
||||
|
||||
foreach($this->faces as $face){
|
||||
if(!$this->getSide($face)->getSupportType(Facing::opposite($face))->equals(SupportType::FULL())){
|
||||
unset($this->faces[$face]);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changed){
|
||||
$world = $this->position->getWorld();
|
||||
if(count($this->faces) === 0){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getSpreadBlock(Block $replace, int $spreadFace) : ?Block{
|
||||
if($replace instanceof self && $replace->hasSameTypeId($this)){
|
||||
if($replace->hasFace($spreadFace)){
|
||||
return null;
|
||||
}
|
||||
$result = $replace;
|
||||
}elseif($replace->getTypeId() === BlockTypeIds::AIR){
|
||||
$result = VanillaBlocks::GLOW_LICHEN();
|
||||
}else{
|
||||
//TODO: if this is a water block, generate a waterlogged block
|
||||
return null;
|
||||
}
|
||||
return $result->setFace($spreadFace, true);
|
||||
}
|
||||
|
||||
private function spread(World $world, Vector3 $replacePos, int $spreadFace) : bool{
|
||||
$supportBlock = $world->getBlock($replacePos->getSide($spreadFace));
|
||||
$supportFace = Facing::opposite($spreadFace);
|
||||
|
||||
if(!$supportBlock->getSupportType($supportFace)->equals(SupportType::FULL())){
|
||||
return false;
|
||||
}
|
||||
|
||||
$replacedBlock = $supportBlock->getSide($supportFace);
|
||||
$replacementBlock = $this->getSpreadBlock($replacedBlock, Facing::opposite($supportFace));
|
||||
if($replacementBlock === null){
|
||||
return false;
|
||||
}
|
||||
|
||||
$ev = new BlockSpreadEvent($replacedBlock, $this, $replacementBlock);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$world->setBlock($replacedBlock->getPosition(), $ev->getNewState());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-return \Generator<int, int, void, void>
|
||||
*/
|
||||
private static function getShuffledSpreadFaces(int $sourceFace) : \Generator{
|
||||
$skipAxis = Facing::axis($sourceFace);
|
||||
|
||||
$faces = Facing::ALL;
|
||||
shuffle($faces);
|
||||
foreach($faces as $spreadFace){
|
||||
if(Facing::axis($spreadFace) !== $skipAxis){
|
||||
yield $spreadFace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function spreadAroundSupport(int $sourceFace) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
$supportPos = $this->position->getSide($sourceFace);
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
$replacePos = $supportPos->getSide($spreadFace);
|
||||
if($this->spread($world, $replacePos, Facing::opposite($spreadFace))){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function spreadAdjacentToSupport(int $sourceFace) : bool{
|
||||
$world = $this->position->getWorld();
|
||||
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
$replacePos = $this->position->getSide($spreadFace);
|
||||
if($this->spread($world, $replacePos, $sourceFace)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function spreadWithinSelf(int $sourceFace) : bool{
|
||||
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
|
||||
if(!$this->hasFace($spreadFace) && $this->spread($this->position->getWorld(), $this->position, $spreadFace)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item instanceof Fertilizer && count($this->faces) > 0){
|
||||
$shuffledFaces = $this->faces;
|
||||
shuffle($shuffledFaces);
|
||||
|
||||
$spreadMethods = [
|
||||
$this->spreadAroundSupport(...),
|
||||
$this->spreadAdjacentToSupport(...),
|
||||
$this->spreadWithinSelf(...),
|
||||
];
|
||||
shuffle($spreadMethods);
|
||||
|
||||
foreach($shuffledFaces as $sourceFace){
|
||||
foreach($spreadMethods as $spreadMethod){
|
||||
if($spreadMethod($sourceFace)){
|
||||
$item->pop();
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDrops(Item $item) : array{
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
|
||||
return $this->getDropsForCompatibleTool($item);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getFlameEncouragement() : int{
|
||||
return 15;
|
||||
}
|
||||
|
||||
public function getFlammability() : int{
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int> $faces
|
||||
*/
|
||||
private function getAvailableFaces() : array{
|
||||
$faces = [];
|
||||
foreach(Facing::ALL as $face){
|
||||
if(!$this->hasFace($face) && $this->getSide($face)->getSupportType(Facing::opposite($face))->equals(SupportType::FULL())){
|
||||
$faces[$face] = $face;
|
||||
}
|
||||
}
|
||||
return $faces;
|
||||
}
|
||||
}
|
@ -148,6 +148,7 @@ class Leaves extends Transparent{
|
||||
LeavesType::SPRUCE() => VanillaBlocks::SPRUCE_SAPLING(),
|
||||
LeavesType::MANGROVE(), //TODO: mangrove propagule
|
||||
LeavesType::AZALEA(), LeavesType::FLOWERING_AZALEA() => null, //TODO: azalea
|
||||
LeavesType::CHERRY() => null, //TODO: cherry
|
||||
default => throw new AssumptionFailedError("Unreachable")
|
||||
})?->asItem();
|
||||
if($sapling !== null){
|
||||
|
@ -159,6 +159,20 @@ use function mb_strtolower;
|
||||
* @method static CaveVines CAVE_VINES()
|
||||
* @method static Chain CHAIN()
|
||||
* @method static ChemicalHeat CHEMICAL_HEAT()
|
||||
* @method static WoodenButton CHERRY_BUTTON()
|
||||
* @method static WoodenDoor CHERRY_DOOR()
|
||||
* @method static WoodenFence CHERRY_FENCE()
|
||||
* @method static FenceGate CHERRY_FENCE_GATE()
|
||||
* @method static Leaves CHERRY_LEAVES()
|
||||
* @method static Wood CHERRY_LOG()
|
||||
* @method static Planks CHERRY_PLANKS()
|
||||
* @method static WoodenPressurePlate CHERRY_PRESSURE_PLATE()
|
||||
* @method static FloorSign CHERRY_SIGN()
|
||||
* @method static WoodenSlab CHERRY_SLAB()
|
||||
* @method static WoodenStairs CHERRY_STAIRS()
|
||||
* @method static WoodenTrapdoor CHERRY_TRAPDOOR()
|
||||
* @method static WallSign CHERRY_WALL_SIGN()
|
||||
* @method static Wood CHERRY_WOOD()
|
||||
* @method static Chest CHEST()
|
||||
* @method static Opaque CHISELED_DEEPSLATE()
|
||||
* @method static Opaque CHISELED_NETHER_BRICKS()
|
||||
@ -417,6 +431,7 @@ use function mb_strtolower;
|
||||
* @method static ItemFrame GLOWING_ITEM_FRAME()
|
||||
* @method static GlowingObsidian GLOWING_OBSIDIAN()
|
||||
* @method static Glowstone GLOWSTONE()
|
||||
* @method static GlowLichen GLOW_LICHEN()
|
||||
* @method static Opaque GOLD()
|
||||
* @method static GoldOre GOLD_ORE()
|
||||
* @method static Opaque GRANITE()
|
||||
@ -864,6 +879,7 @@ final class VanillaBlocks{
|
||||
self::register("glass_pane", new GlassPane(new BID(Ids::GLASS_PANE), "Glass Pane", $glassBreakInfo));
|
||||
self::register("glowing_obsidian", new GlowingObsidian(new BID(Ids::GLOWING_OBSIDIAN), "Glowing Obsidian", new Info(BreakInfo::pickaxe(10.0, ToolTier::DIAMOND(), 50.0))));
|
||||
self::register("glowstone", new Glowstone(new BID(Ids::GLOWSTONE), "Glowstone", new Info(BreakInfo::pickaxe(0.3))));
|
||||
self::register("glow_lichen", new GlowLichen(new BID(Ids::GLOW_LICHEN), "Glow Lichen", new Info(BreakInfo::axe(0.2, null, 0.2))));
|
||||
self::register("gold", new Opaque(new BID(Ids::GOLD), "Gold Block", new Info(BreakInfo::pickaxe(3.0, ToolTier::IRON(), 30.0))));
|
||||
|
||||
$grassBreakInfo = BreakInfo::shovel(0.6);
|
||||
|
@ -58,6 +58,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_PLANKS,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_PLANKS,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_PLANKS,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_PLANKS,
|
||||
default => throw new AssumptionFailedError("All tree types should be covered")
|
||||
});
|
||||
}
|
||||
@ -73,6 +74,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_FENCE,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_FENCE,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_FENCE,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_FENCE,
|
||||
default => throw new AssumptionFailedError("All tree types should be covered")
|
||||
});
|
||||
}
|
||||
@ -88,6 +90,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_SLAB,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_SLAB,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_SLAB,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_SLAB,
|
||||
default => throw new AssumptionFailedError("All tree types should be covered")
|
||||
});
|
||||
}
|
||||
@ -103,6 +106,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_LOG,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_STEM,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_STEM,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_LOG,
|
||||
default => throw new AssumptionFailedError("All tree types should be covered")
|
||||
});
|
||||
}
|
||||
@ -118,6 +122,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_WOOD,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_HYPHAE,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_HYPHAE,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_WOOD,
|
||||
default => throw new AssumptionFailedError("All tree types should be covered")
|
||||
});
|
||||
}
|
||||
@ -133,6 +138,7 @@ final class WoodLikeBlockIdHelper{
|
||||
LeavesType::MANGROVE()->id() => Ids::MANGROVE_LEAVES,
|
||||
LeavesType::AZALEA()->id() => Ids::AZALEA_LEAVES,
|
||||
LeavesType::FLOWERING_AZALEA()->id() => Ids::FLOWERING_AZALEA_LEAVES,
|
||||
LeavesType::CHERRY()->id() => Ids::CHERRY_LEAVES,
|
||||
default => throw new AssumptionFailedError("All leaves types should be covered")
|
||||
});
|
||||
}
|
||||
@ -209,7 +215,12 @@ final class WoodLikeBlockIdHelper{
|
||||
new BID(Ids::WARPED_WALL_SIGN, TileSign::class),
|
||||
fn() => VanillaItems::WARPED_SIGN()
|
||||
];
|
||||
|
||||
case WoodType::CHERRY()->id():
|
||||
return [
|
||||
new BID(Ids::CHERRY_SIGN, TileSign::class),
|
||||
new BID(Ids::CHERRY_WALL_SIGN, TileSign::class),
|
||||
fn() => VanillaItems::CHERRY_SIGN()
|
||||
];
|
||||
}
|
||||
throw new AssumptionFailedError("Switch should cover all wood types");
|
||||
}
|
||||
@ -225,6 +236,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_TRAPDOOR,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_TRAPDOOR,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_TRAPDOOR,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_TRAPDOOR,
|
||||
default => throw new AssumptionFailedError("All wood types should be covered")
|
||||
});
|
||||
}
|
||||
@ -240,6 +252,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_BUTTON,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_BUTTON,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_BUTTON,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_BUTTON,
|
||||
default => throw new AssumptionFailedError("All wood types should be covered")
|
||||
});
|
||||
}
|
||||
@ -255,6 +268,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_PRESSURE_PLATE,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_PRESSURE_PLATE,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_PRESSURE_PLATE,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_PRESSURE_PLATE,
|
||||
default => throw new AssumptionFailedError("All wood types should be covered")
|
||||
});
|
||||
}
|
||||
@ -270,6 +284,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_DOOR,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_DOOR,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_DOOR,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_DOOR,
|
||||
default => throw new AssumptionFailedError("All wood types should be covered")
|
||||
});
|
||||
}
|
||||
@ -285,6 +300,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_FENCE_GATE,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_FENCE_GATE,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_FENCE_GATE,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_FENCE_GATE,
|
||||
default => throw new AssumptionFailedError("All wood types should be covered")
|
||||
});
|
||||
}
|
||||
@ -300,6 +316,7 @@ final class WoodLikeBlockIdHelper{
|
||||
WoodType::MANGROVE()->id() => Ids::MANGROVE_STAIRS,
|
||||
WoodType::CRIMSON()->id() => Ids::CRIMSON_STAIRS,
|
||||
WoodType::WARPED()->id() => Ids::WARPED_STAIRS,
|
||||
WoodType::CHERRY()->id() => Ids::CHERRY_STAIRS,
|
||||
default => throw new AssumptionFailedError("All wood types should be covered")
|
||||
});
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\utils\EnumTrait;
|
||||
* @method static LeavesType ACACIA()
|
||||
* @method static LeavesType AZALEA()
|
||||
* @method static LeavesType BIRCH()
|
||||
* @method static LeavesType CHERRY()
|
||||
* @method static LeavesType DARK_OAK()
|
||||
* @method static LeavesType FLOWERING_AZALEA()
|
||||
* @method static LeavesType JUNGLE()
|
||||
@ -57,7 +58,8 @@ final class LeavesType{
|
||||
new self("dark_oak", "Dark Oak"),
|
||||
new self("mangrove", "Mangrove"),
|
||||
new self("azalea", "Azalea"),
|
||||
new self("flowering_azalea", "Flowering Azalea")
|
||||
new self("flowering_azalea", "Flowering Azalea"),
|
||||
new self("cherry", "Cherry")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\utils\EnumTrait;
|
||||
*
|
||||
* @method static MobHeadType CREEPER()
|
||||
* @method static MobHeadType DRAGON()
|
||||
* @method static MobHeadType PIGLIN()
|
||||
* @method static MobHeadType PLAYER()
|
||||
* @method static MobHeadType SKELETON()
|
||||
* @method static MobHeadType WITHER_SKELETON()
|
||||
@ -50,7 +51,8 @@ final class MobHeadType{
|
||||
new MobHeadType("zombie", "Zombie Head"),
|
||||
new MobHeadType("player", "Player Head"),
|
||||
new MobHeadType("creeper", "Creeper Head"),
|
||||
new MobHeadType("dragon", "Dragon Head")
|
||||
new MobHeadType("dragon", "Dragon Head"),
|
||||
new MobHeadType("piglin", "Piglin Head")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\utils\EnumTrait;
|
||||
*
|
||||
* @method static WoodType ACACIA()
|
||||
* @method static WoodType BIRCH()
|
||||
* @method static WoodType CHERRY()
|
||||
* @method static WoodType CRIMSON()
|
||||
* @method static WoodType DARK_OAK()
|
||||
* @method static WoodType JUNGLE()
|
||||
@ -56,7 +57,8 @@ final class WoodType{
|
||||
new self("dark_oak", "Dark Oak", true),
|
||||
new self("mangrove", "Mangrove", true),
|
||||
new self("crimson", "Crimson", false, "Stem", "Hyphae"),
|
||||
new self("warped", "Warped", false, "Stem", "Hyphae")
|
||||
new self("warped", "Warped", false, "Stem", "Hyphae"),
|
||||
new self("cherry", "Cherry", true),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ final class MobHeadTypeIdMap{
|
||||
$this->register(3, MobHeadType::PLAYER());
|
||||
$this->register(4, MobHeadType::CREEPER());
|
||||
$this->register(5, MobHeadType::DRAGON());
|
||||
$this->register(6, MobHeadType::PIGLIN());
|
||||
}
|
||||
|
||||
private function register(int $id, MobHeadType $type) : void{
|
||||
|
@ -38,6 +38,13 @@ final class BlockLegacyMetadata{
|
||||
public const CORAL_VARIANT_FIRE = 3;
|
||||
public const CORAL_VARIANT_HORN = 4;
|
||||
|
||||
public const MULTI_FACE_DIRECTION_FLAG_DOWN = 0x01;
|
||||
public const MULTI_FACE_DIRECTION_FLAG_UP = 0x02;
|
||||
public const MULTI_FACE_DIRECTION_FLAG_SOUTH = 0x04;
|
||||
public const MULTI_FACE_DIRECTION_FLAG_WEST = 0x08;
|
||||
public const MULTI_FACE_DIRECTION_FLAG_NORTH = 0x10;
|
||||
public const MULTI_FACE_DIRECTION_FLAG_EAST = 0x20;
|
||||
|
||||
public const MUSHROOM_BLOCK_ALL_PORES = 0;
|
||||
public const MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER = 1;
|
||||
public const MUSHROOM_BLOCK_CAP_NORTH_SIDE = 2;
|
||||
|
@ -111,7 +111,10 @@ final class BlockStateData{
|
||||
return new self($name, $states->getValue(), $version);
|
||||
}
|
||||
|
||||
public function toNbt() : CompoundTag{
|
||||
/**
|
||||
* Encodes the blockstate as a TAG_Compound, exactly as it would be in vanilla Bedrock.
|
||||
*/
|
||||
public function toVanillaNbt() : CompoundTag{
|
||||
$statesTag = CompoundTag::create();
|
||||
foreach(Utils::stringifyKeys($this->states) as $key => $value){
|
||||
$statesTag->setTag($key, $value);
|
||||
@ -119,7 +122,15 @@ final class BlockStateData{
|
||||
return CompoundTag::create()
|
||||
->setString(self::TAG_NAME, $this->name)
|
||||
->setInt(self::TAG_VERSION, $this->version)
|
||||
->setTag(self::TAG_STATES, $statesTag)
|
||||
->setTag(self::TAG_STATES, $statesTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the blockstate as a TAG_Compound, but with extra PM-specific metadata, used for fixing bugs in old saved
|
||||
* data. This should be used for anything saved to disk.
|
||||
*/
|
||||
public function toNbt() : CompoundTag{
|
||||
return $this->toVanillaNbt()
|
||||
->setLong(VersionInfo::TAG_WORLD_DATA_VERSION, VersionInfo::WORLD_DATA_VERSION);
|
||||
}
|
||||
|
||||
|
@ -79,6 +79,7 @@ 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;
|
||||
@ -192,7 +193,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->registerFlatColorBlockSerializers();
|
||||
$this->registerFlatCoralSerializers();
|
||||
$this->registerCauldronSerializers();
|
||||
$this->registerWoodBlockSerializers();
|
||||
$this->registerFlatWoodBlockSerializers();
|
||||
$this->registerLegacyWoodBlockSerializers();
|
||||
$this->registerLeavesSerializers();
|
||||
$this->registerSimpleSerializers();
|
||||
$this->registerSerializers();
|
||||
}
|
||||
@ -390,20 +393,206 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::WATER_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel()));
|
||||
}
|
||||
|
||||
private function registerWoodBlockSerializers() : void{
|
||||
$this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE);
|
||||
$this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
|
||||
$this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE);
|
||||
$this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
|
||||
$this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
|
||||
$this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
|
||||
|
||||
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->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE);
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
|
||||
$this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS);
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->map(Blocks::CHERRY_WOOD(), function(Wood $block) : Writer{
|
||||
//we can't use the standard method for this because cherry_wood has a useless property attached to it
|
||||
if(!$block->isStripped()){
|
||||
return Writer::create(Ids::CHERRY_WOOD)
|
||||
->writePillarAxis($block->getAxis())
|
||||
->writeBool(StateNames::STRIPPED_BIT, false); //this is useless, but it has to be written
|
||||
}else{
|
||||
return Writer::create(Ids::STRIPPED_CHERRY_WOOD)
|
||||
->writePillarAxis($block->getAxis());
|
||||
}
|
||||
});
|
||||
|
||||
$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->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE);
|
||||
$this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS);
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
|
||||
$this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS);
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->map(Blocks::MANGROVE_WOOD(), function(Wood $block) : Writer{
|
||||
//we can't use the standard method for this because mangrove_wood has a useless property attached to it
|
||||
if(!$block->isStripped()){
|
||||
return Writer::create(Ids::MANGROVE_WOOD)
|
||||
->writePillarAxis($block->getAxis())
|
||||
->writeBool(StateNames::STRIPPED_BIT, false); //this is useless, but it has to be written
|
||||
}else{
|
||||
return Writer::create(Ids::STRIPPED_MANGROVE_WOOD)
|
||||
->writePillarAxis($block->getAxis());
|
||||
}
|
||||
});
|
||||
|
||||
$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->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
|
||||
$this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS);
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
|
||||
$this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG);
|
||||
$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->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
|
||||
$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)));
|
||||
//wood, planks 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 registerLegacyWoodBlockSerializers() : void{
|
||||
foreach([
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_PLANKS(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_PLANKS(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_PLANKS(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_PLANKS(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_PLANKS(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_PLANKS(),
|
||||
] as $woodType => $block){
|
||||
$this->map($block, fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, $woodType));
|
||||
}
|
||||
|
||||
foreach([
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_SLAB(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_SLAB(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_SLAB(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_SLAB(),
|
||||
] as $woodType => $block){
|
||||
$this->map($block, fn(Slab $block) => Helper::encodeWoodenSlab($block, $woodType));
|
||||
}
|
||||
|
||||
foreach([
|
||||
Blocks::ACACIA_WOOD(),
|
||||
Blocks::BIRCH_WOOD(),
|
||||
Blocks::DARK_OAK_WOOD(),
|
||||
Blocks::JUNGLE_WOOD(),
|
||||
Blocks::OAK_WOOD(),
|
||||
Blocks::SPRUCE_WOOD(),
|
||||
] as $block){
|
||||
$this->map($block, fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
|
||||
//legacy mess
|
||||
$this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_ACACIA));
|
||||
$this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_BIRCH));
|
||||
$this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_DARK_OAK));
|
||||
$this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_JUNGLE));
|
||||
$this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_OAK));
|
||||
$this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_SPRUCE));
|
||||
}
|
||||
|
||||
private function registerSimpleSerializers() : void{
|
||||
@ -436,8 +625,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$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::CRAFTING_TABLE(), Ids::CRAFTING_TABLE);
|
||||
$this->mapSimple(Blocks::CRIMSON_FENCE(), Ids::CRIMSON_FENCE);
|
||||
$this->mapSimple(Blocks::CRIMSON_PLANKS(), Ids::CRIMSON_PLANKS);
|
||||
$this->mapSimple(Blocks::CRYING_OBSIDIAN(), Ids::CRYING_OBSIDIAN);
|
||||
$this->mapSimple(Blocks::DANDELION(), Ids::YELLOW_FLOWER);
|
||||
$this->mapSimple(Blocks::DEAD_BUSH(), Ids::DEADBUSH);
|
||||
@ -607,8 +794,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::LEGACY_STONECUTTER(), Ids::STONECUTTER);
|
||||
$this->mapSimple(Blocks::LILY_PAD(), Ids::WATERLILY);
|
||||
$this->mapSimple(Blocks::MAGMA(), Ids::MAGMA);
|
||||
$this->mapSimple(Blocks::MANGROVE_FENCE(), Ids::MANGROVE_FENCE);
|
||||
$this->mapSimple(Blocks::MANGROVE_PLANKS(), Ids::MANGROVE_PLANKS);
|
||||
$this->mapSimple(Blocks::MANGROVE_ROOTS(), Ids::MANGROVE_ROOTS);
|
||||
$this->mapSimple(Blocks::MELON(), Ids::MELON_BLOCK);
|
||||
$this->mapSimple(Blocks::MONSTER_SPAWNER(), Ids::MOB_SPAWNER);
|
||||
@ -655,27 +840,12 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM);
|
||||
$this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS);
|
||||
$this->mapSimple(Blocks::TUFF(), Ids::TUFF);
|
||||
$this->mapSimple(Blocks::WARPED_FENCE(), Ids::WARPED_FENCE);
|
||||
$this->mapSimple(Blocks::WARPED_PLANKS(), Ids::WARPED_PLANKS);
|
||||
$this->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK);
|
||||
$this->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE);
|
||||
}
|
||||
|
||||
private function registerSerializers() : 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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_ACACIA));
|
||||
$this->map(Blocks::ACACIA_PLANKS(), fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, StringValues::WOOD_TYPE_ACACIA));
|
||||
$this->map(Blocks::ACACIA_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::ACACIA_PRESSURE_PLATE)));
|
||||
$this->map(Blocks::ACACIA_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_ACACIA));
|
||||
$this->map(Blocks::ACACIA_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::ACACIA_STANDING_SIGN)));
|
||||
$this->map(Blocks::ACACIA_SLAB(), fn(Slab $block) => Helper::encodeWoodenSlab($block, StringValues::WOOD_TYPE_ACACIA));
|
||||
$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->map(Blocks::ACACIA_WOOD(), fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
$this->map(Blocks::ACTIVATOR_RAIL(), function(ActivatorRail $block) : Writer{
|
||||
return Writer::create(Ids::ACTIVATOR_RAIL)
|
||||
->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered())
|
||||
@ -698,7 +868,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
default => throw new BlockStateSerializeException("Invalid Anvil damage {$damage}"),
|
||||
});
|
||||
});
|
||||
$this->map(Blocks::AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES)));
|
||||
$this->map(Blocks::AZURE_BLUET(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_HOUSTONIA));
|
||||
$this->map(Blocks::BAMBOO(), function(Bamboo $block) : Writer{
|
||||
return Writer::create(Ids::BAMBOO)
|
||||
@ -749,20 +918,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeLegacyHorizontalFacing($block->getFacing());
|
||||
|
||||
});
|
||||
$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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_BIRCH));
|
||||
$this->map(Blocks::BIRCH_PLANKS(), fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, StringValues::WOOD_TYPE_BIRCH));
|
||||
$this->map(Blocks::BIRCH_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::BIRCH_PRESSURE_PLATE)));
|
||||
$this->map(Blocks::BIRCH_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_BIRCH));
|
||||
$this->map(Blocks::BIRCH_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::BIRCH_STANDING_SIGN)));
|
||||
$this->map(Blocks::BIRCH_SLAB(), fn(Slab $block) => Helper::encodeWoodenSlab($block, StringValues::WOOD_TYPE_BIRCH));
|
||||
$this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS);
|
||||
$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->map(Blocks::BIRCH_WOOD(), fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
$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)));
|
||||
@ -934,35 +1090,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
});
|
||||
$this->map(Blocks::CORNFLOWER(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_CORNFLOWER));
|
||||
$this->map(Blocks::CRACKED_STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_CRACKED));
|
||||
$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->mapSlab(Blocks::CRIMSON_SLAB(), Ids::CRIMSON_SLAB, Ids::CRIMSON_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::CRIMSON_STAIRS(), Ids::CRIMSON_STAIRS);
|
||||
$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->map(Blocks::CUT_RED_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::RED_SANDSTONE, StringValues::SAND_STONE_TYPE_CUT));
|
||||
$this->map(Blocks::CUT_RED_SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab4($block, StringValues::STONE_SLAB_TYPE_4_CUT_RED_SANDSTONE));
|
||||
$this->map(Blocks::CUT_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::SANDSTONE, StringValues::SAND_STONE_TYPE_CUT));
|
||||
$this->map(Blocks::CUT_SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab4($block, StringValues::STONE_SLAB_TYPE_4_CUT_SANDSTONE));
|
||||
$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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_DARK_OAK));
|
||||
$this->map(Blocks::DARK_OAK_PLANKS(), fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, StringValues::WOOD_TYPE_DARK_OAK));
|
||||
$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_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_DARK_OAK));
|
||||
$this->map(Blocks::DARK_OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::DARKOAK_STANDING_SIGN)));
|
||||
$this->map(Blocks::DARK_OAK_SLAB(), fn(Slab $block) => Helper::encodeWoodenSlab($block, StringValues::WOOD_TYPE_DARK_OAK));
|
||||
$this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS);
|
||||
$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->map(Blocks::DARK_OAK_WOOD(), fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
$this->map(Blocks::DARK_PRISMARINE(), fn() => Writer::create(Ids::PRISMARINE)
|
||||
->writeString(StateNames::PRISMARINE_BLOCK_TYPE, StringValues::PRISMARINE_BLOCK_TYPE_DARK));
|
||||
$this->map(Blocks::DARK_PRISMARINE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab2($block, StringValues::STONE_SLAB_TYPE_2_PRISMARINE_DARK));
|
||||
@ -1040,7 +1172,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::FLOWER_POT)
|
||||
->writeBool(StateNames::UPDATE_BIT, false); //to keep MCPE happy
|
||||
});
|
||||
$this->map(Blocks::FLOWERING_AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES_FLOWERED)));
|
||||
$this->map(Blocks::FROGLIGHT(), function(Froglight $block){
|
||||
return Writer::create(match($block->getFroglightType()){
|
||||
FroglightType::OCHRE() => Ids::OCHRE_FROGLIGHT,
|
||||
@ -1055,6 +1186,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->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->map(Blocks::GRANITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_GRANITE));
|
||||
$this->map(Blocks::GRANITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_GRANITE));
|
||||
@ -1086,20 +1221,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$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::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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_JUNGLE));
|
||||
$this->map(Blocks::JUNGLE_PLANKS(), fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, StringValues::WOOD_TYPE_JUNGLE));
|
||||
$this->map(Blocks::JUNGLE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::JUNGLE_PRESSURE_PLATE)));
|
||||
$this->map(Blocks::JUNGLE_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_JUNGLE));
|
||||
$this->map(Blocks::JUNGLE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::JUNGLE_STANDING_SIGN)));
|
||||
$this->map(Blocks::JUNGLE_SLAB(), fn(Slab $block) => Helper::encodeWoodenSlab($block, StringValues::WOOD_TYPE_JUNGLE));
|
||||
$this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS);
|
||||
$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->map(Blocks::JUNGLE_WOOD(), fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
$this->map(Blocks::LAB_TABLE(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_LAB_TABLE, new Writer(Ids::CHEMISTRY_TABLE)));
|
||||
$this->map(Blocks::LADDER(), function(Ladder $block) : Writer{
|
||||
return Writer::create(Ids::LADDER)
|
||||
@ -1149,28 +1271,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::LOOM)
|
||||
->writeLegacyHorizontalFacing($block->getFacing());
|
||||
});
|
||||
$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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::MANGROVE_LEAVES)));
|
||||
$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->mapSlab(Blocks::MANGROVE_SLAB(), Ids::MANGROVE_SLAB, Ids::MANGROVE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::MANGROVE_STAIRS(), Ids::MANGROVE_STAIRS);
|
||||
$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->map(Blocks::MANGROVE_WOOD(), function(Wood $block) : Writer{
|
||||
//we can't use the standard method for this because mangrove_wood has a useless property attached to it
|
||||
if(!$block->isStripped()){
|
||||
return Writer::create(Ids::MANGROVE_WOOD)
|
||||
->writePillarAxis($block->getAxis())
|
||||
->writeBool(StateNames::STRIPPED_BIT, false); //this is useless, but it has to be written
|
||||
}else{
|
||||
return Writer::create(Ids::STRIPPED_MANGROVE_WOOD)
|
||||
->writePillarAxis($block->getAxis());
|
||||
}
|
||||
});
|
||||
$this->map(Blocks::MATERIAL_REDUCER(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_MATERIAL_REDUCER, new Writer(Ids::CHEMISTRY_TABLE)));
|
||||
$this->map(Blocks::MELON_STEM(), fn(MelonStem $block) => Helper::encodeStem($block, new Writer(Ids::MELON_STEM)));
|
||||
$this->map(Blocks::MOB_HEAD(), function(MobHead $block) : Writer{
|
||||
@ -1206,20 +1306,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::NETHER_WART)
|
||||
->writeInt(StateNames::AGE, $block->getAge());
|
||||
});
|
||||
$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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_OAK));
|
||||
$this->map(Blocks::OAK_PLANKS(), fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, StringValues::WOOD_TYPE_OAK));
|
||||
$this->map(Blocks::OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::WOODEN_PRESSURE_PLATE)));
|
||||
$this->map(Blocks::OAK_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_OAK));
|
||||
$this->map(Blocks::OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::STANDING_SIGN)));
|
||||
$this->map(Blocks::OAK_SLAB(), fn(Slab $block) => Helper::encodeWoodenSlab($block, StringValues::WOOD_TYPE_OAK));
|
||||
$this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS);
|
||||
$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->map(Blocks::OAK_WOOD(), fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
$this->map(Blocks::ORANGE_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_ORANGE));
|
||||
$this->map(Blocks::OXEYE_DAISY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_OXEYE));
|
||||
$this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_PAEONIA, Writer::create(Ids::DOUBLE_PLANT)));
|
||||
@ -1367,20 +1454,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::SPONGE)
|
||||
->writeString(StateNames::SPONGE_TYPE, $block->isWet() ? StringValues::SPONGE_TYPE_WET : StringValues::SPONGE_TYPE_DRY);
|
||||
});
|
||||
$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_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_SPRUCE));
|
||||
$this->map(Blocks::SPRUCE_PLANKS(), fn() => Writer::create(Ids::PLANKS)
|
||||
->writeString(StateNames::WOOD_TYPE, StringValues::WOOD_TYPE_SPRUCE));
|
||||
$this->map(Blocks::SPRUCE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::SPRUCE_PRESSURE_PLATE)));
|
||||
$this->map(Blocks::SPRUCE_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_SPRUCE));
|
||||
$this->map(Blocks::SPRUCE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::SPRUCE_STANDING_SIGN)));
|
||||
$this->map(Blocks::SPRUCE_SLAB(), fn(Slab $block) => Helper::encodeWoodenSlab($block, StringValues::WOOD_TYPE_SPRUCE));
|
||||
$this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
|
||||
$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->map(Blocks::SPRUCE_WOOD(), fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
$this->map(Blocks::STAINED_CLAY(), function(StainedHardenedClay $block) : Writer{
|
||||
return Writer::create(Ids::STAINED_HARDENED_CLAY)
|
||||
->writeColor($block->getColor());
|
||||
@ -1477,17 +1551,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeBool(StateNames::DEAD_BIT, $block->isDead())
|
||||
->writeCoralFacing($block->getFacing());
|
||||
});
|
||||
$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->mapSlab(Blocks::WARPED_SLAB(), Ids::WARPED_SLAB, Ids::WARPED_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS);
|
||||
$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->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)
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\block\utils\WallConnectionType;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
||||
use pocketmine\data\bedrock\block\BlockStateNames;
|
||||
@ -134,6 +135,29 @@ final class BlockStateReader{
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
* @phpstan-return array<int, int>
|
||||
*/
|
||||
public function readFacingFlags() : array{
|
||||
$result = [];
|
||||
$flags = $this->readBoundedInt(BlockStateNames::MULTI_FACE_DIRECTION_BITS, 0, 63);
|
||||
foreach([
|
||||
BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_DOWN => Facing::DOWN,
|
||||
BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_UP => Facing::UP,
|
||||
BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_NORTH => Facing::NORTH,
|
||||
BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_SOUTH => Facing::SOUTH,
|
||||
BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_WEST => Facing::WEST,
|
||||
BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_EAST => Facing::EAST
|
||||
] as $flag => $facing){
|
||||
if(($flags & $flag) !== 0){
|
||||
$result[$facing] = $facing;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readEndRodFacingDirection() : int{
|
||||
$result = $this->readFacingDirection();
|
||||
|
@ -75,7 +75,9 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->registerFlatColorBlockDeserializers();
|
||||
$this->registerFlatCoralDeserializers();
|
||||
$this->registerCauldronDeserializers();
|
||||
$this->registerWoodBlockDeserializers();
|
||||
$this->registerFlatWoodBlockDeserializers();
|
||||
$this->registerLegacyWoodBlockDeserializers();
|
||||
$this->registerLeavesDeserializers();
|
||||
$this->registerSimpleDeserializers();
|
||||
$this->registerDeserializers();
|
||||
}
|
||||
@ -283,20 +285,191 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::CAULDRON, $deserializer);
|
||||
}
|
||||
|
||||
private function registerWoodBlockDeserializers() : void{
|
||||
$this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE());
|
||||
$this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE());
|
||||
$this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE());
|
||||
$this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE());
|
||||
$this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE());
|
||||
$this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE());
|
||||
|
||||
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->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE());
|
||||
$this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE());
|
||||
$this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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, function(Reader $in){
|
||||
$in->ignored(StateNames::STRIPPED_BIT); //this is also ignored by vanilla
|
||||
return 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->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE());
|
||||
$this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE());
|
||||
$this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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, function(Reader $in){
|
||||
$in->ignored(StateNames::STRIPPED_BIT); //this is also ignored by vanilla
|
||||
return 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->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE());
|
||||
$this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE());
|
||||
$this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$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 registerLegacyWoodBlockDeserializers() : void{
|
||||
|
||||
$this->map(Ids::PLANKS, function(Reader $in) : Block{
|
||||
return match($woodName = $in->readString(StateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_PLANKS(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_PLANKS(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_PLANKS(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_PLANKS(),
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_PLANKS(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_PLANKS(),
|
||||
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodName),
|
||||
};
|
||||
});
|
||||
$this->mapSlab(Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB, fn(Reader $in) => Helper::mapWoodenSlabType($in));
|
||||
|
||||
$this->map(Ids::WOOD, fn(Reader $in) : Block => Helper::decodeLog(match($woodType = $in->readString(StateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_WOOD(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_WOOD(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_WOOD(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_WOOD(),
|
||||
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodType),
|
||||
}, $in->readBool(StateNames::STRIPPED_BIT), $in));
|
||||
}
|
||||
|
||||
private function registerLeavesDeserializers() : void{
|
||||
//flattened IDs
|
||||
$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::CHERRY_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::CHERRY_LEAVES(), $in));
|
||||
$this->map(Ids::MANGROVE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::MANGROVE_LEAVES(), $in));
|
||||
|
||||
//legacy mess
|
||||
$this->map(Ids::LEAVES, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::OLD_LEAF_TYPE)){
|
||||
StringValues::OLD_LEAF_TYPE_BIRCH => Blocks::BIRCH_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_JUNGLE => Blocks::JUNGLE_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_OAK => Blocks::OAK_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_SPRUCE => Blocks::SPRUCE_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::OLD_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
$this->map(Ids::LEAVES2, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::NEW_LEAF_TYPE)){
|
||||
StringValues::NEW_LEAF_TYPE_ACACIA => Blocks::ACACIA_LEAVES(),
|
||||
StringValues::NEW_LEAF_TYPE_DARK_OAK => Blocks::DARK_OAK_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::NEW_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
}
|
||||
|
||||
private function registerSimpleDeserializers() : void{
|
||||
@ -328,8 +501,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$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::CRAFTING_TABLE, fn() => Blocks::CRAFTING_TABLE());
|
||||
$this->mapSimple(Ids::CRIMSON_FENCE, fn() => Blocks::CRIMSON_FENCE());
|
||||
$this->mapSimple(Ids::CRIMSON_PLANKS, fn() => Blocks::CRIMSON_PLANKS());
|
||||
$this->mapSimple(Ids::CRYING_OBSIDIAN, fn() => Blocks::CRYING_OBSIDIAN());
|
||||
$this->mapSimple(Ids::DEADBUSH, fn() => Blocks::DEAD_BUSH());
|
||||
$this->mapSimple(Ids::DEEPSLATE_BRICKS, fn() => Blocks::DEEPSLATE_BRICKS());
|
||||
@ -496,8 +667,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$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_FENCE, fn() => Blocks::MANGROVE_FENCE());
|
||||
$this->mapSimple(Ids::MANGROVE_PLANKS, fn() => Blocks::MANGROVE_PLANKS());
|
||||
$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());
|
||||
@ -545,8 +714,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS());
|
||||
$this->mapSimple(Ids::TUFF, fn() => Blocks::TUFF());
|
||||
$this->mapSimple(Ids::UNDYED_SHULKER_BOX, fn() => Blocks::SHULKER_BOX());
|
||||
$this->mapSimple(Ids::WARPED_FENCE, fn() => Blocks::WARPED_FENCE());
|
||||
$this->mapSimple(Ids::WARPED_PLANKS, fn() => Blocks::WARPED_PLANKS());
|
||||
$this->mapSimple(Ids::WARPED_WART_BLOCK, fn() => Blocks::WARPED_WART_BLOCK());
|
||||
$this->mapSimple(Ids::WATERLILY, fn() => Blocks::LILY_PAD());
|
||||
$this->mapSimple(Ids::WEB, fn() => Blocks::COBWEB());
|
||||
@ -555,14 +722,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
}
|
||||
|
||||
private function registerDeserializers() : 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->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
|
||||
$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->map(Ids::ACTIVATOR_RAIL, function(Reader $in) : Block{
|
||||
return Blocks::ACTIVATOR_RAIL()
|
||||
->setPowered($in->readBool(StateNames::RAIL_DATA_BIT))
|
||||
@ -580,8 +739,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
})
|
||||
->setFacing($in->readLegacyHorizontalFacing());
|
||||
});
|
||||
$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::BAMBOO, function(Reader $in) : Block{
|
||||
return Blocks::BAMBOO()
|
||||
->setLeafSize(match($value = $in->readString(StateNames::BAMBOO_LEAF_SIZE)){
|
||||
@ -627,14 +784,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setFacing($in->readLegacyHorizontalFacing())
|
||||
->setAttachmentType($in->readBellAttachmentType());
|
||||
});
|
||||
$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->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
|
||||
$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->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));
|
||||
@ -756,26 +905,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Helper::decodeWallCoralFan(Blocks::WALL_CORAL_FAN(), $in)
|
||||
->setCoralType(CoralType::HORN());
|
||||
});
|
||||
$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->mapSlab(Ids::CRIMSON_SLAB, Ids::CRIMSON_DOUBLE_SLAB, fn() => Blocks::CRIMSON_SLAB());
|
||||
$this->map(Ids::CRIMSON_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::CRIMSON_FENCE_GATE(), $in));
|
||||
$this->map(Ids::CRIMSON_HYPHAE, fn(Reader $in) => Helper::decodeLog(Blocks::CRIMSON_HYPHAE(), false, $in));
|
||||
$this->map(Ids::CRIMSON_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::CRIMSON_PRESSURE_PLATE(), $in));
|
||||
$this->mapStairs(Ids::CRIMSON_STAIRS, fn() => Blocks::CRIMSON_STAIRS());
|
||||
$this->map(Ids::CRIMSON_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::CRIMSON_SIGN(), $in));
|
||||
$this->map(Ids::CRIMSON_STEM, fn(Reader $in) => Helper::decodeLog(Blocks::CRIMSON_STEM(), false, $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->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->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
|
||||
$this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in));
|
||||
$this->mapStairs(Ids::DARK_PRISMARINE_STAIRS, fn() => Blocks::DARK_PRISMARINE_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::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)
|
||||
@ -839,7 +969,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::FARMLAND()
|
||||
->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7));
|
||||
});
|
||||
$this->map(Ids::FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::OAK_FENCE_GATE(), $in));
|
||||
$this->map(Ids::FIRE, function(Reader $in) : Block{
|
||||
return Blocks::FIRE()
|
||||
->setAge($in->readBoundedInt(StateNames::AGE, 0, 15));
|
||||
@ -860,6 +989,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setFacing($in->readHorizontalFacing())
|
||||
->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()
|
||||
@ -887,14 +1017,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
});
|
||||
$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::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->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
|
||||
$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->map(Ids::LADDER, function(Reader $in) : Block{
|
||||
return Blocks::LADDER()
|
||||
->setFacing($in->readHorizontalFacing());
|
||||
@ -904,18 +1026,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setHanging($in->readBool(StateNames::HANGING));
|
||||
});
|
||||
$this->map(Ids::LAVA, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::LAVA(), $in));
|
||||
$this->map(Ids::LEAVES, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::OLD_LEAF_TYPE)){
|
||||
StringValues::OLD_LEAF_TYPE_BIRCH => Blocks::BIRCH_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_JUNGLE => Blocks::JUNGLE_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_OAK => Blocks::OAK_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_SPRUCE => Blocks::SPRUCE_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::OLD_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
$this->map(Ids::LEAVES2, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::NEW_LEAF_TYPE)){
|
||||
StringValues::NEW_LEAF_TYPE_ACACIA => Blocks::ACACIA_LEAVES(),
|
||||
StringValues::NEW_LEAF_TYPE_DARK_OAK => Blocks::DARK_OAK_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::NEW_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
$this->map(Ids::LECTERN, function(Reader $in) : Block{
|
||||
return Blocks::LECTERN()
|
||||
->setFacing($in->readLegacyHorizontalFacing())
|
||||
@ -977,21 +1087,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::LOOM()
|
||||
->setFacing($in->readLegacyHorizontalFacing());
|
||||
});
|
||||
$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->mapSlab(Ids::MANGROVE_SLAB, Ids::MANGROVE_DOUBLE_SLAB, fn() => Blocks::MANGROVE_SLAB());
|
||||
$this->map(Ids::MANGROVE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::MANGROVE_FENCE_GATE(), $in));
|
||||
$this->map(Ids::MANGROVE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::MANGROVE_LEAVES(), $in));
|
||||
$this->map(Ids::MANGROVE_LOG, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_LOG(), false, $in));
|
||||
$this->map(Ids::MANGROVE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::MANGROVE_PRESSURE_PLATE(), $in));
|
||||
$this->mapStairs(Ids::MANGROVE_STAIRS, fn() => Blocks::MANGROVE_STAIRS());
|
||||
$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->map(Ids::MANGROVE_WOOD, function(Reader $in){
|
||||
$in->ignored(StateNames::STRIPPED_BIT); //this is also ignored by vanilla
|
||||
return Helper::decodeLog(Blocks::MANGROVE_WOOD(), false, $in);
|
||||
});
|
||||
$this->map(Ids::MELON_STEM, fn(Reader $in) => Helper::decodeStem(Blocks::MELON_STEM(), $in));
|
||||
$this->map(Ids::MONSTER_EGG, function(Reader $in) : Block{
|
||||
return match($type = $in->readString(StateNames::MONSTER_EGG_STONE_TYPE)){
|
||||
@ -1019,24 +1114,12 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setAge($in->readBoundedInt(StateNames::AGE, 0, 3));
|
||||
});
|
||||
$this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS());
|
||||
$this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
|
||||
$this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE())->setAxis($in->readPillarAxis()));
|
||||
$this->map(Ids::OXIDIZED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED()));
|
||||
$this->map(Ids::OXIDIZED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED()));
|
||||
$this->mapSlab(Ids::OXIDIZED_CUT_COPPER_SLAB, Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED()));
|
||||
$this->mapStairs(Ids::OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED()));
|
||||
$this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT())->setAxis($in->readPillarAxis()));
|
||||
$this->map(Ids::PLANKS, function(Reader $in) : Block{
|
||||
return match($woodName = $in->readString(StateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_PLANKS(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_PLANKS(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_PLANKS(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_PLANKS(),
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_PLANKS(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_PLANKS(),
|
||||
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodName),
|
||||
};
|
||||
});
|
||||
$this->mapStairs(Ids::POLISHED_ANDESITE_STAIRS, fn() => Blocks::POLISHED_ANDESITE_STAIRS());
|
||||
$this->map(Ids::POLISHED_BASALT, function(Reader $in) : Block{
|
||||
return Blocks::POLISHED_BASALT()
|
||||
@ -1241,14 +1324,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
default => throw $in->badValueException(StateNames::SPONGE_TYPE, $type),
|
||||
});
|
||||
});
|
||||
$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->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
|
||||
$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->map(Ids::STAINED_GLASS, function(Reader $in) : Block{
|
||||
return Blocks::STAINED_GLASS()
|
||||
->setColor($in->readColor());
|
||||
@ -1265,7 +1340,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::BANNER()
|
||||
->setRotation($in->readBoundedInt(StateNames::GROUND_SIGN_DIRECTION, 0, 15));
|
||||
});
|
||||
$this->map(Ids::STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::OAK_SIGN(), $in));
|
||||
$this->map(Ids::STONE, function(Reader $in) : Block{
|
||||
return match($type = $in->readString(StateNames::STONE_TYPE)){
|
||||
StringValues::STONE_TYPE_ANDESITE => Blocks::ANDESITE(),
|
||||
@ -1300,12 +1374,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::STONECUTTER()
|
||||
->setFacing($in->readHorizontalFacing());
|
||||
});
|
||||
$this->map(Ids::STRIPPED_CRIMSON_HYPHAE, fn(Reader $in) => Helper::decodeLog(Blocks::CRIMSON_HYPHAE(), true, $in));
|
||||
$this->map(Ids::STRIPPED_CRIMSON_STEM, fn(Reader $in) => Helper::decodeLog(Blocks::CRIMSON_STEM(), true, $in));
|
||||
$this->map(Ids::STRIPPED_MANGROVE_LOG, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_LOG(), true, $in));
|
||||
$this->map(Ids::STRIPPED_MANGROVE_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_WOOD(), true, $in));
|
||||
$this->map(Ids::STRIPPED_WARPED_HYPHAE, fn(Reader $in) => Helper::decodeLog(Blocks::WARPED_HYPHAE(), true, $in));
|
||||
$this->map(Ids::STRIPPED_WARPED_STEM, fn(Reader $in) => Helper::decodeLog(Blocks::WARPED_STEM(), true, $in));
|
||||
$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);
|
||||
@ -1328,7 +1396,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::TORCH()
|
||||
->setFacing($in->readTorchFacing());
|
||||
});
|
||||
$this->map(Ids::TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::OAK_TRAPDOOR(), $in));
|
||||
$this->map(Ids::TRAPPED_CHEST, function(Reader $in) : Block{
|
||||
return Blocks::TRAPPED_CHEST()
|
||||
->setFacing($in->readHorizontalFacing());
|
||||
@ -1375,18 +1442,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::WALL_BANNER()
|
||||
->setFacing($in->readHorizontalFacing());
|
||||
});
|
||||
$this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in));
|
||||
$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->mapSlab(Ids::WARPED_SLAB, Ids::WARPED_DOUBLE_SLAB, fn() => Blocks::WARPED_SLAB());
|
||||
$this->map(Ids::WARPED_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::WARPED_FENCE_GATE(), $in));
|
||||
$this->map(Ids::WARPED_HYPHAE, fn(Reader $in) => Helper::decodeLog(Blocks::WARPED_HYPHAE(), false, $in));
|
||||
$this->map(Ids::WARPED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::WARPED_PRESSURE_PLATE(), $in));
|
||||
$this->mapStairs(Ids::WARPED_STAIRS, fn() => Blocks::WARPED_STAIRS());
|
||||
$this->map(Ids::WARPED_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::WARPED_SIGN(), $in));
|
||||
$this->map(Ids::WARPED_STEM, fn(Reader $in) => Helper::decodeLog(Blocks::WARPED_STEM(), false, $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->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in));
|
||||
$this->map(Ids::WAXED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::NONE()));
|
||||
$this->map(Ids::WAXED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE()));
|
||||
@ -1413,19 +1468,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25));
|
||||
});
|
||||
$this->map(Ids::WHEAT, fn(Reader $in) => Helper::decodeCrops(Blocks::WHEAT(), $in));
|
||||
$this->map(Ids::WOOD, fn(Reader $in) : Block => Helper::decodeLog(match($woodType = $in->readString(StateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_WOOD(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_WOOD(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_WOOD(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_WOOD(),
|
||||
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodType),
|
||||
}, $in->readBool(StateNames::STRIPPED_BIT), $in));
|
||||
$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::WOODEN_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::OAK_PRESSURE_PLATE(), $in));
|
||||
$this->mapSlab(Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB, fn(Reader $in) => Helper::mapWoodenSlabType($in));
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\block\utils\WallConnectionType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\data\bedrock\block\BlockStateNames;
|
||||
use pocketmine\data\bedrock\block\BlockStateSerializeException;
|
||||
@ -39,6 +40,7 @@ use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\nbt\tag\Tag;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
|
||||
final class BlockStateWriter{
|
||||
|
||||
@ -88,6 +90,28 @@ final class BlockStateWriter{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
* @phpstan-param array<int, int> $faces
|
||||
* @return $this
|
||||
*/
|
||||
public function writeFacingFlags(array $faces) : self{
|
||||
$result = 0;
|
||||
foreach($faces as $face){
|
||||
$result |= match($face){
|
||||
Facing::DOWN => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_DOWN,
|
||||
Facing::UP => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_UP,
|
||||
Facing::NORTH => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_NORTH,
|
||||
Facing::SOUTH => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_SOUTH,
|
||||
Facing::WEST => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_WEST,
|
||||
Facing::EAST => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_EAST,
|
||||
default => throw new AssumptionFailedError("Unhandled face $face")
|
||||
};
|
||||
}
|
||||
|
||||
return $this->writeInt(BlockStateNames::MULTI_FACE_DIRECTION_BITS, $result);
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeEndRodFacingDirection(int $value) : self{
|
||||
//end rods are stupid in bedrock and have everything except up/down the wrong way round
|
||||
|
@ -24,6 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\bedrock\block\upgrade;
|
||||
|
||||
use pocketmine\nbt\tag\Tag;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_diff;
|
||||
use function count;
|
||||
|
||||
final class BlockStateUpgradeSchemaBlockRemap{
|
||||
/**
|
||||
@ -37,8 +40,43 @@ final class BlockStateUpgradeSchemaBlockRemap{
|
||||
*/
|
||||
public function __construct(
|
||||
public array $oldState,
|
||||
public string $newName,
|
||||
public string|BlockStateUpgradeSchemaFlattenedName $newName,
|
||||
public array $newState,
|
||||
public array $copiedState
|
||||
){}
|
||||
|
||||
public function equals(self $that) : bool{
|
||||
$sameName = $this->newName === $that->newName ||
|
||||
(
|
||||
$this->newName instanceof BlockStateUpgradeSchemaFlattenedName &&
|
||||
$that->newName instanceof BlockStateUpgradeSchemaFlattenedName &&
|
||||
$this->newName->equals($that->newName)
|
||||
);
|
||||
if(!$sameName){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(
|
||||
count($this->oldState) !== count($that->oldState) ||
|
||||
count($this->newState) !== count($that->newState) ||
|
||||
count($this->copiedState) !== count($that->copiedState) ||
|
||||
count(array_diff($this->copiedState, $that->copiedState)) !== 0
|
||||
){
|
||||
return false;
|
||||
}
|
||||
foreach(Utils::stringifyKeys($this->oldState) as $propertyName => $propertyValue){
|
||||
if(!isset($that->oldState[$propertyName]) || !$that->oldState[$propertyName]->equals($propertyValue)){
|
||||
//different filter value
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach(Utils::stringifyKeys($this->newState) as $propertyName => $propertyValue){
|
||||
if(!isset($that->newState[$propertyName]) || !$that->newState[$propertyName]->equals($propertyValue)){
|
||||
//different replacement value
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\block\upgrade;
|
||||
|
||||
final class BlockStateUpgradeSchemaFlattenedName{
|
||||
|
||||
public function __construct(
|
||||
public string $prefix,
|
||||
public string $flattenedProperty,
|
||||
public string $suffix
|
||||
){}
|
||||
|
||||
public function equals(self $that) : bool{
|
||||
return $this->prefix === $that->prefix &&
|
||||
$this->flattenedProperty === $that->flattenedProperty &&
|
||||
$this->suffix === $that->suffix;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ namespace pocketmine\data\bedrock\block\upgrade;
|
||||
|
||||
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModel;
|
||||
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelBlockRemap;
|
||||
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelFlattenedName;
|
||||
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelTag;
|
||||
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelValueRemap;
|
||||
use pocketmine\nbt\tag\ByteTag;
|
||||
@ -43,12 +44,14 @@ use function get_debug_type;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_object;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function ksort;
|
||||
use function sort;
|
||||
use function str_pad;
|
||||
use function strval;
|
||||
use function usort;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const SORT_NUMERIC;
|
||||
use const STR_PAD_LEFT;
|
||||
@ -154,9 +157,17 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
|
||||
foreach(Utils::stringifyKeys($model->remappedStates ?? []) as $oldBlockName => $remaps){
|
||||
foreach($remaps as $remap){
|
||||
if(isset($remap->newName) === isset($remap->newFlattenedName)){
|
||||
throw new \UnexpectedValueException("Expected exactly one of 'newName' or 'newFlattenedName' properties to be set");
|
||||
}
|
||||
|
||||
$result->remappedStates[$oldBlockName][] = new BlockStateUpgradeSchemaBlockRemap(
|
||||
array_map(fn(BlockStateUpgradeSchemaModelTag $tag) => self::jsonModelToTag($tag), $remap->oldState ?? []),
|
||||
$remap->newName,
|
||||
$remap->newName ?? new BlockStateUpgradeSchemaFlattenedName(
|
||||
$remap->newFlattenedName->prefix,
|
||||
$remap->newFlattenedName->flattenedProperty,
|
||||
$remap->newFlattenedName->suffix
|
||||
),
|
||||
array_map(fn(BlockStateUpgradeSchemaModelTag $tag) => self::jsonModelToTag($tag), $remap->newState ?? []),
|
||||
$remap->copiedState ?? []
|
||||
);
|
||||
@ -285,7 +296,13 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
foreach($remaps as $remap){
|
||||
$modelRemap = new BlockStateUpgradeSchemaModelBlockRemap(
|
||||
array_map(fn(Tag $tag) => self::tagToJsonModel($tag), $remap->oldState),
|
||||
$remap->newName,
|
||||
is_string($remap->newName) ?
|
||||
$remap->newName :
|
||||
new BlockStateUpgradeSchemaModelFlattenedName(
|
||||
$remap->newName->prefix,
|
||||
$remap->newName->flattenedProperty,
|
||||
$remap->newName->suffix
|
||||
),
|
||||
array_map(fn(Tag $tag) => self::tagToJsonModel($tag), $remap->newState),
|
||||
$remap->copiedState
|
||||
);
|
||||
@ -299,7 +316,15 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
}
|
||||
$keyedRemaps[$key] = $modelRemap;
|
||||
}
|
||||
ksort($keyedRemaps);
|
||||
usort($keyedRemaps, function(BlockStateUpgradeSchemaModelBlockRemap $a, BlockStateUpgradeSchemaModelBlockRemap $b) : int{
|
||||
//remaps with more specific criteria must come first
|
||||
$filterSizeCompare = count($b->oldState ?? []) <=> count($a->oldState ?? []);
|
||||
if($filterSizeCompare !== 0){
|
||||
return $filterSizeCompare;
|
||||
}
|
||||
//remaps with the same number of criteria should be sorted alphabetically, but this is not strictly necessary
|
||||
return json_encode($a->oldState ?? []) <=> json_encode($b->oldState ?? []);
|
||||
});
|
||||
$result->remappedStates[$oldBlockName] = array_values($keyedRemaps);
|
||||
}
|
||||
if(isset($result->remappedStates)){
|
||||
|
@ -24,11 +24,14 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\bedrock\block\upgrade;
|
||||
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\nbt\tag\Tag;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
use function is_string;
|
||||
use function ksort;
|
||||
use function max;
|
||||
use function sprintf;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
final class BlockStateUpgrader{
|
||||
@ -79,6 +82,20 @@ final class BlockStateUpgrader{
|
||||
continue 2; //try next state
|
||||
}
|
||||
}
|
||||
|
||||
if(is_string($remap->newName)){
|
||||
$newName = $remap->newName;
|
||||
}else{
|
||||
$flattenedValue = $oldState[$remap->newName->flattenedProperty];
|
||||
if($flattenedValue instanceof StringTag){
|
||||
$newName = sprintf("%s%s%s", $remap->newName->prefix, $flattenedValue->getValue(), $remap->newName->suffix);
|
||||
unset($oldState[$remap->newName->flattenedProperty]);
|
||||
}else{
|
||||
//flattened property is not a TAG_String, so this transformation is not applicable
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$newState = $remap->newState;
|
||||
foreach($remap->copiedState as $stateName){
|
||||
if(isset($oldState[$stateName])){
|
||||
@ -86,7 +103,7 @@ final class BlockStateUpgrader{
|
||||
}
|
||||
}
|
||||
|
||||
$blockStateData = new BlockStateData($remap->newName, $newState, $resultVersion);
|
||||
$blockStateData = new BlockStateData($newName, $newState, $resultVersion);
|
||||
continue 2; //try next schema
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,16 @@ final class BlockStateUpgradeSchemaModelBlockRemap{
|
||||
*/
|
||||
public ?array $oldState;
|
||||
|
||||
/** @required */
|
||||
/**
|
||||
* Either this or newFlattenedName must be present
|
||||
* Due to technical limitations of jsonmapper, we can't use a union type here
|
||||
*/
|
||||
public string $newName;
|
||||
/**
|
||||
* Either this or newName must be present
|
||||
* Due to technical limitations of jsonmapper, we can't use a union type here
|
||||
*/
|
||||
public BlockStateUpgradeSchemaModelFlattenedName $newFlattenedName;
|
||||
|
||||
/**
|
||||
* @var BlockStateUpgradeSchemaModelTag[]|null
|
||||
@ -59,9 +67,13 @@ final class BlockStateUpgradeSchemaModelBlockRemap{
|
||||
* @phpstan-param array<string, BlockStateUpgradeSchemaModelTag> $newState
|
||||
* @phpstan-param list<string> $copiedState
|
||||
*/
|
||||
public function __construct(array $oldState, string $newName, array $newState, array $copiedState){
|
||||
public function __construct(array $oldState, string|BlockStateUpgradeSchemaModelFlattenedName $newNameRule, array $newState, array $copiedState){
|
||||
$this->oldState = count($oldState) === 0 ? null : $oldState;
|
||||
$this->newName = $newName;
|
||||
if($newNameRule instanceof BlockStateUpgradeSchemaModelFlattenedName){
|
||||
$this->newFlattenedName = $newNameRule;
|
||||
}else{
|
||||
$this->newName = $newNameRule;
|
||||
}
|
||||
$this->newState = count($newState) === 0 ? null : $newState;
|
||||
$this->copiedState = $copiedState;
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\block\upgrade\model;
|
||||
|
||||
final class BlockStateUpgradeSchemaModelFlattenedName{
|
||||
|
||||
/** @required */
|
||||
public string $prefix;
|
||||
/** @required */
|
||||
public string $flattenedProperty;
|
||||
/** @required */
|
||||
public string $suffix;
|
||||
|
||||
public function __construct(string $prefix, string $flattenedProperty, string $suffix){
|
||||
$this->prefix = $prefix;
|
||||
$this->flattenedProperty = $flattenedProperty;
|
||||
$this->suffix = $suffix;
|
||||
}
|
||||
}
|
@ -135,6 +135,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Block(Ids::CAKE, Blocks::CAKE());
|
||||
$this->map1to1Block(Ids::CAULDRON, Blocks::CAULDRON());
|
||||
$this->map1to1Block(Ids::CHAIN, Blocks::CHAIN());
|
||||
$this->map1to1Block(Ids::CHERRY_DOOR, Blocks::CHERRY_DOOR());
|
||||
$this->map1to1Block(Ids::COMPARATOR, Blocks::REDSTONE_COMPARATOR());
|
||||
$this->map1to1Block(Ids::CRIMSON_DOOR, Blocks::CRIMSON_DOOR());
|
||||
$this->map1to1Block(Ids::DARK_OAK_DOOR, Blocks::DARK_OAK_DOOR());
|
||||
@ -185,6 +186,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::CHAINMAIL_HELMET, Items::CHAINMAIL_HELMET());
|
||||
$this->map1to1Item(Ids::CHAINMAIL_LEGGINGS, Items::CHAINMAIL_LEGGINGS());
|
||||
$this->map1to1Item(Ids::CHARCOAL, Items::CHARCOAL());
|
||||
$this->map1to1Item(Ids::CHERRY_SIGN, Items::CHERRY_SIGN());
|
||||
$this->map1to1Item(Ids::CHICKEN, Items::RAW_CHICKEN());
|
||||
$this->map1to1Item(Ids::CHORUS_FRUIT, Items::CHORUS_FRUIT());
|
||||
$this->map1to1Item(Ids::CLAY_BALL, Items::CLAY());
|
||||
|
@ -30,20 +30,24 @@ final class ItemTypeNames{
|
||||
public const ACACIA_BOAT = "minecraft:acacia_boat";
|
||||
public const ACACIA_CHEST_BOAT = "minecraft:acacia_chest_boat";
|
||||
public const ACACIA_DOOR = "minecraft:acacia_door";
|
||||
public const ACACIA_HANGING_SIGN = "minecraft:acacia_hanging_sign";
|
||||
public const ACACIA_SIGN = "minecraft:acacia_sign";
|
||||
public const AGENT_SPAWN_EGG = "minecraft:agent_spawn_egg";
|
||||
public const ALLAY_SPAWN_EGG = "minecraft:allay_spawn_egg";
|
||||
public const AMETHYST_SHARD = "minecraft:amethyst_shard";
|
||||
public const ANGLER_POTTERY_SHERD = "minecraft:angler_pottery_sherd";
|
||||
public const APPLE = "minecraft:apple";
|
||||
public const ARCHER_POTTERY_SHARD = "minecraft:archer_pottery_shard";
|
||||
public const ARCHER_POTTERY_SHERD = "minecraft:archer_pottery_sherd";
|
||||
public const ARMOR_STAND = "minecraft:armor_stand";
|
||||
public const ARMS_UP_POTTERY_SHARD = "minecraft:arms_up_pottery_shard";
|
||||
public const ARMS_UP_POTTERY_SHERD = "minecraft:arms_up_pottery_sherd";
|
||||
public const ARROW = "minecraft:arrow";
|
||||
public const AXOLOTL_BUCKET = "minecraft:axolotl_bucket";
|
||||
public const AXOLOTL_SPAWN_EGG = "minecraft:axolotl_spawn_egg";
|
||||
public const BAKED_POTATO = "minecraft:baked_potato";
|
||||
public const BALLOON = "minecraft:balloon";
|
||||
public const BAMBOO_CHEST_RAFT = "minecraft:bamboo_chest_raft";
|
||||
public const BAMBOO_DOOR = "minecraft:bamboo_door";
|
||||
public const BAMBOO_HANGING_SIGN = "minecraft:bamboo_hanging_sign";
|
||||
public const BAMBOO_RAFT = "minecraft:bamboo_raft";
|
||||
public const BAMBOO_SIGN = "minecraft:bamboo_sign";
|
||||
public const BANNER = "minecraft:banner";
|
||||
@ -58,8 +62,10 @@ final class ItemTypeNames{
|
||||
public const BIRCH_BOAT = "minecraft:birch_boat";
|
||||
public const BIRCH_CHEST_BOAT = "minecraft:birch_chest_boat";
|
||||
public const BIRCH_DOOR = "minecraft:birch_door";
|
||||
public const BIRCH_HANGING_SIGN = "minecraft:birch_hanging_sign";
|
||||
public const BIRCH_SIGN = "minecraft:birch_sign";
|
||||
public const BLACK_DYE = "minecraft:black_dye";
|
||||
public const BLADE_POTTERY_SHERD = "minecraft:blade_pottery_sherd";
|
||||
public const BLAZE_POWDER = "minecraft:blaze_powder";
|
||||
public const BLAZE_ROD = "minecraft:blaze_rod";
|
||||
public const BLAZE_SPAWN_EGG = "minecraft:blaze_spawn_egg";
|
||||
@ -73,15 +79,18 @@ final class ItemTypeNames{
|
||||
public const BOW = "minecraft:bow";
|
||||
public const BOWL = "minecraft:bowl";
|
||||
public const BREAD = "minecraft:bread";
|
||||
public const BREWER_POTTERY_SHERD = "minecraft:brewer_pottery_sherd";
|
||||
public const BREWING_STAND = "minecraft:brewing_stand";
|
||||
public const BRICK = "minecraft:brick";
|
||||
public const BROWN_DYE = "minecraft:brown_dye";
|
||||
public const BRUSH = "minecraft:brush";
|
||||
public const BUCKET = "minecraft:bucket";
|
||||
public const BURN_POTTERY_SHERD = "minecraft:burn_pottery_sherd";
|
||||
public const CAKE = "minecraft:cake";
|
||||
public const CAMEL_SPAWN_EGG = "minecraft:camel_spawn_egg";
|
||||
public const CAMERA = "minecraft:camera";
|
||||
public const CAMPFIRE = "minecraft:campfire";
|
||||
public const CARPET = "minecraft:carpet";
|
||||
public const CARROT = "minecraft:carrot";
|
||||
public const CARROT_ON_A_STICK = "minecraft:carrot_on_a_stick";
|
||||
public const CAT_SPAWN_EGG = "minecraft:cat_spawn_egg";
|
||||
@ -93,6 +102,11 @@ final class ItemTypeNames{
|
||||
public const CHAINMAIL_HELMET = "minecraft:chainmail_helmet";
|
||||
public const CHAINMAIL_LEGGINGS = "minecraft:chainmail_leggings";
|
||||
public const CHARCOAL = "minecraft:charcoal";
|
||||
public const CHERRY_BOAT = "minecraft:cherry_boat";
|
||||
public const CHERRY_CHEST_BOAT = "minecraft:cherry_chest_boat";
|
||||
public const CHERRY_DOOR = "minecraft:cherry_door";
|
||||
public const CHERRY_HANGING_SIGN = "minecraft:cherry_hanging_sign";
|
||||
public const CHERRY_SIGN = "minecraft:cherry_sign";
|
||||
public const CHEST_BOAT = "minecraft:chest_boat";
|
||||
public const CHEST_MINECART = "minecraft:chest_minecart";
|
||||
public const CHICKEN = "minecraft:chicken";
|
||||
@ -101,6 +115,7 @@ final class ItemTypeNames{
|
||||
public const CLAY_BALL = "minecraft:clay_ball";
|
||||
public const CLOCK = "minecraft:clock";
|
||||
public const COAL = "minecraft:coal";
|
||||
public const COAST_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:coast_armor_trim_smithing_template";
|
||||
public const COCOA_BEANS = "minecraft:cocoa_beans";
|
||||
public const COD = "minecraft:cod";
|
||||
public const COD_BUCKET = "minecraft:cod_bucket";
|
||||
@ -118,18 +133,21 @@ final class ItemTypeNames{
|
||||
public const COOKED_SALMON = "minecraft:cooked_salmon";
|
||||
public const COOKIE = "minecraft:cookie";
|
||||
public const COPPER_INGOT = "minecraft:copper_ingot";
|
||||
public const CORAL = "minecraft:coral";
|
||||
public const COW_SPAWN_EGG = "minecraft:cow_spawn_egg";
|
||||
public const CREEPER_BANNER_PATTERN = "minecraft:creeper_banner_pattern";
|
||||
public const CREEPER_SPAWN_EGG = "minecraft:creeper_spawn_egg";
|
||||
public const CRIMSON_DOOR = "minecraft:crimson_door";
|
||||
public const CRIMSON_HANGING_SIGN = "minecraft:crimson_hanging_sign";
|
||||
public const CRIMSON_SIGN = "minecraft:crimson_sign";
|
||||
public const CROSSBOW = "minecraft:crossbow";
|
||||
public const CYAN_DYE = "minecraft:cyan_dye";
|
||||
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";
|
||||
public const DARK_OAK_DOOR = "minecraft:dark_oak_door";
|
||||
public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
|
||||
public const DARK_OAK_SIGN = "minecraft:dark_oak_sign";
|
||||
public const DEBUG_STICK = "minecraft:debug_stick";
|
||||
public const DIAMOND = "minecraft:diamond";
|
||||
public const DIAMOND_AXE = "minecraft:diamond_axe";
|
||||
public const DIAMOND_BOOTS = "minecraft:diamond_boots";
|
||||
@ -147,6 +165,7 @@ final class ItemTypeNames{
|
||||
public const DRAGON_BREATH = "minecraft:dragon_breath";
|
||||
public const DRIED_KELP = "minecraft:dried_kelp";
|
||||
public const DROWNED_SPAWN_EGG = "minecraft:drowned_spawn_egg";
|
||||
public const DUNE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:dune_armor_trim_smithing_template";
|
||||
public const DYE = "minecraft:dye";
|
||||
public const ECHO_SHARD = "minecraft:echo_shard";
|
||||
public const EGG = "minecraft:egg";
|
||||
@ -164,7 +183,10 @@ final class ItemTypeNames{
|
||||
public const ENDERMITE_SPAWN_EGG = "minecraft:endermite_spawn_egg";
|
||||
public const EVOKER_SPAWN_EGG = "minecraft:evoker_spawn_egg";
|
||||
public const EXPERIENCE_BOTTLE = "minecraft:experience_bottle";
|
||||
public const EXPLORER_POTTERY_SHERD = "minecraft:explorer_pottery_sherd";
|
||||
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:eye_armor_trim_smithing_template";
|
||||
public const FEATHER = "minecraft:feather";
|
||||
public const FENCE = "minecraft:fence";
|
||||
public const FERMENTED_SPIDER_EYE = "minecraft:fermented_spider_eye";
|
||||
public const FIELD_MASONED_BANNER_PATTERN = "minecraft:field_masoned_banner_pattern";
|
||||
public const FILLED_MAP = "minecraft:filled_map";
|
||||
@ -178,6 +200,7 @@ final class ItemTypeNames{
|
||||
public const FLOWER_POT = "minecraft:flower_pot";
|
||||
public const FOX_SPAWN_EGG = "minecraft:fox_spawn_egg";
|
||||
public const FRAME = "minecraft:frame";
|
||||
public const FRIEND_POTTERY_SHERD = "minecraft:friend_pottery_sherd";
|
||||
public const FROG_SPAWN_EGG = "minecraft:frog_spawn_egg";
|
||||
public const GHAST_SPAWN_EGG = "minecraft:ghast_spawn_egg";
|
||||
public const GHAST_TEAR = "minecraft:ghast_tear";
|
||||
@ -211,12 +234,16 @@ final class ItemTypeNames{
|
||||
public const GUARDIAN_SPAWN_EGG = "minecraft:guardian_spawn_egg";
|
||||
public const GUNPOWDER = "minecraft:gunpowder";
|
||||
public const HEART_OF_THE_SEA = "minecraft:heart_of_the_sea";
|
||||
public const HEART_POTTERY_SHERD = "minecraft:heart_pottery_sherd";
|
||||
public const HEARTBREAK_POTTERY_SHERD = "minecraft:heartbreak_pottery_sherd";
|
||||
public const HOGLIN_SPAWN_EGG = "minecraft:hoglin_spawn_egg";
|
||||
public const HONEY_BOTTLE = "minecraft:honey_bottle";
|
||||
public const HONEYCOMB = "minecraft:honeycomb";
|
||||
public const HOPPER = "minecraft:hopper";
|
||||
public const HOPPER_MINECART = "minecraft:hopper_minecart";
|
||||
public const HORSE_SPAWN_EGG = "minecraft:horse_spawn_egg";
|
||||
public const HOST_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:host_armor_trim_smithing_template";
|
||||
public const HOWL_POTTERY_SHERD = "minecraft:howl_pottery_sherd";
|
||||
public const HUSK_SPAWN_EGG = "minecraft:husk_spawn_egg";
|
||||
public const ICE_BOMB = "minecraft:ice_bomb";
|
||||
public const INK_SAC = "minecraft:ink_sac";
|
||||
@ -237,6 +264,7 @@ final class ItemTypeNames{
|
||||
public const JUNGLE_BOAT = "minecraft:jungle_boat";
|
||||
public const JUNGLE_CHEST_BOAT = "minecraft:jungle_chest_boat";
|
||||
public const JUNGLE_DOOR = "minecraft:jungle_door";
|
||||
public const JUNGLE_HANGING_SIGN = "minecraft:jungle_hanging_sign";
|
||||
public const JUNGLE_SIGN = "minecraft:jungle_sign";
|
||||
public const KELP = "minecraft:kelp";
|
||||
public const LAPIS_LAZULI = "minecraft:lapis_lazuli";
|
||||
@ -254,20 +282,25 @@ final class ItemTypeNames{
|
||||
public const LINGERING_POTION = "minecraft:lingering_potion";
|
||||
public const LLAMA_SPAWN_EGG = "minecraft:llama_spawn_egg";
|
||||
public const LODESTONE_COMPASS = "minecraft:lodestone_compass";
|
||||
public const LOG = "minecraft:log";
|
||||
public const LOG2 = "minecraft:log2";
|
||||
public const MAGENTA_DYE = "minecraft:magenta_dye";
|
||||
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";
|
||||
public const MANGROVE_CHEST_BOAT = "minecraft:mangrove_chest_boat";
|
||||
public const MANGROVE_DOOR = "minecraft:mangrove_door";
|
||||
public const MANGROVE_HANGING_SIGN = "minecraft:mangrove_hanging_sign";
|
||||
public const MANGROVE_SIGN = "minecraft:mangrove_sign";
|
||||
public const MEDICINE = "minecraft:medicine";
|
||||
public const MELON_SEEDS = "minecraft:melon_seeds";
|
||||
public const MELON_SLICE = "minecraft:melon_slice";
|
||||
public const MILK_BUCKET = "minecraft:milk_bucket";
|
||||
public const MINECART = "minecraft:minecart";
|
||||
public const MINER_POTTERY_SHERD = "minecraft:miner_pottery_sherd";
|
||||
public const MOJANG_BANNER_PATTERN = "minecraft:mojang_banner_pattern";
|
||||
public const MOOSHROOM_SPAWN_EGG = "minecraft:mooshroom_spawn_egg";
|
||||
public const MOURNER_POTTERY_SHERD = "minecraft:mourner_pottery_sherd";
|
||||
public const MULE_SPAWN_EGG = "minecraft:mule_spawn_egg";
|
||||
public const MUSHROOM_STEW = "minecraft:mushroom_stew";
|
||||
public const MUSIC_DISC_11 = "minecraft:music_disc_11";
|
||||
@ -281,6 +314,7 @@ final class ItemTypeNames{
|
||||
public const MUSIC_DISC_MELLOHI = "minecraft:music_disc_mellohi";
|
||||
public const MUSIC_DISC_OTHERSIDE = "minecraft:music_disc_otherside";
|
||||
public const MUSIC_DISC_PIGSTEP = "minecraft:music_disc_pigstep";
|
||||
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_WAIT = "minecraft:music_disc_wait";
|
||||
@ -303,9 +337,11 @@ final class ItemTypeNames{
|
||||
public const NETHERITE_SCRAP = "minecraft:netherite_scrap";
|
||||
public const NETHERITE_SHOVEL = "minecraft:netherite_shovel";
|
||||
public const NETHERITE_SWORD = "minecraft:netherite_sword";
|
||||
public const NETHERITE_UPGRADE_SMITHING_TEMPLATE = "minecraft:netherite_upgrade_smithing_template";
|
||||
public const NPC_SPAWN_EGG = "minecraft:npc_spawn_egg";
|
||||
public const OAK_BOAT = "minecraft:oak_boat";
|
||||
public const OAK_CHEST_BOAT = "minecraft:oak_chest_boat";
|
||||
public const OAK_HANGING_SIGN = "minecraft:oak_hanging_sign";
|
||||
public const OAK_SIGN = "minecraft:oak_sign";
|
||||
public const OCELOT_SPAWN_EGG = "minecraft:ocelot_spawn_egg";
|
||||
public const ORANGE_DYE = "minecraft:orange_dye";
|
||||
@ -321,6 +357,8 @@ final class ItemTypeNames{
|
||||
public const PIGLIN_SPAWN_EGG = "minecraft:piglin_spawn_egg";
|
||||
public const PILLAGER_SPAWN_EGG = "minecraft:pillager_spawn_egg";
|
||||
public const PINK_DYE = "minecraft:pink_dye";
|
||||
public const PITCHER_POD = "minecraft:pitcher_pod";
|
||||
public const PLENTY_POTTERY_SHERD = "minecraft:plenty_pottery_sherd";
|
||||
public const POISONOUS_POTATO = "minecraft:poisonous_potato";
|
||||
public const POLAR_BEAR_SPAWN_EGG = "minecraft:polar_bear_spawn_egg";
|
||||
public const POPPED_CHORUS_FRUIT = "minecraft:popped_chorus_fruit";
|
||||
@ -330,7 +368,7 @@ final class ItemTypeNames{
|
||||
public const POWDER_SNOW_BUCKET = "minecraft:powder_snow_bucket";
|
||||
public const PRISMARINE_CRYSTALS = "minecraft:prismarine_crystals";
|
||||
public const PRISMARINE_SHARD = "minecraft:prismarine_shard";
|
||||
public const PRIZE_POTTERY_SHARD = "minecraft:prize_pottery_shard";
|
||||
public const PRIZE_POTTERY_SHERD = "minecraft:prize_pottery_sherd";
|
||||
public const PUFFERFISH = "minecraft:pufferfish";
|
||||
public const PUFFERFISH_BUCKET = "minecraft:pufferfish_bucket";
|
||||
public const PUFFERFISH_SPAWN_EGG = "minecraft:pufferfish_spawn_egg";
|
||||
@ -343,6 +381,7 @@ final class ItemTypeNames{
|
||||
public const RABBIT_HIDE = "minecraft:rabbit_hide";
|
||||
public const RABBIT_SPAWN_EGG = "minecraft:rabbit_spawn_egg";
|
||||
public const RABBIT_STEW = "minecraft:rabbit_stew";
|
||||
public const RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:raiser_armor_trim_smithing_template";
|
||||
public const RAPID_FERTILIZER = "minecraft:rapid_fertilizer";
|
||||
public const RAVAGER_SPAWN_EGG = "minecraft:ravager_spawn_egg";
|
||||
public const RAW_COPPER = "minecraft:raw_copper";
|
||||
@ -352,26 +391,34 @@ final class ItemTypeNames{
|
||||
public const RED_DYE = "minecraft:red_dye";
|
||||
public const REDSTONE = "minecraft:redstone";
|
||||
public const REPEATER = "minecraft:repeater";
|
||||
public const RIB_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:rib_armor_trim_smithing_template";
|
||||
public const ROTTEN_FLESH = "minecraft:rotten_flesh";
|
||||
public const SADDLE = "minecraft:saddle";
|
||||
public const SALMON = "minecraft:salmon";
|
||||
public const SALMON_BUCKET = "minecraft:salmon_bucket";
|
||||
public const SALMON_SPAWN_EGG = "minecraft:salmon_spawn_egg";
|
||||
public const SCUTE = "minecraft:scute";
|
||||
public const SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:sentry_armor_trim_smithing_template";
|
||||
public const SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:shaper_armor_trim_smithing_template";
|
||||
public const SHEAF_POTTERY_SHERD = "minecraft:sheaf_pottery_sherd";
|
||||
public const SHEARS = "minecraft:shears";
|
||||
public const SHEEP_SPAWN_EGG = "minecraft:sheep_spawn_egg";
|
||||
public const SHELTER_POTTERY_SHERD = "minecraft:shelter_pottery_sherd";
|
||||
public const SHIELD = "minecraft:shield";
|
||||
public const SHULKER_SHELL = "minecraft:shulker_shell";
|
||||
public const SHULKER_SPAWN_EGG = "minecraft:shulker_spawn_egg";
|
||||
public const SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:silence_armor_trim_smithing_template";
|
||||
public const SILVERFISH_SPAWN_EGG = "minecraft:silverfish_spawn_egg";
|
||||
public const SKELETON_HORSE_SPAWN_EGG = "minecraft:skeleton_horse_spawn_egg";
|
||||
public const SKELETON_SPAWN_EGG = "minecraft:skeleton_spawn_egg";
|
||||
public const SKULL = "minecraft:skull";
|
||||
public const SKULL_BANNER_PATTERN = "minecraft:skull_banner_pattern";
|
||||
public const SKULL_POTTERY_SHARD = "minecraft:skull_pottery_shard";
|
||||
public const SKULL_POTTERY_SHERD = "minecraft:skull_pottery_sherd";
|
||||
public const SLIME_BALL = "minecraft:slime_ball";
|
||||
public const SLIME_SPAWN_EGG = "minecraft:slime_spawn_egg";
|
||||
public const SNIFFER_SPAWN_EGG = "minecraft:sniffer_spawn_egg";
|
||||
public const SNORT_POTTERY_SHERD = "minecraft:snort_pottery_sherd";
|
||||
public const SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:snout_armor_trim_smithing_template";
|
||||
public const SNOW_GOLEM_SPAWN_EGG = "minecraft:snow_golem_spawn_egg";
|
||||
public const SNOWBALL = "minecraft:snowball";
|
||||
public const SOUL_CAMPFIRE = "minecraft:soul_campfire";
|
||||
@ -379,10 +426,12 @@ final class ItemTypeNames{
|
||||
public const SPAWN_EGG = "minecraft:spawn_egg";
|
||||
public const SPIDER_EYE = "minecraft:spider_eye";
|
||||
public const SPIDER_SPAWN_EGG = "minecraft:spider_spawn_egg";
|
||||
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:spire_armor_trim_smithing_template";
|
||||
public const SPLASH_POTION = "minecraft:splash_potion";
|
||||
public const SPRUCE_BOAT = "minecraft:spruce_boat";
|
||||
public const SPRUCE_CHEST_BOAT = "minecraft:spruce_chest_boat";
|
||||
public const SPRUCE_DOOR = "minecraft:spruce_door";
|
||||
public const SPRUCE_HANGING_SIGN = "minecraft:spruce_hanging_sign";
|
||||
public const SPRUCE_SIGN = "minecraft:spruce_sign";
|
||||
public const SPYGLASS = "minecraft:spyglass";
|
||||
public const SQUID_SPAWN_EGG = "minecraft:squid_spawn_egg";
|
||||
@ -401,6 +450,7 @@ final class ItemTypeNames{
|
||||
public const SWEET_BERRIES = "minecraft:sweet_berries";
|
||||
public const TADPOLE_BUCKET = "minecraft:tadpole_bucket";
|
||||
public const TADPOLE_SPAWN_EGG = "minecraft:tadpole_spawn_egg";
|
||||
public const TIDE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:tide_armor_trim_smithing_template";
|
||||
public const TNT_MINECART = "minecraft:tnt_minecart";
|
||||
public const TORCHFLOWER_SEEDS = "minecraft:torchflower_seeds";
|
||||
public const TOTEM_OF_UNDYING = "minecraft:totem_of_undying";
|
||||
@ -411,18 +461,23 @@ final class ItemTypeNames{
|
||||
public const TROPICAL_FISH_SPAWN_EGG = "minecraft:tropical_fish_spawn_egg";
|
||||
public const TURTLE_HELMET = "minecraft:turtle_helmet";
|
||||
public const TURTLE_SPAWN_EGG = "minecraft:turtle_spawn_egg";
|
||||
public const VEX_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:vex_armor_trim_smithing_template";
|
||||
public const VEX_SPAWN_EGG = "minecraft:vex_spawn_egg";
|
||||
public const VILLAGER_SPAWN_EGG = "minecraft:villager_spawn_egg";
|
||||
public const VINDICATOR_SPAWN_EGG = "minecraft:vindicator_spawn_egg";
|
||||
public const WANDERING_TRADER_SPAWN_EGG = "minecraft:wandering_trader_spawn_egg";
|
||||
public const WARD_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:ward_armor_trim_smithing_template";
|
||||
public const WARDEN_SPAWN_EGG = "minecraft:warden_spawn_egg";
|
||||
public const WARPED_DOOR = "minecraft:warped_door";
|
||||
public const WARPED_FUNGUS_ON_A_STICK = "minecraft:warped_fungus_on_a_stick";
|
||||
public const WARPED_HANGING_SIGN = "minecraft:warped_hanging_sign";
|
||||
public const WARPED_SIGN = "minecraft:warped_sign";
|
||||
public const WATER_BUCKET = "minecraft:water_bucket";
|
||||
public const WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wayfinder_armor_trim_smithing_template";
|
||||
public const WHEAT = "minecraft:wheat";
|
||||
public const WHEAT_SEEDS = "minecraft:wheat_seeds";
|
||||
public const WHITE_DYE = "minecraft:white_dye";
|
||||
public const WILD_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wild_armor_trim_smithing_template";
|
||||
public const WITCH_SPAWN_EGG = "minecraft:witch_spawn_egg";
|
||||
public const WITHER_SKELETON_SPAWN_EGG = "minecraft:wither_skeleton_spawn_egg";
|
||||
public const WITHER_SPAWN_EGG = "minecraft:wither_spawn_egg";
|
||||
|
@ -36,6 +36,11 @@ interface RuntimeDataDescriber extends RuntimeEnumDescriber{
|
||||
|
||||
public function horizontalFacing(int &$facing) : void;
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
*/
|
||||
public function facingFlags(array &$faces) : void;
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
*/
|
||||
|
@ -86,6 +86,20 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
*/
|
||||
public function facingFlags(array &$faces) : void{
|
||||
$result = [];
|
||||
foreach(Facing::ALL as $facing){
|
||||
if($this->readBool()){
|
||||
$result[$facing] = $facing;
|
||||
}
|
||||
}
|
||||
|
||||
$faces = $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
*/
|
||||
|
@ -56,6 +56,10 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
|
||||
$this->addBits(2);
|
||||
}
|
||||
|
||||
public function facingFlags(array &$faces) : void{
|
||||
$this->addBits(count(Facing::ALL));
|
||||
}
|
||||
|
||||
public function horizontalFacingFlags(array &$faces) : void{
|
||||
$this->addBits(count(Facing::HORIZONTAL));
|
||||
}
|
||||
|
@ -85,6 +85,16 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
*/
|
||||
public function facingFlags(array &$faces) : void{
|
||||
$uniqueFaces = array_flip($faces);
|
||||
foreach(Facing::ALL as $facing){
|
||||
$this->writeBool(isset($uniqueFaces[$facing]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
*/
|
||||
|
@ -130,10 +130,11 @@ trait RuntimeEnumDeserializerTrait{
|
||||
$value = match($this->readInt(3)){
|
||||
0 => \pocketmine\block\utils\MobHeadType::CREEPER(),
|
||||
1 => \pocketmine\block\utils\MobHeadType::DRAGON(),
|
||||
2 => \pocketmine\block\utils\MobHeadType::PLAYER(),
|
||||
3 => \pocketmine\block\utils\MobHeadType::SKELETON(),
|
||||
4 => \pocketmine\block\utils\MobHeadType::WITHER_SKELETON(),
|
||||
5 => \pocketmine\block\utils\MobHeadType::ZOMBIE(),
|
||||
2 => \pocketmine\block\utils\MobHeadType::PIGLIN(),
|
||||
3 => \pocketmine\block\utils\MobHeadType::PLAYER(),
|
||||
4 => \pocketmine\block\utils\MobHeadType::SKELETON(),
|
||||
5 => \pocketmine\block\utils\MobHeadType::WITHER_SKELETON(),
|
||||
6 => \pocketmine\block\utils\MobHeadType::ZOMBIE(),
|
||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for MobHeadType")
|
||||
};
|
||||
}
|
||||
|
@ -130,10 +130,11 @@ trait RuntimeEnumSerializerTrait{
|
||||
$this->writeInt(3, match($value){
|
||||
\pocketmine\block\utils\MobHeadType::CREEPER() => 0,
|
||||
\pocketmine\block\utils\MobHeadType::DRAGON() => 1,
|
||||
\pocketmine\block\utils\MobHeadType::PLAYER() => 2,
|
||||
\pocketmine\block\utils\MobHeadType::SKELETON() => 3,
|
||||
\pocketmine\block\utils\MobHeadType::WITHER_SKELETON() => 4,
|
||||
\pocketmine\block\utils\MobHeadType::ZOMBIE() => 5,
|
||||
\pocketmine\block\utils\MobHeadType::PIGLIN() => 2,
|
||||
\pocketmine\block\utils\MobHeadType::PLAYER() => 3,
|
||||
\pocketmine\block\utils\MobHeadType::SKELETON() => 4,
|
||||
\pocketmine\block\utils\MobHeadType::WITHER_SKELETON() => 5,
|
||||
\pocketmine\block\utils\MobHeadType::ZOMBIE() => 6,
|
||||
default => throw new \pocketmine\utils\AssumptionFailedError("All MobHeadType cases should be covered")
|
||||
});
|
||||
}
|
||||
|
@ -302,8 +302,9 @@ final class ItemTypeIds{
|
||||
public const MEDICINE = 20263;
|
||||
public const MANGROVE_BOAT = 20264;
|
||||
public const GLOW_BERRIES = 20265;
|
||||
public const CHERRY_SIGN = 20266;
|
||||
|
||||
public const FIRST_UNUSED_ITEM_ID = 20266;
|
||||
public const FIRST_UNUSED_ITEM_ID = 20267;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||
|
||||
|
@ -208,6 +208,19 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("cauldron", fn() => Blocks::CAULDRON());
|
||||
$result->registerBlock("cave_vines", fn() => Blocks::CAVE_VINES());
|
||||
$result->registerBlock("chain", fn() => Blocks::CHAIN());
|
||||
$result->registerBlock("cherry_button", fn() => Blocks::CHERRY_BUTTON());
|
||||
$result->registerBlock("cherry_door", fn() => Blocks::CHERRY_DOOR());
|
||||
$result->registerBlock("cherry_fence", fn() => Blocks::CHERRY_FENCE());
|
||||
$result->registerBlock("cherry_fence_gate", fn() => Blocks::CHERRY_FENCE_GATE());
|
||||
$result->registerBlock("cherry_leaves", fn() => Blocks::CHERRY_LEAVES());
|
||||
$result->registerBlock("cherry_log", fn() => Blocks::CHERRY_LOG());
|
||||
$result->registerBlock("cherry_planks", fn() => Blocks::CHERRY_PLANKS());
|
||||
$result->registerBlock("cherry_pressure_plate", fn() => Blocks::CHERRY_PRESSURE_PLATE());
|
||||
$result->registerBlock("cherry_sign", fn() => Blocks::CHERRY_SIGN());
|
||||
$result->registerBlock("cherry_slab", fn() => Blocks::CHERRY_SLAB());
|
||||
$result->registerBlock("cherry_stairs", fn() => Blocks::CHERRY_STAIRS());
|
||||
$result->registerBlock("cherry_trapdoor", fn() => Blocks::CHERRY_TRAPDOOR());
|
||||
$result->registerBlock("cherry_wood", fn() => Blocks::CHERRY_WOOD());
|
||||
$result->registerBlock("chemical_heat", fn() => Blocks::CHEMICAL_HEAT());
|
||||
$result->registerBlock("chemistry_table", fn() => Blocks::COMPOUND_CREATOR());
|
||||
$result->registerBlock("chest", fn() => Blocks::CHEST());
|
||||
@ -647,6 +660,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("glowingobsidian", fn() => Blocks::GLOWING_OBSIDIAN());
|
||||
$result->registerBlock("glowstone", fn() => Blocks::GLOWSTONE());
|
||||
$result->registerBlock("glowstone_block", fn() => Blocks::GLOWSTONE());
|
||||
$result->registerBlock("glow_lichen", fn() => Blocks::GLOW_LICHEN());
|
||||
$result->registerBlock("gold", fn() => Blocks::GOLD());
|
||||
$result->registerBlock("gold_block", fn() => Blocks::GOLD());
|
||||
$result->registerBlock("gold_ore", fn() => Blocks::GOLD_ORE());
|
||||
@ -842,6 +856,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("packed_mud", fn() => Blocks::PACKED_MUD());
|
||||
$result->registerBlock("peony", fn() => Blocks::PEONY());
|
||||
$result->registerBlock("pink_tulip", fn() => Blocks::PINK_TULIP());
|
||||
$result->registerBlock("piglin_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PIGLIN()));
|
||||
$result->registerBlock("plank", fn() => Blocks::OAK_PLANKS());
|
||||
$result->registerBlock("planks", fn() => Blocks::OAK_PLANKS());
|
||||
$result->registerBlock("player_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PLAYER()));
|
||||
@ -1064,6 +1079,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("trunk2", fn() => Blocks::ACACIA_LOG()->setStripped(false));
|
||||
$result->registerBlock("tuff", fn() => Blocks::TUFF());
|
||||
$result->registerBlock("twisting_vines", fn() => Blocks::TWISTING_VINES());
|
||||
$result->registerBlock("underwater_tnt", fn() => Blocks::TNT()->setWorksUnderwater(true));
|
||||
$result->registerBlock("underwater_torch", fn() => Blocks::UNDERWATER_TORCH());
|
||||
$result->registerBlock("undyed_shulker_box", fn() => Blocks::SHULKER_BOX());
|
||||
$result->registerBlock("unlit_redstone_torch", fn() => Blocks::REDSTONE_TORCH());
|
||||
|
@ -114,6 +114,7 @@ use pocketmine\world\World;
|
||||
* @method static Item CHEMICAL_SULPHATE()
|
||||
* @method static Item CHEMICAL_TUNGSTEN_CHLORIDE()
|
||||
* @method static Item CHEMICAL_WATER()
|
||||
* @method static ItemBlockWallOrFloor CHERRY_SIGN()
|
||||
* @method static ChorusFruit CHORUS_FRUIT()
|
||||
* @method static Item CLAY()
|
||||
* @method static Clock CLOCK()
|
||||
@ -362,6 +363,7 @@ final class VanillaItems{
|
||||
self::register("bucket", new Bucket(new IID(Ids::BUCKET), "Bucket"));
|
||||
self::register("carrot", new Carrot(new IID(Ids::CARROT), "Carrot"));
|
||||
self::register("charcoal", new Coal(new IID(Ids::CHARCOAL), "Charcoal"));
|
||||
self::register("cherry_sign", new ItemBlockWallOrFloor(new IID(Ids::CHERRY_SIGN), Blocks::CHERRY_SIGN(), Blocks::CHERRY_WALL_SIGN()));
|
||||
self::register("chemical_aluminium_oxide", new Item(new IID(Ids::CHEMICAL_ALUMINIUM_OXIDE), "Aluminium Oxide"));
|
||||
self::register("chemical_ammonia", new Item(new IID(Ids::CHEMICAL_AMMONIA), "Ammonia"));
|
||||
self::register("chemical_barium_sulphate", new Item(new IID(Ids::CHEMICAL_BARIUM_SULPHATE), "Barium Sulphate"));
|
||||
|
@ -39,7 +39,6 @@ use pocketmine\world\format\io\FastChunkSerializer;
|
||||
|
||||
class ChunkRequestTask extends AsyncTask{
|
||||
private const TLS_KEY_PROMISE = "promise";
|
||||
private const TLS_KEY_ERROR_HOOK = "errorHook";
|
||||
|
||||
protected string $chunk;
|
||||
protected int $chunkX;
|
||||
@ -48,10 +47,7 @@ class ChunkRequestTask extends AsyncTask{
|
||||
protected NonThreadSafeValue $compressor;
|
||||
private string $tiles;
|
||||
|
||||
/**
|
||||
* @phpstan-param (\Closure() : void)|null $onError
|
||||
*/
|
||||
public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatchPromise $promise, Compressor $compressor, ?\Closure $onError = null){
|
||||
public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatchPromise $promise, Compressor $compressor){
|
||||
$this->compressor = new NonThreadSafeValue($compressor);
|
||||
|
||||
$this->chunk = FastChunkSerializer::serializeTerrain($chunk);
|
||||
@ -60,7 +56,6 @@ class ChunkRequestTask extends AsyncTask{
|
||||
$this->tiles = ChunkSerializer::serializeTiles($chunk);
|
||||
|
||||
$this->storeLocal(self::TLS_KEY_PROMISE, $promise);
|
||||
$this->storeLocal(self::TLS_KEY_ERROR_HOOK, $onError);
|
||||
}
|
||||
|
||||
public function onRun() : void{
|
||||
@ -75,17 +70,6 @@ class ChunkRequestTask extends AsyncTask{
|
||||
$this->setResult($this->compressor->deserialize()->compress($stream->getBuffer()));
|
||||
}
|
||||
|
||||
public function onError() : void{
|
||||
/**
|
||||
* @var \Closure|null $hook
|
||||
* @phpstan-var (\Closure() : void)|null $hook
|
||||
*/
|
||||
$hook = $this->fetchLocal(self::TLS_KEY_ERROR_HOOK);
|
||||
if($hook !== null){
|
||||
$hook();
|
||||
}
|
||||
}
|
||||
|
||||
public function onCompletion() : void{
|
||||
/** @var CompressBatchPromise $promise */
|
||||
$promise = $this->fetchLocal(self::TLS_KEY_PROMISE);
|
||||
|
@ -51,7 +51,7 @@ use const SORT_NUMERIC;
|
||||
final class StandardEntityEventBroadcaster implements EntityEventBroadcaster{
|
||||
|
||||
public function __construct(
|
||||
private StandardPacketBroadcaster $broadcaster,
|
||||
private PacketBroadcaster $broadcaster,
|
||||
private TypeConverter $typeConverter
|
||||
){}
|
||||
|
||||
|
9
src/network/mcpe/cache/ChunkCache.php
vendored
9
src/network/mcpe/cache/ChunkCache.php
vendored
@ -118,14 +118,7 @@ class ChunkCache implements ChunkListener{
|
||||
$chunkZ,
|
||||
$chunk,
|
||||
$this->caches[$chunkHash],
|
||||
$this->compressor,
|
||||
function() use ($chunkHash, $chunkX, $chunkZ) : void{
|
||||
$this->world->getLogger()->error("Failed preparing chunk $chunkX $chunkZ, retrying");
|
||||
|
||||
if(isset($this->caches[$chunkHash])){
|
||||
$this->restartPendingRequest($chunkX, $chunkZ);
|
||||
}
|
||||
}
|
||||
$this->compressor
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -24,15 +24,17 @@ declare(strict_types=1);
|
||||
namespace pocketmine\scheduler;
|
||||
|
||||
use pmmp\thread\Thread as NativeThread;
|
||||
use pmmp\thread\ThreadSafeArray;
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\thread\log\ThreadSafeLogger;
|
||||
use pocketmine\thread\ThreadSafeClassLoader;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function spl_object_id;
|
||||
use function time;
|
||||
use const PHP_INT_MAX;
|
||||
@ -130,6 +132,8 @@ class AsyncPool{
|
||||
foreach($this->workerStartHooks as $hook){
|
||||
$hook($workerId);
|
||||
}
|
||||
}else{
|
||||
$this->checkCrashedWorker($workerId, null);
|
||||
}
|
||||
|
||||
return $this->workers[$workerId];
|
||||
@ -146,7 +150,6 @@ class AsyncPool{
|
||||
throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
|
||||
}
|
||||
|
||||
$task->progressUpdates = new ThreadSafeArray();
|
||||
$task->setSubmitted();
|
||||
|
||||
$this->getWorker($worker)->submit($task);
|
||||
@ -199,6 +202,28 @@ class AsyncPool{
|
||||
return $worker;
|
||||
}
|
||||
|
||||
private function checkCrashedWorker(int $workerId, ?AsyncTask $crashedTask) : void{
|
||||
$entry = $this->workers[$workerId];
|
||||
if($entry->worker->isTerminated()){
|
||||
if($crashedTask === null){
|
||||
foreach($entry->tasks as $task){
|
||||
if($task->isTerminated()){
|
||||
$crashedTask = $task;
|
||||
break;
|
||||
}elseif(!$task->isFinished()){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($crashedTask !== null){
|
||||
$message = "Worker $workerId crashed while running task " . get_class($crashedTask) . "#" . spl_object_id($crashedTask);
|
||||
}else{
|
||||
$message = "Worker $workerId crashed for unknown reason";
|
||||
}
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects finished and/or crashed tasks from the workers, firing their on-completion hooks where appropriate.
|
||||
*
|
||||
@ -231,9 +256,9 @@ class AsyncPool{
|
||||
if($task->isFinished()){ //make sure the task actually executed before trying to collect
|
||||
$queue->dequeue();
|
||||
|
||||
if($task->isCrashed()){
|
||||
$this->logger->critical("Could not execute asynchronous task " . (new \ReflectionClass($task))->getShortName() . ": Task crashed");
|
||||
$task->onError();
|
||||
if($task->isTerminated()){
|
||||
$this->checkCrashedWorker($worker, $task);
|
||||
throw new AssumptionFailedError("checkCrashedWorker() should have thrown an exception, making this unreachable");
|
||||
}elseif(!$task->hasCancelledRun()){
|
||||
/*
|
||||
* It's possible for a task to submit a progress update and then finish before the progress
|
||||
@ -244,11 +269,13 @@ class AsyncPool{
|
||||
* lost. Thus, it's necessary to do one last check here to make sure all progress updates have
|
||||
* been consumed before completing.
|
||||
*/
|
||||
$task->checkProgressUpdates();
|
||||
$task->onCompletion();
|
||||
$this->checkTaskProgressUpdates($task);
|
||||
Timings::getAsyncTaskCompletionTimings($task)->time(function() use ($task) : void{
|
||||
$task->onCompletion();
|
||||
});
|
||||
}
|
||||
}else{
|
||||
$task->checkProgressUpdates();
|
||||
$this->checkTaskProgressUpdates($task);
|
||||
$more = true;
|
||||
break; //current task is still running, skip to next worker
|
||||
}
|
||||
@ -296,4 +323,10 @@ class AsyncPool{
|
||||
}
|
||||
$this->workers = [];
|
||||
}
|
||||
|
||||
private function checkTaskProgressUpdates(AsyncTask $task) : void{
|
||||
Timings::getAsyncTaskProgressUpdateTimings($task)->time(function() use ($task) : void{
|
||||
$task->checkProgressUpdates();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -61,34 +61,27 @@ use function spl_object_id;
|
||||
*/
|
||||
abstract class AsyncTask extends Runnable{
|
||||
/**
|
||||
* @var \ArrayObject|mixed[]|null object hash => mixed data
|
||||
* @phpstan-var \ArrayObject<int, array<string, mixed>>|null
|
||||
* @var mixed[][] object hash => mixed data
|
||||
* @phpstan-var array<int, array<string, mixed>>
|
||||
*
|
||||
* Used to store objects which are only needed on one thread and should not be serialized.
|
||||
* Used to store thread-local data to be used by onCompletion().
|
||||
*/
|
||||
private static ?\ArrayObject $threadLocalStorage = null;
|
||||
private static array $threadLocalStorage = [];
|
||||
|
||||
/** @phpstan-var ThreadSafeArray<int, string> */
|
||||
public ThreadSafeArray $progressUpdates;
|
||||
/** @phpstan-var ThreadSafeArray<int, string>|null */
|
||||
private ?ThreadSafeArray $progressUpdates = null;
|
||||
|
||||
private ThreadSafe|string|int|bool|null|float $result = null;
|
||||
private bool $cancelRun = false;
|
||||
private bool $submitted = false;
|
||||
|
||||
private bool $crashed = false;
|
||||
private bool $finished = false;
|
||||
|
||||
public function run() : void{
|
||||
$this->result = null;
|
||||
|
||||
if(!$this->cancelRun){
|
||||
try{
|
||||
$this->onRun();
|
||||
}catch(\Throwable $e){
|
||||
$this->crashed = true;
|
||||
|
||||
\GlobalLogger::get()->logException($e);
|
||||
}
|
||||
$this->onRun();
|
||||
}
|
||||
|
||||
$this->finished = true;
|
||||
@ -97,8 +90,11 @@ abstract class AsyncTask extends Runnable{
|
||||
$worker->getNotifier()->wakeupSleeper();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isCrashed() : bool{
|
||||
return $this->crashed || $this->isTerminated();
|
||||
return $this->isTerminated();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +102,7 @@ abstract class AsyncTask extends Runnable{
|
||||
* because it is not true prior to task execution.
|
||||
*/
|
||||
public function isFinished() : bool{
|
||||
return $this->finished || $this->isCrashed();
|
||||
return $this->finished || $this->isTerminated();
|
||||
}
|
||||
|
||||
public function hasResult() : bool{
|
||||
@ -163,15 +159,22 @@ abstract class AsyncTask extends Runnable{
|
||||
* @param mixed $progress A value that can be safely serialize()'ed.
|
||||
*/
|
||||
public function publishProgress(mixed $progress) : void{
|
||||
$this->progressUpdates[] = igbinary_serialize($progress) ?? throw new \InvalidArgumentException("Progress must be serializable");
|
||||
$progressUpdates = $this->progressUpdates;
|
||||
if($progressUpdates === null){
|
||||
$progressUpdates = $this->progressUpdates = new ThreadSafeArray();
|
||||
}
|
||||
$progressUpdates[] = igbinary_serialize($progress) ?? throw new \InvalidArgumentException("Progress must be serializable");
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Only call from AsyncPool.php on the main thread
|
||||
*/
|
||||
public function checkProgressUpdates() : void{
|
||||
while(($progress = $this->progressUpdates->shift()) !== null){
|
||||
$this->onProgressUpdate(igbinary_unserialize($progress));
|
||||
$progressUpdates = $this->progressUpdates;
|
||||
if($progressUpdates !== null){
|
||||
while(($progress = $progressUpdates->shift()) !== null){
|
||||
$this->onProgressUpdate(igbinary_unserialize($progress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,8 +191,7 @@ abstract class AsyncTask extends Runnable{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the main thread when the async task experiences an error during onRun(). Use this for things like
|
||||
* promise rejection.
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
public function onError() : void{
|
||||
|
||||
@ -210,15 +212,6 @@ abstract class AsyncTask extends Runnable{
|
||||
* from.
|
||||
*/
|
||||
protected function storeLocal(string $key, mixed $complexData) : void{
|
||||
if(self::$threadLocalStorage === null){
|
||||
/*
|
||||
* It's necessary to use an object (not array) here because pthreads is stupid. Non-default array statics
|
||||
* will be inherited when task classes are copied to the worker thread, which would cause unwanted
|
||||
* inheritance of primitive thread-locals, which we really don't want for various reasons.
|
||||
* It won't try to inherit objects though, so this is the easiest solution.
|
||||
*/
|
||||
self::$threadLocalStorage = new \ArrayObject();
|
||||
}
|
||||
self::$threadLocalStorage[spl_object_id($this)][$key] = $complexData;
|
||||
}
|
||||
|
||||
@ -234,7 +227,7 @@ abstract class AsyncTask extends Runnable{
|
||||
*/
|
||||
protected function fetchLocal(string $key){
|
||||
$id = spl_object_id($this);
|
||||
if(self::$threadLocalStorage === null || !isset(self::$threadLocalStorage[$id][$key])){
|
||||
if(!isset(self::$threadLocalStorage[$id][$key])){
|
||||
throw new \InvalidArgumentException("No matching thread-local data found on this thread");
|
||||
}
|
||||
|
||||
@ -243,18 +236,7 @@ abstract class AsyncTask extends Runnable{
|
||||
|
||||
final public function __destruct(){
|
||||
$this->reallyDestruct();
|
||||
if(self::$threadLocalStorage !== null && isset(self::$threadLocalStorage[$h = spl_object_id($this)])){
|
||||
//Beware changing this code!
|
||||
//This code may cause the GC to be triggered, causing destruction of other AsyncTasks (which may or may not
|
||||
//have been indirectly referenced by the TLS).
|
||||
//This may cause the code to be re-entered from a different context unexpectedly, causing a crash if handled
|
||||
//incorrectly.
|
||||
if(self::$threadLocalStorage->count() === 1){
|
||||
self::$threadLocalStorage = null;
|
||||
}else{
|
||||
unset(self::$threadLocalStorage[$h]);
|
||||
}
|
||||
}
|
||||
unset(self::$threadLocalStorage[spl_object_id($this)]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,7 @@ use pocketmine\thread\Worker;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use function gc_enable;
|
||||
use function ini_set;
|
||||
use function set_exception_handler;
|
||||
|
||||
class AsyncWorker extends Worker{
|
||||
/** @var mixed[] */
|
||||
@ -67,6 +68,10 @@ class AsyncWorker extends Worker{
|
||||
}
|
||||
|
||||
$this->saveToThreadStore(self::TLS_KEY_NOTIFIER, $this->sleeperEntry->createNotifier());
|
||||
|
||||
set_exception_handler(function(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
});
|
||||
}
|
||||
|
||||
public function getLogger() : ThreadSafeLogger{
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\event\Event;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\ServerboundPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\scheduler\TaskHandler;
|
||||
use function get_class;
|
||||
use function str_starts_with;
|
||||
@ -115,6 +116,17 @@ abstract class Timings{
|
||||
/** @var TimingsHandler[][] */
|
||||
private static array $eventHandlers = [];
|
||||
|
||||
private static TimingsHandler $asyncTaskProgressUpdateParent;
|
||||
private static TimingsHandler $asyncTaskCompletionParent;
|
||||
private static TimingsHandler $asyncTaskErrorParent;
|
||||
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $asyncTaskProgressUpdate = [];
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $asyncTaskCompletion = [];
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $asyncTaskError = [];
|
||||
|
||||
public static function init() : void{
|
||||
if(self::$initialized){
|
||||
return;
|
||||
@ -168,7 +180,11 @@ abstract class Timings{
|
||||
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity", group: self::GROUP_BREAKDOWN);
|
||||
|
||||
self::$schedulerSync = new TimingsHandler("Scheduler - Sync Tasks", group: self::GROUP_BREAKDOWN);
|
||||
|
||||
self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks", group: self::GROUP_BREAKDOWN);
|
||||
self::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
||||
self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
||||
self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
||||
|
||||
self::$playerCommand = new TimingsHandler("Player Command", group: self::GROUP_BREAKDOWN);
|
||||
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache", group: self::GROUP_BREAKDOWN);
|
||||
@ -299,4 +315,46 @@ abstract class Timings{
|
||||
|
||||
return self::$eventHandlers[$event][$handlerName];
|
||||
}
|
||||
|
||||
public static function getAsyncTaskProgressUpdateTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{
|
||||
$taskClass = $task::class;
|
||||
if(!isset(self::$asyncTaskProgressUpdate[$taskClass])){
|
||||
self::init();
|
||||
self::$asyncTaskProgressUpdate[$taskClass] = new TimingsHandler(
|
||||
"AsyncTask - " . self::shortenCoreClassName($taskClass, "pocketmine\\") . " - Progress Updates",
|
||||
self::$asyncTaskProgressUpdateParent,
|
||||
$group
|
||||
);
|
||||
}
|
||||
|
||||
return self::$asyncTaskProgressUpdate[$taskClass];
|
||||
}
|
||||
|
||||
public static function getAsyncTaskCompletionTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{
|
||||
$taskClass = $task::class;
|
||||
if(!isset(self::$asyncTaskCompletion[$taskClass])){
|
||||
self::init();
|
||||
self::$asyncTaskCompletion[$taskClass] = new TimingsHandler(
|
||||
"AsyncTask - " . self::shortenCoreClassName($taskClass, "pocketmine\\") . " - Completion Handler",
|
||||
self::$asyncTaskCompletionParent,
|
||||
$group
|
||||
);
|
||||
}
|
||||
|
||||
return self::$asyncTaskCompletion[$taskClass];
|
||||
}
|
||||
|
||||
public static function getAsyncTaskErrorTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{
|
||||
$taskClass = $task::class;
|
||||
if(!isset(self::$asyncTaskError[$taskClass])){
|
||||
self::init();
|
||||
self::$asyncTaskError[$taskClass] = new TimingsHandler(
|
||||
"AsyncTask - " . self::shortenCoreClassName($taskClass, "pocketmine\\") . " - Error Handler",
|
||||
self::$asyncTaskErrorParent,
|
||||
$group
|
||||
);
|
||||
}
|
||||
|
||||
return self::$asyncTaskError[$taskClass];
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ final class GlobalBlockStateHandlers{
|
||||
BlockIdMetaUpgrader::loadFromString(
|
||||
Filesystem::fileGetContents(Path::join(
|
||||
BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH,
|
||||
'1.12.0_to_1.18.10_blockstate_map.bin'
|
||||
'id_meta_to_nbt/1.12.0.bin'
|
||||
)),
|
||||
LegacyBlockIdToStringIdMap::getInstance(),
|
||||
$blockStateUpgrader
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_unique;
|
||||
use function max;
|
||||
|
||||
@ -43,4 +44,14 @@ class BlockTypeIdsTest extends TestCase{
|
||||
|
||||
self::assertSameSize($idTable, array_unique($idTable), "Every BlockTypeID must be unique");
|
||||
}
|
||||
|
||||
public function testVanillaBlocksParity() : void{
|
||||
$reflect = new \ReflectionClass(BlockTypeIds::class);
|
||||
|
||||
foreach(Utils::stringifyKeys(VanillaBlocks::getAll()) as $name => $block){
|
||||
$expected = $block->getTypeId();
|
||||
$actual = $reflect->getConstant($name);
|
||||
self::assertSame($expected, $actual, "VanillaBlocks::$name() does not match BlockTypeIds::$name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\item;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_unique;
|
||||
use function max;
|
||||
|
||||
@ -43,4 +44,17 @@ class ItemTypeIdsTest extends TestCase{
|
||||
|
||||
self::assertSameSize($idTable, array_unique($idTable), "Every ItemTypeID must be unique");
|
||||
}
|
||||
|
||||
public function testVanillaItemsParity() : void{
|
||||
$reflect = new \ReflectionClass(ItemTypeIds::class);
|
||||
|
||||
foreach(Utils::stringifyKeys(VanillaItems::getAll()) as $name => $item){
|
||||
if($item instanceof ItemBlock){
|
||||
continue;
|
||||
}
|
||||
$expected = $item->getTypeId();
|
||||
$actual = $reflect->getConstant($name);
|
||||
self::assertSame($expected, $actual, "VanillaItems::$name() type ID does not match ItemTypeIds::$name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,20 +26,29 @@ namespace pocketmine\tools\generate_blockstate_upgrade_schema;
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchema;
|
||||
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchemaBlockRemap;
|
||||
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchemaFlattenedName;
|
||||
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchemaUtils;
|
||||
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchemaValueRemap;
|
||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\nbt\tag\Tag;
|
||||
use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_filter;
|
||||
use function array_key_first;
|
||||
use function array_merge;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function explode;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function json_encode;
|
||||
use function ksort;
|
||||
use function usort;
|
||||
@ -56,9 +65,22 @@ class BlockStateMapping{
|
||||
){}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag[] $properties
|
||||
* @phpstan-param array<string, Tag> $properties
|
||||
*/
|
||||
function encodeOrderedProperties(array $properties) : string{
|
||||
ksort($properties, SORT_STRING);
|
||||
return implode("", array_map(fn(Tag $tag) => encodeProperty($tag), array_values($properties)));
|
||||
}
|
||||
|
||||
function encodeProperty(Tag $tag) : string{
|
||||
return (new LittleEndianNbtSerializer())->write(new TreeRoot($tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BlockStateMapping[][]
|
||||
* @phpstan-return array<string, list<BlockStateMapping>>
|
||||
* @phpstan-return array<string, array<string, BlockStateMapping>>
|
||||
*/
|
||||
function loadUpgradeTable(string $file, bool $reverse) : array{
|
||||
$contents = Filesystem::fileGetContents($file);
|
||||
@ -72,7 +94,7 @@ function loadUpgradeTable(string $file, bool $reverse) : array{
|
||||
$old = BlockStateData::fromNbt($reverse ? $newTag : $oldTag);
|
||||
$new = BlockStateData::fromNbt($reverse ? $oldTag : $newTag);
|
||||
|
||||
$result[$old->getName()][] = new BlockStateMapping(
|
||||
$result[$old->getName()][encodeOrderedProperties($old->getStates())] = new BlockStateMapping(
|
||||
$old,
|
||||
$new
|
||||
);
|
||||
@ -82,111 +104,176 @@ function loadUpgradeTable(string $file, bool $reverse) : array{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param true[] $removedPropertiesCache
|
||||
* @param Tag[][] $remappedPropertyValuesCache
|
||||
* @phpstan-param array<string, true> $removedPropertiesCache
|
||||
* @phpstan-param array<string, array<string, Tag>> $remappedPropertyValuesCache
|
||||
* @param BlockStateData[] $states
|
||||
* @phpstan-param array<string, BlockStateData> $states
|
||||
*
|
||||
* @return Tag[][]
|
||||
* @phpstan-return array<string, array<string, Tag>>
|
||||
*/
|
||||
function processState(BlockStateData $old, BlockStateData $new, BlockStateUpgradeSchema $result, array &$removedPropertiesCache, array &$remappedPropertyValuesCache) : void{
|
||||
function buildStateGroupSchema(array $states) : ?array{
|
||||
$first = $states[array_key_first($states)];
|
||||
|
||||
//new and old IDs are the same; compare states
|
||||
$oldName = $old->getName();
|
||||
$properties = [];
|
||||
foreach(Utils::stringifyKeys($first->getStates()) as $propertyName => $propertyValue){
|
||||
$properties[$propertyName][encodeProperty($propertyValue)] = $propertyValue;
|
||||
}
|
||||
foreach($states as $state){
|
||||
if(count($state->getStates()) !== count($properties)){
|
||||
return null;
|
||||
}
|
||||
foreach(Utils::stringifyKeys($state->getStates()) as $propertyName => $propertyValue){
|
||||
if(!isset($properties[$propertyName])){
|
||||
return null;
|
||||
}
|
||||
$properties[$propertyName][encodeProperty($propertyValue)] = $propertyValue;
|
||||
}
|
||||
}
|
||||
|
||||
$oldStates = $old->getStates();
|
||||
$newStates = $new->getStates();
|
||||
return $properties;
|
||||
}
|
||||
|
||||
$propertyRemoved = [];
|
||||
$propertyAdded = [];
|
||||
foreach(Utils::stringifyKeys($oldStates) as $propertyName => $oldProperty){
|
||||
$newProperty = $new->getState($propertyName);
|
||||
if($newProperty === null){
|
||||
$propertyRemoved[$propertyName] = $oldProperty;
|
||||
}elseif(!$newProperty->equals($oldProperty)){
|
||||
if(!isset($remappedPropertyValuesCache[$propertyName][$oldProperty->getValue()])){
|
||||
$result->remappedPropertyValues[$oldName][$propertyName][] = new BlockStateUpgradeSchemaValueRemap(
|
||||
$oldProperty,
|
||||
$newProperty
|
||||
);
|
||||
$remappedPropertyValuesCache[$propertyName][$oldProperty->getValue()] = $newProperty;
|
||||
/**
|
||||
* @param BlockStateMapping[] $upgradeTable
|
||||
* @phpstan-param array<string, BlockStateMapping> $upgradeTable
|
||||
*/
|
||||
function processStateGroup(string $oldName, array $upgradeTable, BlockStateUpgradeSchema $result) : bool{
|
||||
$newProperties = buildStateGroupSchema(array_map(fn(BlockStateMapping $m) => $m->new, $upgradeTable));
|
||||
if($newProperties === null){
|
||||
\GlobalLogger::get()->warning("New states for $oldName don't all have the same set of properties - processing as remaps instead");
|
||||
return false;
|
||||
}
|
||||
$oldProperties = buildStateGroupSchema(array_map(fn(BlockStateMapping $m) => $m->old, $upgradeTable));
|
||||
if($oldProperties === null){
|
||||
//TODO: not sure if this is actually required - we may be able to apply some transformations even if the states are not consistent
|
||||
//however, this should never normally occur anyway
|
||||
\GlobalLogger::get()->warning("Old states for $oldName don't all have the same set of properties - processing as remaps instead");
|
||||
return false;
|
||||
}
|
||||
|
||||
$remappedPropertyValues = [];
|
||||
$addedProperties = [];
|
||||
$removedProperties = [];
|
||||
$renamedProperties = [];
|
||||
|
||||
foreach(Utils::stringifyKeys($newProperties) as $newPropertyName => $newPropertyValues){
|
||||
if(count($newPropertyValues) === 1){
|
||||
$newPropertyValue = $newPropertyValues[array_key_first($newPropertyValues)];
|
||||
if(isset($oldProperties[$newPropertyName])){
|
||||
//all the old values for this property were mapped to the same new value
|
||||
//it would be more space-efficient to represent this as a remove+add, but we can't guarantee that the
|
||||
//removal of the old value will be done before the addition of the new value
|
||||
foreach($oldProperties[$newPropertyName] as $oldPropertyValue){
|
||||
$remappedPropertyValues[$newPropertyName][encodeProperty($oldPropertyValue)] = $newPropertyValue;
|
||||
}
|
||||
}else{
|
||||
//this property has no relation to any property value in any of the old states - it's a new property
|
||||
$addedProperties[$newPropertyName] = $newPropertyValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach(Utils::stringifyKeys($newStates) as $propertyName => $value){
|
||||
if($old->getState($propertyName) === null){
|
||||
$propertyAdded[$propertyName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if(count($propertyAdded) === 0 && count($propertyRemoved) === 0){
|
||||
return;
|
||||
}
|
||||
if(count($propertyAdded) === 1 && count($propertyRemoved) === 1){
|
||||
$propertyOldName = array_key_first($propertyRemoved);
|
||||
$propertyNewName = array_key_first($propertyAdded);
|
||||
|
||||
$propertyOldValue = $propertyRemoved[$propertyOldName];
|
||||
$propertyNewValue = $propertyAdded[$propertyNewName];
|
||||
|
||||
$existingPropertyValueMap = $remappedPropertyValuesCache[$propertyOldName][$propertyOldValue->getValue()] ?? null;
|
||||
if($propertyOldName !== $propertyNewName){
|
||||
if(!$propertyOldValue->equals($propertyNewValue) && $existingPropertyValueMap === null){
|
||||
\GlobalLogger::get()->warning("warning: guessing that $oldName has $propertyOldName renamed to $propertyNewName with a value map of $propertyOldValue mapped to $propertyNewValue");;
|
||||
}
|
||||
//this is a guess; it might not be reliable if the value changed as well
|
||||
//this will probably never be an issue, but it might rear its ugly head in the future
|
||||
$result->renamedProperties[$oldName][$propertyOldName] = $propertyNewName;
|
||||
}
|
||||
if(!$propertyOldValue->equals($propertyNewValue)){
|
||||
$mapped = true;
|
||||
if($existingPropertyValueMap !== null && !$existingPropertyValueMap->equals($propertyNewValue)){
|
||||
if($existingPropertyValueMap->equals($propertyOldValue)){
|
||||
\GlobalLogger::get()->warning("warning: guessing that the value $propertyOldValue of $propertyNewValue did not change");;
|
||||
$mapped = false;
|
||||
}else{
|
||||
\GlobalLogger::get()->warning("warning: mismatch of new value for $propertyNewName for $oldName: $propertyOldValue seen mapped to $propertyNewValue and $existingPropertyValueMap");;
|
||||
foreach(Utils::stringifyKeys($oldProperties) as $oldPropertyName => $oldPropertyValues){
|
||||
$mappingsContainingOldValue = [];
|
||||
foreach($upgradeTable as $mapping){
|
||||
$mappingOldValue = $mapping->old->getState($oldPropertyName) ?? throw new AssumptionFailedError("This should never happen");
|
||||
foreach($oldPropertyValues as $oldPropertyValue){
|
||||
if($mappingOldValue->equals($oldPropertyValue)){
|
||||
$mappingsContainingOldValue[encodeProperty($oldPropertyValue)][] = $mapping;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if($mapped && !isset($remappedPropertyValuesCache[$propertyOldName][$propertyOldValue->getValue()])){
|
||||
//value remap
|
||||
$result->remappedPropertyValues[$oldName][$propertyOldName][] = new BlockStateUpgradeSchemaValueRemap(
|
||||
$propertyRemoved[$propertyOldName],
|
||||
$propertyAdded[$propertyNewName]
|
||||
);
|
||||
$remappedPropertyValuesCache[$propertyOldName][$propertyOldValue->getValue()] = $propertyNewValue;
|
||||
}
|
||||
}elseif($existingPropertyValueMap !== null){
|
||||
\GlobalLogger::get()->warning("warning: multiple values found for value $propertyOldValue of $propertyNewName on block $oldName, guessing it did not change");;
|
||||
$remappedPropertyValuesCache[$propertyOldName][$propertyOldValue->getValue()] = $propertyNewValue;
|
||||
}
|
||||
}else{
|
||||
if(count($propertyAdded) !== 0 && count($propertyRemoved) === 0){
|
||||
foreach(Utils::stringifyKeys($propertyAdded) as $propertyAddedName => $propertyAddedValue){
|
||||
$existingDefault = $result->addedProperties[$oldName][$propertyAddedName] ?? null;
|
||||
if($existingDefault !== null && !$existingDefault->equals($propertyAddedValue)){
|
||||
throw new \UnexpectedValueException("Ambiguous default value for added property $propertyAddedName on block $oldName");
|
||||
}
|
||||
|
||||
$result->addedProperties[$oldName][$propertyAddedName] = $propertyAddedValue;
|
||||
$candidateNewPropertyNames = [];
|
||||
//foreach mappings by unique value, compute the diff across all the states in the list
|
||||
foreach(Utils::stringifyKeys($mappingsContainingOldValue) as $rawOldValue => $mappingList){
|
||||
$first = array_shift($mappingList);
|
||||
foreach(Utils::stringifyKeys($first->new->getStates()) as $newPropertyName => $newPropertyValue){
|
||||
if(isset($addedProperties[$newPropertyName])){
|
||||
//this property was already determined to be unrelated to any old property
|
||||
continue;
|
||||
}
|
||||
foreach($mappingList as $pair){
|
||||
if(!($pair->new->getState($newPropertyName)?->equals($newPropertyValue) ?? false)){
|
||||
//if the new property is different with an unchanged old value,
|
||||
//the property may be influenced by multiple old properties, or be unrelated entirely
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$candidateNewPropertyNames[$newPropertyName][$rawOldValue] = $newPropertyValue;
|
||||
}
|
||||
}elseif(count($propertyRemoved) !== 0 && count($propertyAdded) === 0){
|
||||
foreach(Utils::stringifyKeys($propertyRemoved) as $propertyRemovedName => $propertyRemovedValue){
|
||||
if(!isset($removedPropertiesCache[$propertyRemovedName])){
|
||||
//to avoid having useless keys in the output
|
||||
$result->removedProperties[$oldName][] = $propertyRemovedName;
|
||||
$removedPropertiesCache[$propertyRemovedName] = $propertyRemovedName;
|
||||
}
|
||||
|
||||
if(count($candidateNewPropertyNames) === 0){
|
||||
$removedProperties[$oldPropertyName] = $oldPropertyName;
|
||||
}elseif(count($candidateNewPropertyNames) === 1){
|
||||
$newPropertyName = array_key_first($candidateNewPropertyNames);
|
||||
$newPropertyValues = $candidateNewPropertyNames[$newPropertyName];
|
||||
|
||||
if($oldPropertyName !== $newPropertyName){
|
||||
$renamedProperties[$oldPropertyName] = $newPropertyName;
|
||||
}
|
||||
|
||||
foreach(Utils::stringifyKeys($newPropertyValues) as $rawOldValue => $newPropertyValue){
|
||||
if(!$newPropertyValue->equals($oldPropertyValues[$rawOldValue])){
|
||||
$remappedPropertyValues[$oldPropertyName][$rawOldValue] = $newPropertyValue;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$result->remappedStates[$oldName][] = new BlockStateUpgradeSchemaBlockRemap(
|
||||
$oldStates,
|
||||
$new->getName(),
|
||||
$newStates,
|
||||
[]
|
||||
);
|
||||
\GlobalLogger::get()->warning("warning: multiple properties added and removed for $oldName; added full state remap");;
|
||||
$split = true;
|
||||
if(isset($candidateNewPropertyNames[$oldPropertyName])){
|
||||
//In 1.10, direction wasn't changed at all, but not all state permutations were present in the palette,
|
||||
//making it appear that door_hinge_bit was correlated with direction.
|
||||
//If a new property is present with the same name and values as an old property, we can assume that
|
||||
//the property was unchanged, and that any extra matches properties are probably unrelated.
|
||||
$changedValues = false;
|
||||
foreach(Utils::stringifyKeys($candidateNewPropertyNames[$oldPropertyName]) as $rawOldValue => $newPropertyValue){
|
||||
if(!$newPropertyValue->equals($oldPropertyValues[$rawOldValue])){
|
||||
//if any of the new values are different, we may be dealing with a property being split into
|
||||
//multiple new properties - hand this off to the remap handler
|
||||
$changedValues = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!$changedValues){
|
||||
$split = false;
|
||||
}
|
||||
}
|
||||
if($split){
|
||||
\GlobalLogger::get()->warning(
|
||||
"Multiple new properties (" . (implode(", ", array_keys($candidateNewPropertyNames))) . ") are correlated with $oldName property $oldPropertyName, processing as remaps instead"
|
||||
);
|
||||
return false;
|
||||
}else{
|
||||
//is it safe to ignore the rest?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//finally, write the results to the schema
|
||||
|
||||
if(count($remappedPropertyValues) !== 0){
|
||||
foreach(Utils::stringifyKeys($remappedPropertyValues) as $oldPropertyName => $propertyValues){
|
||||
foreach(Utils::stringifyKeys($propertyValues) as $rawOldValue => $newPropertyValue){
|
||||
$oldPropertyValue = $oldProperties[$oldPropertyName][$rawOldValue];
|
||||
$result->remappedPropertyValues[$oldName][$oldPropertyName][] = new BlockStateUpgradeSchemaValueRemap(
|
||||
$oldPropertyValue,
|
||||
$newPropertyValue
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(count($addedProperties) !== 0){
|
||||
$result->addedProperties[$oldName] = $addedProperties;
|
||||
}
|
||||
if(count($removedProperties) !== 0){
|
||||
$result->removedProperties[$oldName] = array_values($removedProperties);
|
||||
}
|
||||
if(count($renamedProperties) !== 0){
|
||||
$result->renamedProperties[$oldName] = $renamedProperties;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,17 +281,18 @@ function processState(BlockStateData $old, BlockStateData $new, BlockStateUpgrad
|
||||
* This significantly reduces the output size during flattening when the flattened block has many permutations
|
||||
* (e.g. walls).
|
||||
*
|
||||
* @param BlockStateUpgradeSchemaBlockRemap[] $stateRemaps
|
||||
* @param BlockStateMapping[] $upgradeTable
|
||||
* @param BlockStateMapping[] $upgradeTable
|
||||
* @phpstan-param array<string, BlockStateMapping> $upgradeTable
|
||||
*
|
||||
* @return BlockStateUpgradeSchemaBlockRemap[]
|
||||
* @phpstan-return list<BlockStateUpgradeSchemaBlockRemap>
|
||||
*/
|
||||
function compressRemappedStates(array $upgradeTable, array $stateRemaps) : array{
|
||||
function processRemappedStates(array $upgradeTable) : array{
|
||||
$unchangedStatesByNewName = [];
|
||||
|
||||
foreach($upgradeTable as $pair){
|
||||
if(count($pair->old->getStates()) === 0 || count($pair->new->getStates()) === 0){
|
||||
//all states have changed in some way - compression not possible
|
||||
//all states have changed in some way - no states are copied over
|
||||
$unchangedStatesByNewName[$pair->new->getName()] = [];
|
||||
continue;
|
||||
}
|
||||
@ -240,78 +328,115 @@ function compressRemappedStates(array $upgradeTable, array $stateRemaps) : array
|
||||
$unchangedStatesByNewName[$newName] = $unchangedStates;
|
||||
}
|
||||
|
||||
$compressedRemaps = [];
|
||||
$flattenedProperties = [];
|
||||
$notFlattenedProperties = [];
|
||||
$notFlattenedPropertyValues = [];
|
||||
foreach($upgradeTable as $pair){
|
||||
foreach(Utils::stringifyKeys($pair->old->getStates()) as $propertyName => $propertyValue){
|
||||
if(isset($notFlattenedProperties[$propertyName])){
|
||||
continue;
|
||||
}
|
||||
if(!$propertyValue instanceof StringTag){
|
||||
$notFlattenedProperties[$propertyName] = true;
|
||||
continue;
|
||||
}
|
||||
$rawValue = $propertyValue->getValue();
|
||||
if($rawValue === ""){
|
||||
$notFlattenedProperties[$propertyName] = true;
|
||||
continue;
|
||||
}
|
||||
$parts = explode($rawValue, $pair->new->getName(), 2);
|
||||
if(count($parts) !== 2){
|
||||
//the new name does not contain the property value, but it may still be able to be flattened in other cases
|
||||
$notFlattenedPropertyValues[$propertyName][$rawValue] = $rawValue;
|
||||
continue;
|
||||
}
|
||||
[$prefix, $suffix] = $parts;
|
||||
|
||||
foreach($stateRemaps as $remap){
|
||||
$oldState = $remap->oldState;
|
||||
$newState = $remap->newState;
|
||||
|
||||
if($oldState === null || $newState === null){
|
||||
//no unchanged states - no compression possible
|
||||
assert(!isset($unchangedStatesByNewName[$remap->newName]));
|
||||
$compressedRemaps[$remap->newName][] = $remap;
|
||||
continue;
|
||||
$filter = $pair->old->getStates();
|
||||
foreach($unchangedStatesByNewName[$pair->new->getName()] as $unchangedPropertyName){
|
||||
unset($filter[$unchangedPropertyName]);
|
||||
}
|
||||
unset($filter[$propertyName]);
|
||||
$rawFilter = encodeOrderedProperties($filter);
|
||||
$flattenRule = new BlockStateUpgradeSchemaFlattenedName(
|
||||
prefix: $prefix,
|
||||
flattenedProperty: $propertyName,
|
||||
suffix: $suffix
|
||||
);
|
||||
if(!isset($flattenedProperties[$propertyName][$rawFilter])){
|
||||
$flattenedProperties[$propertyName][$rawFilter] = $flattenRule;
|
||||
}elseif(!$flattenRule->equals($flattenedProperties[$propertyName][$rawFilter])){
|
||||
$notFlattenedProperties[$propertyName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach(Utils::stringifyKeys($notFlattenedProperties) as $propertyName => $_){
|
||||
unset($flattenedProperties[$propertyName]);
|
||||
}
|
||||
|
||||
ksort($flattenedProperties, SORT_STRING);
|
||||
$flattenProperty = array_key_first($flattenedProperties);
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach($upgradeTable as $pair){
|
||||
$oldState = $pair->old->getStates();
|
||||
$newState = $pair->new->getStates();
|
||||
|
||||
$cleanedOldState = $oldState;
|
||||
$cleanedNewState = $newState;
|
||||
$newName = $pair->new->getName();
|
||||
|
||||
foreach($unchangedStatesByNewName[$remap->newName] as $propertyName){
|
||||
foreach($unchangedStatesByNewName[$newName] as $propertyName){
|
||||
unset($cleanedOldState[$propertyName]);
|
||||
unset($cleanedNewState[$propertyName]);
|
||||
}
|
||||
ksort($cleanedOldState);
|
||||
ksort($cleanedNewState);
|
||||
|
||||
$duplicate = false;
|
||||
$compressedRemaps[$remap->newName] ??= [];
|
||||
foreach($compressedRemaps[$remap->newName] as $k => $compressedRemap){
|
||||
assert($compressedRemap->oldState !== null && $compressedRemap->newState !== null);
|
||||
|
||||
if(
|
||||
count($compressedRemap->oldState) !== count($cleanedOldState) ||
|
||||
count($compressedRemap->newState) !== count($cleanedNewState)
|
||||
){
|
||||
continue;
|
||||
$flattened = false;
|
||||
if($flattenProperty !== null){
|
||||
$flattenedValue = $cleanedOldState[$flattenProperty] ?? null;
|
||||
if(!$flattenedValue instanceof StringTag){
|
||||
throw new AssumptionFailedError("This should always be a TAG_String");
|
||||
}
|
||||
foreach(Utils::stringifyKeys($cleanedOldState) as $propertyName => $propertyValue){
|
||||
if(!isset($compressedRemap->oldState[$propertyName]) || !$compressedRemap->oldState[$propertyName]->equals($propertyValue)){
|
||||
//different filter value
|
||||
continue 2;
|
||||
}
|
||||
if(!isset($notFlattenedPropertyValues[$flattenProperty][$flattenedValue->getValue()])){
|
||||
unset($cleanedOldState[$flattenProperty]);
|
||||
$flattened = true;
|
||||
}
|
||||
foreach(Utils::stringifyKeys($cleanedNewState) as $propertyName => $propertyValue){
|
||||
if(!isset($compressedRemap->newState[$propertyName]) || !$compressedRemap->newState[$propertyName]->equals($propertyValue)){
|
||||
//different replacement value
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$duplicate = true;
|
||||
break;
|
||||
}
|
||||
if(!$duplicate){
|
||||
$compressedRemaps[$remap->newName][] = new BlockStateUpgradeSchemaBlockRemap(
|
||||
$cleanedOldState,
|
||||
$remap->newName,
|
||||
$cleanedNewState,
|
||||
$unchangedStatesByNewName[$remap->newName]
|
||||
);
|
||||
$rawOldState = encodeOrderedProperties($cleanedOldState);
|
||||
$newNameRule = $flattenProperty !== null && $flattened ?
|
||||
$flattenedProperties[$flattenProperty][$rawOldState] ?? throw new AssumptionFailedError("This should always be set") :
|
||||
$newName;
|
||||
|
||||
$remap = new BlockStateUpgradeSchemaBlockRemap(
|
||||
$cleanedOldState,
|
||||
$newNameRule,
|
||||
$cleanedNewState,
|
||||
$unchangedStatesByNewName[$pair->new->getName()]
|
||||
);
|
||||
|
||||
$existing = $list[$rawOldState] ?? null;
|
||||
if($existing === null || $existing->equals($remap)){
|
||||
$list[$rawOldState] = $remap;
|
||||
}else{
|
||||
//match criteria is borked
|
||||
throw new AssumptionFailedError("Match criteria resulted in two ambiguous remaps");
|
||||
}
|
||||
}
|
||||
|
||||
$list = array_merge(...array_values($compressedRemaps));
|
||||
|
||||
//more specific filters must come before less specific ones, in case of a remap on a certain value which is
|
||||
//otherwise unchanged
|
||||
usort($list, function(BlockStateUpgradeSchemaBlockRemap $a, BlockStateUpgradeSchemaBlockRemap $b) : int{
|
||||
return count($b->oldState) <=> count($a->oldState);
|
||||
});
|
||||
return $list;
|
||||
return array_values($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlockStateMapping[][] $upgradeTable
|
||||
* @phpstan-param array<string, list<BlockStateMapping>> $upgradeTable
|
||||
* @phpstan-param array<string, array<string, BlockStateMapping>> $upgradeTable
|
||||
*/
|
||||
function generateBlockStateUpgradeSchema(array $upgradeTable) : BlockStateUpgradeSchema{
|
||||
$foundVersion = -1;
|
||||
@ -343,8 +468,6 @@ function generateBlockStateUpgradeSchema(array $upgradeTable) : BlockStateUpgrad
|
||||
foreach(Utils::stringifyKeys($upgradeTable) as $oldName => $blockStateMappings){
|
||||
$newNameFound = [];
|
||||
|
||||
$removedPropertiesCache = [];
|
||||
$remappedPropertyValuesCache = [];
|
||||
foreach($blockStateMappings as $mapping){
|
||||
$newName = $mapping->new->getName();
|
||||
$newNameFound[$newName] = true;
|
||||
@ -354,35 +477,23 @@ function generateBlockStateUpgradeSchema(array $upgradeTable) : BlockStateUpgrad
|
||||
if($newName !== $oldName){
|
||||
$result->renamedIds[$oldName] = array_key_first($newNameFound);
|
||||
}
|
||||
foreach($blockStateMappings as $mapping){
|
||||
processState($mapping->old, $mapping->new, $result, $removedPropertiesCache, $remappedPropertyValuesCache);
|
||||
if(!processStateGroup($oldName, $blockStateMappings, $result)){
|
||||
throw new \RuntimeException("States with the same ID should be fully consistent");
|
||||
}
|
||||
}else{
|
||||
if(isset($newNameFound[$oldName])){
|
||||
//some of the states stayed under the same ID - we can process these as normal states
|
||||
foreach($blockStateMappings as $k => $mapping){
|
||||
if($mapping->new->getName() === $oldName){
|
||||
processState($mapping->old, $mapping->new, $result, $removedPropertiesCache, $remappedPropertyValuesCache);
|
||||
$stateGroup = array_filter($blockStateMappings, fn(BlockStateMapping $m) => $m->new->getName() === $oldName);
|
||||
if(processStateGroup($oldName, $stateGroup, $result)){
|
||||
foreach(Utils::stringifyKeys($stateGroup) as $k => $mapping){
|
||||
unset($blockStateMappings[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//block mapped to multiple different new IDs; we can't guess these, so we just do a plain old remap
|
||||
foreach($blockStateMappings as $mapping){
|
||||
if(!$mapping->old->equals($mapping->new)){
|
||||
$result->remappedStates[$mapping->old->getName()][] = new BlockStateUpgradeSchemaBlockRemap(
|
||||
$mapping->old->getStates(),
|
||||
$mapping->new->getName(),
|
||||
$mapping->new->getStates(),
|
||||
[]
|
||||
);
|
||||
}
|
||||
}
|
||||
$result->remappedStates[$oldName] = processRemappedStates($blockStateMappings);
|
||||
}
|
||||
}
|
||||
foreach(Utils::stringifyKeys($result->remappedStates) as $oldName => $remap){
|
||||
$result->remappedStates[$oldName] = compressRemappedStates($upgradeTable[$oldName], $remap);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user