Enums for rail shapes, sort of

this makes the API more sane, although the internals will need to be rewritten at some point in the future.
This commit is contained in:
Dylan K. Taylor 2025-08-29 23:33:52 +01:00
parent 7449ad5637
commit 8dc4371385
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
10 changed files with 117 additions and 68 deletions

View File

@ -24,18 +24,16 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\RailConnectionInfo;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\block\utils\RailShape;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\math\Facing;
use function array_keys;
use function implode;
class Rail extends BaseRail{
private int $railShape = BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
private RailShape $railShape = RailShape::FLAT_AXIS_Z;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->railShape($this->railShape);
$w->enum($this->railShape);
}
protected function setShapeFromConnections(array $connections) : void{
@ -43,11 +41,11 @@ class Rail extends BaseRail{
if($railShape === null){
throw new \InvalidArgumentException("No rail shape matches these connections");
}
$this->railShape = $railShape;
$this->railShape = RailShape::from($railShape);
}
protected function getCurrentShapeConnections() : array{
return RailConnectionInfo::CURVE_CONNECTIONS[$this->railShape] ?? RailConnectionInfo::CONNECTIONS[$this->railShape];
return RailConnectionInfo::CURVE_CONNECTIONS[$this->railShape->value] ?? RailConnectionInfo::CONNECTIONS[$this->railShape->value];
}
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
@ -69,13 +67,10 @@ class Rail extends BaseRail{
return $possible;
}
public function getShape() : int{ return $this->railShape; }
public function getShape() : RailShape{ return $this->railShape; }
/** @return $this */
public function setShape(int $shape) : self{
if(!isset(RailConnectionInfo::CONNECTIONS[$shape]) && !isset(RailConnectionInfo::CURVE_CONNECTIONS[$shape])){
throw new \InvalidArgumentException("Invalid shape, must be one of " . implode(", ", [...array_keys(RailConnectionInfo::CONNECTIONS), ...array_keys(RailConnectionInfo::CURVE_CONNECTIONS)]));
}
public function setShape(RailShape $shape) : self{
$this->railShape = $shape;
return $this;
}

View File

@ -24,20 +24,18 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\RailConnectionInfo;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\block\utils\StraightOnlyRailShape;
use pocketmine\data\runtime\RuntimeDataDescriber;
use function array_keys;
use function implode;
/**
* Simple non-curvable rail.
*/
class StraightOnlyRail extends BaseRail{
private int $railShape = BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
private StraightOnlyRailShape $railShape = StraightOnlyRailShape::FLAT_AXIS_Z;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->straightOnlyRailShape($this->railShape);
$w->enum($this->railShape);
}
protected function setShapeFromConnections(array $connections) : void{
@ -45,20 +43,17 @@ class StraightOnlyRail extends BaseRail{
if($railShape === null){
throw new \InvalidArgumentException("No rail shape matches these connections");
}
$this->railShape = $railShape;
$this->railShape = StraightOnlyRailShape::from($railShape);
}
protected function getCurrentShapeConnections() : array{
return RailConnectionInfo::CONNECTIONS[$this->railShape];
return RailConnectionInfo::CONNECTIONS[$this->railShape->value];
}
public function getShape() : int{ return $this->railShape; }
public function getShape() : StraightOnlyRailShape{ return $this->railShape; }
/** @return $this */
public function setShape(int $shape) : self{
if(!isset(RailConnectionInfo::CONNECTIONS[$shape])){
throw new \InvalidArgumentException("Invalid rail shape, must be one of " . implode(", ", array_keys(RailConnectionInfo::CONNECTIONS)));
}
public function setShape(StraightOnlyRailShape $shape) : self{
$this->railShape = $shape;
return $this;

View File

@ -0,0 +1,41 @@
<?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\utils;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
enum RailShape : int{
//TODO: these values really need to be removed
case FLAT_AXIS_Z = BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
case FLAT_AXIS_X = BlockLegacyMetadata::RAIL_STRAIGHT_EAST_WEST;
case ASCENDING_EAST = BlockLegacyMetadata::RAIL_ASCENDING_EAST;
case ASCENDING_WEST = BlockLegacyMetadata::RAIL_ASCENDING_WEST;
case ASCENDING_NORTH = BlockLegacyMetadata::RAIL_ASCENDING_NORTH;
case ASCENDING_SOUTH = BlockLegacyMetadata::RAIL_ASCENDING_SOUTH;
case CURVED_SOUTHEAST = BlockLegacyMetadata::RAIL_CURVE_SOUTHEAST;
case CURVED_SOUTHWEST = BlockLegacyMetadata::RAIL_CURVE_SOUTHWEST;
case CURVED_NORTHWEST = BlockLegacyMetadata::RAIL_CURVE_NORTHWEST;
case CURVED_NORTHEAST = BlockLegacyMetadata::RAIL_CURVE_NORTHEAST;
}

View File

@ -0,0 +1,33 @@
<?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\utils;
enum StraightOnlyRailShape : int{
case FLAT_AXIS_Z = RailShape::FLAT_AXIS_Z->value;
case FLAT_AXIS_X = RailShape::FLAT_AXIS_X->value;
case ASCENDING_EAST = RailShape::ASCENDING_EAST->value;
case ASCENDING_WEST = RailShape::ASCENDING_WEST->value;
case ASCENDING_NORTH = RailShape::ASCENDING_NORTH->value;
case ASCENDING_SOUTH = RailShape::ASCENDING_SOUTH->value;
}

View File

@ -81,7 +81,6 @@ use pocketmine\block\SeaPickle;
use pocketmine\block\SmallDripleaf;
use pocketmine\block\SnowLayer;
use pocketmine\block\Sponge;
use pocketmine\block\StraightOnlyRail;
use pocketmine\block\Sugarcane;
use pocketmine\block\SweetBerryBush;
use pocketmine\block\TNT;
@ -102,6 +101,7 @@ use pocketmine\block\utils\LeverFacing;
use pocketmine\block\utils\MobHeadType;
use pocketmine\block\utils\MushroomBlockType;
use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\RailShape;
use pocketmine\block\VanillaBlocks as Blocks;
use pocketmine\block\Vine;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
@ -1215,7 +1215,7 @@ final class VanillaBlockMappings{
//A
$reg->mapModel(Model::create(Blocks::ACTIVATOR_RAIL(), Ids::ACTIVATOR_RAIL)->properties([
new BoolProperty(StateNames::RAIL_DATA_BIT, fn(ActivatorRail $b) => $b->isPowered(), fn(ActivatorRail $b, bool $v) => $b->setPowered($v)),
new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(ActivatorRail $b) => $b->getShape(), fn(ActivatorRail $b, int $v) => $b->setShape($v))
$commonProperties->straightOnlyRailShape
]));
//B
@ -1300,7 +1300,7 @@ final class VanillaBlockMappings{
$reg->mapModel(Model::create(Blocks::DEEPSLATE(), Ids::DEEPSLATE)->properties([$commonProperties->pillarAxis]));
$reg->mapModel(Model::create(Blocks::DETECTOR_RAIL(), Ids::DETECTOR_RAIL)->properties([
new BoolProperty(StateNames::RAIL_DATA_BIT, fn(DetectorRail $b) => $b->isActivated(), fn(DetectorRail $b, bool $v) => $b->setActivated($v)),
new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, int $v) => $b->setShape($v)) //TODO: shared with ActivatorRail
$commonProperties->straightOnlyRailShape
]));
//E
@ -1381,7 +1381,7 @@ final class VanillaBlockMappings{
]));
$reg->mapModel(Model::create(Blocks::POWERED_RAIL(), Ids::GOLDEN_RAIL)->properties([
new BoolProperty(StateNames::RAIL_DATA_BIT, fn(PoweredRail $b) => $b->isPowered(), fn(PoweredRail $b, bool $v) => $b->setPowered($v)), //TODO: shared with ActivatorRail
new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, int $v) => $b->setShape($v)) //TODO: shared with ActivatorRail
$commonProperties->straightOnlyRailShape
]));
$reg->mapModel(Model::create(Blocks::PITCHER_PLANT(), Ids::PITCHER_PLANT)->properties([
new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(DoublePlant $b) => $b->isTop(), fn(DoublePlant $b, bool $v) => $b->setTop($v)), //TODO: don't we have helpers for this?
@ -1406,7 +1406,18 @@ final class VanillaBlockMappings{
//R
$reg->mapModel(Model::create(Blocks::RAIL(), Ids::RAIL)->properties([
new IntProperty(StateNames::RAIL_DIRECTION, 0, 9, fn(Rail $b) => $b->getShape(), fn(Rail $b, int $v) => $b->setShape($v))
new ValueFromIntProperty(StateNames::RAIL_DIRECTION, EnumFromRawStateMap::int(RailShape::class, fn(RailShape $case) => match($case){
RailShape::FLAT_AXIS_Z => BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH,
RailShape::FLAT_AXIS_X => BlockLegacyMetadata::RAIL_STRAIGHT_EAST_WEST,
RailShape::ASCENDING_EAST => BlockLegacyMetadata::RAIL_ASCENDING_EAST,
RailShape::ASCENDING_WEST => BlockLegacyMetadata::RAIL_ASCENDING_WEST,
RailShape::ASCENDING_NORTH => BlockLegacyMetadata::RAIL_ASCENDING_NORTH,
RailShape::ASCENDING_SOUTH => BlockLegacyMetadata::RAIL_ASCENDING_SOUTH,
RailShape::CURVED_NORTHEAST => BlockLegacyMetadata::RAIL_CURVE_NORTHEAST,
RailShape::CURVED_NORTHWEST => BlockLegacyMetadata::RAIL_CURVE_NORTHWEST,
RailShape::CURVED_SOUTHEAST => BlockLegacyMetadata::RAIL_CURVE_SOUTHEAST,
RailShape::CURVED_SOUTHWEST => BlockLegacyMetadata::RAIL_CURVE_SOUTHWEST,
}), fn(Rail $b) => $b->getShape(), fn(Rail $b, RailShape $v) => $b->setShape($v))
]));
$reg->mapModel(Model::create(Blocks::REDSTONE_WIRE(), Ids::REDSTONE_WIRE)->properties([$commonProperties->analogRedstoneSignal]));
$reg->mapModel(Model::create(Blocks::RESPAWN_ANCHOR(), Ids::RESPAWN_ANCHOR)->properties([

View File

@ -33,6 +33,7 @@ use pocketmine\block\SimplePressurePlate;
use pocketmine\block\Slab;
use pocketmine\block\Stair;
use pocketmine\block\Stem;
use pocketmine\block\StraightOnlyRail;
use pocketmine\block\Torch;
use pocketmine\block\Trapdoor;
use pocketmine\block\utils\Ageable;
@ -51,6 +52,7 @@ use pocketmine\block\utils\MultiAnyFacing;
use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SlabType;
use pocketmine\block\utils\StraightOnlyRailShape;
use pocketmine\block\Wall;
use pocketmine\block\Wood;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
@ -95,6 +97,8 @@ final class CommonProperties{
public readonly IntProperty $cropAgeMax7;
/** @phpstan-var BoolProperty<DoublePlant> */
public readonly BoolProperty $doublePlantHalf;
/** @phpstan-var ValueFromIntProperty<StraightOnlyRail, StraightOnlyRailShape> */
public readonly ValueFromIntProperty $straightOnlyRailShape;
/** @phpstan-var IntProperty<Liquid> */
public readonly IntProperty $liquidData;
@ -266,6 +270,15 @@ final class CommonProperties{
$this->cropAgeMax7 = new IntProperty(StateNames::GROWTH, 0, 7, fn(Ageable $b) => $b->getAge(), fn(Ageable $b, int $v) => $b->setAge($v));
$this->doublePlantHalf = new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(DoublePlant $b) => $b->isTop(), fn(DoublePlant $b, bool $v) => $b->setTop($v));
$this->straightOnlyRailShape = new ValueFromIntProperty(StateNames::RAIL_DIRECTION, EnumFromRawStateMap::int(StraightOnlyRailShape::class, fn(StraightOnlyRailShape $case) => match($case){
StraightOnlyRailShape::FLAT_AXIS_Z => BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH,
StraightOnlyRailShape::FLAT_AXIS_X => BlockLegacyMetadata::RAIL_STRAIGHT_EAST_WEST,
StraightOnlyRailShape::ASCENDING_EAST => BlockLegacyMetadata::RAIL_ASCENDING_EAST,
StraightOnlyRailShape::ASCENDING_WEST => BlockLegacyMetadata::RAIL_ASCENDING_WEST,
StraightOnlyRailShape::ASCENDING_NORTH => BlockLegacyMetadata::RAIL_ASCENDING_NORTH,
StraightOnlyRailShape::ASCENDING_SOUTH => BlockLegacyMetadata::RAIL_ASCENDING_SOUTH
}), fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, StraightOnlyRailShape $v) => $b->setShape($v));
$fallingFlag = BlockLegacyMetadata::LIQUID_FALLING_FLAG;
$this->liquidData = new IntProperty(
StateNames::LIQUID_DEPTH,

View File

@ -67,10 +67,6 @@ interface RuntimeDataDescriber{
*/
public function wallConnections(array &$connections) : void;
public function railShape(int &$railShape) : void;
public function straightOnlyRailShape(int &$railShape) : void;
/**
* @phpstan-template T of \UnitEnum
* @phpstan-param T &$case

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\RailConnectionInfo;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
@ -147,24 +146,6 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
$connections = $result;
}
public function railShape(int &$railShape) : void{
$result = $this->readInt(4);
if(!isset(RailConnectionInfo::CONNECTIONS[$result]) && !isset(RailConnectionInfo::CURVE_CONNECTIONS[$result])){
throw new InvalidSerializedRuntimeDataException("Invalid rail shape $result");
}
$railShape = $result;
}
public function straightOnlyRailShape(int &$railShape) : void{
$result = $this->readInt(3);
if(!isset(RailConnectionInfo::CONNECTIONS[$result])){
throw new InvalidSerializedRuntimeDataException("No rail shape matches meta $result");
}
$railShape = $result;
}
public function enum(\UnitEnum &$case) : void{
$metadata = RuntimeEnumMetadata::from($case);
$raw = $this->readInt($metadata->bits);

View File

@ -72,14 +72,6 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
$this->addBits(7);
}
public function railShape(int &$railShape) : void{
$this->addBits(4);
}
public function straightOnlyRailShape(int &$railShape) : void{
$this->addBits(3);
}
public function enum(\UnitEnum &$case) : void{
$metadata = RuntimeEnumMetadata::from($case);
$this->addBits($metadata->bits);

View File

@ -130,14 +130,6 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
$this->writeBoundedIntAuto(0, (3 ** 4) - 1, $packed);
}
public function railShape(int &$railShape) : void{
$this->int(4, $railShape);
}
public function straightOnlyRailShape(int &$railShape) : void{
$this->int(3, $railShape);
}
public function enum(\UnitEnum &$case) : void{
$metadata = RuntimeEnumMetadata::from($case);
$this->writeInt($metadata->bits, $metadata->enumToInt($case));