mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-06 17:59:48 +00:00
This has several advantages: Easier to implement new blocks (one less file to modify) Easier to adjust serialization of existing blocks Guaranteed consistency between serializers and deserializers Potentially, exposes more metadata for programmatic analysis, instead of having everything baked inside opaque Closures There are some exceptions which still use the old approach: big dripleaf, cauldrons, mushroom stems, and pitcher crops. These all have multiple PM block types for a single ID, with relatively complex logic to select which to use. These weren't worth the effort to unify due to their small number. I may revisit this in the future, but I already spent a lot of brainpower on it.
360 lines
12 KiB
PHP
360 lines
12 KiB
PHP
<?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\convert;
|
|
|
|
use pocketmine\block\Block;
|
|
use pocketmine\block\Button;
|
|
use pocketmine\block\Candle;
|
|
use pocketmine\block\Crops;
|
|
use pocketmine\block\DaylightSensor;
|
|
use pocketmine\block\Door;
|
|
use pocketmine\block\DoublePlant;
|
|
use pocketmine\block\FenceGate;
|
|
use pocketmine\block\FloorCoralFan;
|
|
use pocketmine\block\FloorSign;
|
|
use pocketmine\block\ItemFrame;
|
|
use pocketmine\block\Leaves;
|
|
use pocketmine\block\Liquid;
|
|
use pocketmine\block\RedMushroomBlock;
|
|
use pocketmine\block\RedstoneComparator;
|
|
use pocketmine\block\RedstoneRepeater;
|
|
use pocketmine\block\Sapling;
|
|
use pocketmine\block\SimplePressurePlate;
|
|
use pocketmine\block\Slab;
|
|
use pocketmine\block\Stair;
|
|
use pocketmine\block\Stem;
|
|
use pocketmine\block\Trapdoor;
|
|
use pocketmine\block\utils\CopperMaterial;
|
|
use pocketmine\block\utils\CopperOxidation;
|
|
use pocketmine\block\utils\SlabType;
|
|
use pocketmine\block\Wall;
|
|
use pocketmine\block\WallSign;
|
|
use pocketmine\block\WeightedPressurePlate;
|
|
use pocketmine\block\Wood;
|
|
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
|
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
|
|
use pocketmine\data\bedrock\block\BlockStateNames;
|
|
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
|
|
use pocketmine\data\bedrock\block\convert\property\ValueMappings;
|
|
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
|
|
use pocketmine\math\Facing;
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
final class BlockStateDeserializerHelper{
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeButton(Button $block, BlockStateReader $in) : Button{
|
|
return $block
|
|
->setFacing($in->readFacingDirection())
|
|
->setPressed($in->readBool(BlockStateNames::BUTTON_PRESSED_BIT));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @phpstan-template TCandle of Candle
|
|
* @phpstan-param TCandle $block
|
|
* @phpstan-return TCandle
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeCandle(Candle $block, BlockStateReader $in) : Candle{
|
|
return $block
|
|
->setCount($in->readBoundedInt(StateNames::CANDLES, 0, 3) + 1)
|
|
->setLit($in->readBool(StateNames::LIT));
|
|
}
|
|
|
|
/**
|
|
* @phpstan-template TCrops of Crops
|
|
* @phpstan-param TCrops $block
|
|
* @phpstan-return TCrops
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeCrops(Crops $block, BlockStateReader $in) : Crops{
|
|
return $block->setAge($in->readBoundedInt(BlockStateNames::GROWTH, 0, 7));
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeComparator(RedstoneComparator $block, BlockStateReader $in) : RedstoneComparator{
|
|
return $block
|
|
->setFacing($in->readCardinalHorizontalFacing())
|
|
->setPowered($in->readBool(BlockStateNames::OUTPUT_LIT_BIT))
|
|
->setSubtractMode($in->readBool(BlockStateNames::OUTPUT_SUBTRACT_BIT));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @phpstan-template TBlock of CopperMaterial
|
|
*
|
|
* @phpstan-param TBlock $block
|
|
* @phpstan-return TBlock
|
|
*/
|
|
public static function decodeCopper(CopperMaterial $block, CopperOxidation $oxidation) : CopperMaterial{
|
|
$block->setOxidation($oxidation);
|
|
$block->setWaxed(false);
|
|
return $block;
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @phpstan-template TBlock of CopperMaterial
|
|
*
|
|
* @phpstan-param TBlock $block
|
|
* @phpstan-return TBlock
|
|
*/
|
|
public static function decodeWaxedCopper(CopperMaterial $block, CopperOxidation $oxidation) : CopperMaterial{
|
|
$block->setOxidation($oxidation);
|
|
$block->setWaxed(true);
|
|
return $block;
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeDaylightSensor(DaylightSensor $block, BlockStateReader $in) : DaylightSensor{
|
|
return $block
|
|
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @phpstan-template TDoor of Door
|
|
* @phpstan-param TDoor $block
|
|
* @phpstan-return TDoor
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeDoor(Door $block, BlockStateReader $in) : Door{
|
|
//TODO: check if these need any special treatment to get the appropriate data to both halves of the door
|
|
return $block
|
|
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT))
|
|
//a door facing "east" is actually facing north - thanks mojang
|
|
->setFacing(Facing::rotateY($in->readCardinalHorizontalFacing(), clockwise: false))
|
|
->setHingeRight($in->readBool(BlockStateNames::DOOR_HINGE_BIT))
|
|
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeDoublePlant(DoublePlant $block, BlockStateReader $in) : DoublePlant{
|
|
return $block
|
|
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeFenceGate(FenceGate $block, BlockStateReader $in) : FenceGate{
|
|
return $block
|
|
->setFacing($in->readCardinalHorizontalFacing())
|
|
->setInWall($in->readBool(BlockStateNames::IN_WALL_BIT))
|
|
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeFloorCoralFan(FloorCoralFan $block, BlockStateReader $in) : FloorCoralFan{
|
|
return $block
|
|
->setAxis($in->mapIntFromInt(BlockStateNames::CORAL_FAN_DIRECTION, ValueMappings::getInstance()->coralAxis));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeFloorSign(FloorSign $block, BlockStateReader $in) : FloorSign{
|
|
return $block
|
|
->setRotation($in->readBoundedInt(BlockStateNames::GROUND_SIGN_DIRECTION, 0, 15));
|
|
}
|
|
|
|
public static function decodeItemFrame(ItemFrame $block, BlockStateReader $in) : ItemFrame{
|
|
$in->todo(StateNames::ITEM_FRAME_PHOTO_BIT); //TODO: not sure what the point of this is
|
|
return $block
|
|
->setFacing($in->readFacingDirection())
|
|
->setHasMap($in->readBool(StateNames::ITEM_FRAME_MAP_BIT));
|
|
}
|
|
|
|
/**
|
|
* @throws BlockStateDeserializeException
|
|
* @deprecated
|
|
*/
|
|
public static function decodeLeaves(Leaves $block, BlockStateReader $in) : Leaves{
|
|
return $block
|
|
->setNoDecay($in->readBool(StateNames::PERSISTENT_BIT))
|
|
->setCheckDecay($in->readBool(StateNames::UPDATE_BIT));
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeLiquid(Liquid $block, BlockStateReader $in, bool $still) : Liquid{
|
|
$fluidHeightState = $in->readBoundedInt(BlockStateNames::LIQUID_DEPTH, 0, 15);
|
|
return $block
|
|
->setDecay($fluidHeightState & 0x7)
|
|
->setFalling(($fluidHeightState & 0x8) !== 0)
|
|
->setStill($still);
|
|
}
|
|
|
|
public static function decodeFlowingLiquid(Liquid $block, BlockStateReader $in) : Liquid{
|
|
return self::decodeLiquid($block, $in, false);
|
|
}
|
|
|
|
public static function decodeStillLiquid(Liquid $block, BlockStateReader $in) : Liquid{
|
|
return self::decodeLiquid($block, $in, true);
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeLog(Wood $block, bool $stripped, BlockStateReader $in) : Wood{
|
|
return $block
|
|
->setAxis($in->readPillarAxis())
|
|
->setStripped($stripped);
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeMushroomBlock(RedMushroomBlock $block, BlockStateReader $in) : Block{
|
|
switch($type = $in->readBoundedInt(BlockStateNames::HUGE_MUSHROOM_BITS, 0, 15)){
|
|
case BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM:
|
|
case BlockLegacyMetadata::MUSHROOM_BLOCK_STEM: throw new BlockStateDeserializeException("This state does not exist");
|
|
default:
|
|
//invalid types get left as default
|
|
$type = MushroomBlockTypeIdMap::getInstance()->fromId($type);
|
|
return $type !== null ? $block->setMushroomBlockType($type) : $block;
|
|
}
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeRepeater(RedstoneRepeater $block, BlockStateReader $in) : RedstoneRepeater{
|
|
return $block
|
|
->setFacing($in->readCardinalHorizontalFacing())
|
|
->setDelay($in->readBoundedInt(BlockStateNames::REPEATER_DELAY, 0, 3) + 1);
|
|
}
|
|
|
|
/**
|
|
* @throws BlockStateDeserializeException
|
|
* @deprecated
|
|
*/
|
|
public static function decodeSapling(Sapling $block, BlockStateReader $in) : Sapling{
|
|
return $block
|
|
->setReady($in->readBool(BlockStateNames::AGE_BIT));
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeSimplePressurePlate(SimplePressurePlate $block, BlockStateReader $in) : SimplePressurePlate{
|
|
//TODO: not sure what the deal is here ... seems like a mojang bug / artifact of bad implementation?
|
|
//best to keep this separate from weighted plates anyway...
|
|
return $block->setPressed($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15) !== 0);
|
|
}
|
|
|
|
/**
|
|
* @phpstan-template TSlab of Slab
|
|
* @phpstan-param TSlab $block
|
|
* @phpstan-return TSlab
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeSingleSlab(Slab $block, BlockStateReader $in) : Slab{
|
|
return $block->setSlabType($in->readSlabPosition());
|
|
}
|
|
|
|
/**
|
|
* @phpstan-template TSlab of Slab
|
|
* @phpstan-param TSlab $block
|
|
* @phpstan-return TSlab
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeDoubleSlab(Slab $block, BlockStateReader $in) : Slab{
|
|
$in->ignored(StateNames::MC_VERTICAL_HALF);
|
|
return $block->setSlabType(SlabType::DOUBLE);
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @phpstan-template TStair of Stair
|
|
* @phpstan-param TStair $block
|
|
* @phpstan-return TStair
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeStairs(Stair $block, BlockStateReader $in) : Stair{
|
|
return $block
|
|
->setUpsideDown($in->readBool(BlockStateNames::UPSIDE_DOWN_BIT))
|
|
->setFacing($in->readWeirdoHorizontalFacing());
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeStem(Stem $block, BlockStateReader $in) : Stem{
|
|
//In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the
|
|
//most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which
|
|
//is absurd, and I refuse to make our API similarly absurd.
|
|
$facing = $in->readFacingWithoutUp();
|
|
return self::decodeCrops($block, $in)
|
|
->setFacing($facing === Facing::DOWN ? Facing::UP : $facing);
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @phpstan-template TTrapdoor of Trapdoor
|
|
* @phpstan-param TTrapdoor $block
|
|
* @phpstan-return TTrapdoor
|
|
*
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeTrapdoor(Trapdoor $block, BlockStateReader $in) : Trapdoor{
|
|
return $block
|
|
->setFacing($in->read5MinusHorizontalFacing())
|
|
->setTop($in->readBool(BlockStateNames::UPSIDE_DOWN_BIT))
|
|
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
|
|
}
|
|
|
|
/** @throws BlockStateDeserializeException */
|
|
public static function decodeWall(Wall $block, BlockStateReader $in) : Wall{
|
|
$block->setPost($in->readBool(BlockStateNames::WALL_POST_BIT));
|
|
$block->setConnection(Facing::NORTH, $in->readWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_NORTH));
|
|
$block->setConnection(Facing::SOUTH, $in->readWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_SOUTH));
|
|
$block->setConnection(Facing::WEST, $in->readWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_WEST));
|
|
$block->setConnection(Facing::EAST, $in->readWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_EAST));
|
|
|
|
return $block;
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeWallSign(WallSign $block, BlockStateReader $in) : WallSign{
|
|
return $block
|
|
->setFacing($in->readHorizontalFacing());
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @throws BlockStateDeserializeException
|
|
*/
|
|
public static function decodeWeightedPressurePlate(WeightedPressurePlate $block, BlockStateReader $in) : WeightedPressurePlate{
|
|
return $block
|
|
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));
|
|
}
|
|
}
|