mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-07 18:32:55 +00:00
Refactor Rail handling to allow LSP-complaint shape handling
the reason there hasn't been any API until now is because of how inconvenient it was to expose a LSP-compliant API _and_ use the same base class for handling all the connection logic. This commit fixes that problem by abstracting shape handling away from BaseRail entirely, so that now it deals exclusively with connections. Deciding the shape of rail to use is now the job of the subclasses.
This commit is contained in:
@ -23,74 +23,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\InvalidBlockStateException;
|
||||
use pocketmine\block\utils\RailConnectionInfo;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function array_map;
|
||||
use function array_reverse;
|
||||
use function array_search;
|
||||
use function array_shift;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
|
||||
abstract class BaseRail extends Flowable{
|
||||
|
||||
protected const FLAG_ASCEND = 1 << 24; //used to indicate direction-up
|
||||
|
||||
protected const CONNECTIONS = [
|
||||
//straights
|
||||
BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH => [
|
||||
Facing::NORTH,
|
||||
Facing::SOUTH
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_STRAIGHT_EAST_WEST => [
|
||||
Facing::EAST,
|
||||
Facing::WEST
|
||||
],
|
||||
|
||||
//ascending
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_EAST => [
|
||||
Facing::WEST,
|
||||
Facing::EAST | self::FLAG_ASCEND
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_WEST => [
|
||||
Facing::EAST,
|
||||
Facing::WEST | self::FLAG_ASCEND
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_NORTH => [
|
||||
Facing::SOUTH,
|
||||
Facing::NORTH | self::FLAG_ASCEND
|
||||
],
|
||||
BlockLegacyMetadata::RAIL_ASCENDING_SOUTH => [
|
||||
Facing::NORTH,
|
||||
Facing::SOUTH | self::FLAG_ASCEND
|
||||
]
|
||||
];
|
||||
|
||||
protected int $railShape = BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
|
||||
|
||||
protected function writeStateToMeta() : int{
|
||||
return $this->railShape;
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$railShape = $this->readRailShapeFromMeta($stateMeta);
|
||||
if($railShape === null){
|
||||
throw new InvalidBlockStateException("Invalid rail type meta $stateMeta");
|
||||
}
|
||||
$this->railShape = $railShape;
|
||||
}
|
||||
|
||||
abstract protected function readRailShapeFromMeta(int $stateMeta) : ?int;
|
||||
|
||||
public function getStateBitmask() : int{
|
||||
return 0b1111;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$blockReplace->getSide(Facing::DOWN)->isTransparent()){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
@ -108,28 +54,22 @@ abstract class BaseRail extends Flowable{
|
||||
* @param int[][] $lookup
|
||||
* @phpstan-param array<int, list<int>> $lookup
|
||||
*/
|
||||
protected static function searchState(array $connections, array $lookup) : int{
|
||||
$meta = array_search($connections, $lookup, true);
|
||||
if($meta === false){
|
||||
$meta = array_search(array_reverse($connections), $lookup, true);
|
||||
protected static function searchState(array $connections, array $lookup) : ?int{
|
||||
$shape = array_search($connections, $lookup, true);
|
||||
if($shape === false){
|
||||
$shape = array_search(array_reverse($connections), $lookup, true);
|
||||
}
|
||||
if($meta === false){
|
||||
throw new \InvalidArgumentException("No meta value matches connections " . implode(", ", array_map('\dechex', $connections)));
|
||||
}
|
||||
|
||||
return $meta;
|
||||
return $shape === false ? null : $shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a meta value for the rail with the given connections.
|
||||
* Sets the rail shape according to the given connections, if a shape matches.
|
||||
*
|
||||
* @param int[] $connections
|
||||
*
|
||||
* @throws \InvalidArgumentException if no state matches the given connections
|
||||
* @throws \InvalidArgumentException if no shape matches the given connections
|
||||
*/
|
||||
protected function getShapeForConnections(array $connections) : int{
|
||||
return self::searchState($connections, self::CONNECTIONS);
|
||||
}
|
||||
abstract protected function setShapeFromConnections(array $connections) : void;
|
||||
|
||||
/**
|
||||
* Returns the connection directions of this rail (depending on the current block state)
|
||||
@ -149,15 +89,15 @@ abstract class BaseRail extends Flowable{
|
||||
|
||||
/** @var int $connection */
|
||||
foreach($this->getCurrentShapeConnections() as $connection){
|
||||
$other = $this->getSide($connection & ~self::FLAG_ASCEND);
|
||||
$otherConnection = Facing::opposite($connection & ~self::FLAG_ASCEND);
|
||||
$other = $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
$otherConnection = Facing::opposite($connection & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
|
||||
if(($connection & self::FLAG_ASCEND) !== 0){
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0){
|
||||
$other = $other->getSide(Facing::UP);
|
||||
|
||||
}elseif(!($other instanceof BaseRail)){ //check for rail sloping up to meet this one
|
||||
$other = $other->getSide(Facing::DOWN);
|
||||
$otherConnection |= self::FLAG_ASCEND;
|
||||
$otherConnection |= RailConnectionInfo::FLAG_ASCEND;
|
||||
}
|
||||
|
||||
if(
|
||||
@ -188,7 +128,7 @@ abstract class BaseRail extends Flowable{
|
||||
Facing::EAST => true
|
||||
];
|
||||
foreach($possible as $p => $_){
|
||||
$possible[$p | self::FLAG_ASCEND] = true;
|
||||
$possible[$p | RailConnectionInfo::FLAG_ASCEND] = true;
|
||||
}
|
||||
|
||||
return $possible;
|
||||
@ -206,13 +146,13 @@ abstract class BaseRail extends Flowable{
|
||||
* @phpstan-return array<int, true>
|
||||
*/
|
||||
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
|
||||
$opposite = Facing::opposite($constraint & ~self::FLAG_ASCEND);
|
||||
$opposite = Facing::opposite($constraint & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
|
||||
$possible = [$opposite => true];
|
||||
|
||||
if(($constraint & self::FLAG_ASCEND) === 0){
|
||||
if(($constraint & RailConnectionInfo::FLAG_ASCEND) === 0){
|
||||
//We can slope the other way if this connection isn't already a slope
|
||||
$possible[$opposite | self::FLAG_ASCEND] = true;
|
||||
$possible[$opposite | RailConnectionInfo::FLAG_ASCEND] = true;
|
||||
}
|
||||
|
||||
return $possible;
|
||||
@ -227,16 +167,16 @@ abstract class BaseRail extends Flowable{
|
||||
$continue = false;
|
||||
|
||||
foreach($possible as $thisSide => $_){
|
||||
$otherSide = Facing::opposite($thisSide & ~self::FLAG_ASCEND);
|
||||
$otherSide = Facing::opposite($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
|
||||
$other = $this->getSide($thisSide & ~self::FLAG_ASCEND);
|
||||
$other = $this->getSide($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
|
||||
if(($thisSide & self::FLAG_ASCEND) !== 0){
|
||||
if(($thisSide & RailConnectionInfo::FLAG_ASCEND) !== 0){
|
||||
$other = $other->getSide(Facing::UP);
|
||||
|
||||
}elseif(!($other instanceof BaseRail)){ //check if other rails can slope up to meet this one
|
||||
$other = $other->getSide(Facing::DOWN);
|
||||
$otherSide |= self::FLAG_ASCEND;
|
||||
$otherSide |= RailConnectionInfo::FLAG_ASCEND;
|
||||
}
|
||||
|
||||
if(!($other instanceof BaseRail) or count($otherConnections = $other->getConnectedDirections()) >= 2){
|
||||
@ -271,12 +211,12 @@ abstract class BaseRail extends Flowable{
|
||||
*/
|
||||
private function setConnections(array $connections) : void{
|
||||
if(count($connections) === 1){
|
||||
$connections[] = Facing::opposite($connections[0] & ~self::FLAG_ASCEND);
|
||||
$connections[] = Facing::opposite($connections[0] & ~RailConnectionInfo::FLAG_ASCEND);
|
||||
}elseif(count($connections) !== 2){
|
||||
throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
|
||||
}
|
||||
|
||||
$this->railShape = $this->getShapeForConnections($connections);
|
||||
$this->setShapeFromConnections($connections);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
@ -284,7 +224,7 @@ abstract class BaseRail extends Flowable{
|
||||
$this->pos->getWorld()->useBreakOn($this->pos);
|
||||
}else{
|
||||
foreach($this->getCurrentShapeConnections() as $connection){
|
||||
if(($connection & self::FLAG_ASCEND) !== 0 and $this->getSide($connection & ~self::FLAG_ASCEND)->isTransparent()){
|
||||
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 and $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->isTransparent()){
|
||||
$this->pos->getWorld()->useBreakOn($this->pos);
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user