mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
Move block permutation generation into Block
this allows sealing off a whole bunch of internal APIs.
This commit is contained in:
parent
6c0ad9589b
commit
d4ca566fd0
@ -29,6 +29,7 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\tile\Spawnable;
|
||||
use pocketmine\block\tile\Tile;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\InvalidSerializedRuntimeDataException;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\data\runtime\RuntimeDataReader;
|
||||
use pocketmine\data\runtime\RuntimeDataSizeCalculator;
|
||||
@ -185,14 +186,6 @@ class Block{
|
||||
return new ItemBlock($normalized);
|
||||
}
|
||||
|
||||
final public function getRequiredTypeDataBits() : int{
|
||||
return $this->requiredTypeDataBits;
|
||||
}
|
||||
|
||||
final public function getRequiredStateDataBits() : int{
|
||||
return $this->requiredStateDataBits;
|
||||
}
|
||||
|
||||
private function decodeTypeData(int $data) : void{
|
||||
$reader = new RuntimeDataReader($this->requiredTypeDataBits, $data);
|
||||
|
||||
@ -213,10 +206,7 @@ class Block{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final public function decodeTypeAndStateData(int $data) : void{
|
||||
private function decodeTypeAndStateData(int $data) : void{
|
||||
$reader = new RuntimeDataReader($this->requiredTypeDataBits + $this->requiredStateDataBits, $data);
|
||||
$this->decodeTypeData($reader->readInt($this->requiredTypeDataBits));
|
||||
$this->decodeStateData($reader->readInt($this->requiredStateDataBits));
|
||||
@ -246,10 +236,7 @@ class Block{
|
||||
return $writer->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final public function computeTypeAndStateData() : int{
|
||||
private function computeTypeAndStateData() : int{
|
||||
$writer = new RuntimeDataWriter($this->requiredTypeDataBits + $this->requiredStateDataBits);
|
||||
$writer->writeInt($this->requiredTypeDataBits, $this->computeTypeData());
|
||||
$writer->writeInt($this->requiredStateDataBits, $this->computeStateData());
|
||||
@ -281,6 +268,35 @@ class Block{
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates copies of this Block in all possible state permutations.
|
||||
* Every possible combination of known properties (e.g. facing, open/closed, powered/unpowered, on/off) will be
|
||||
* generated.
|
||||
*
|
||||
* @phpstan-return \Generator<int, Block, void, void>
|
||||
*/
|
||||
public function generateStatePermutations() : \Generator{
|
||||
//TODO: this bruteforce approach to discovering all valid states is very inefficient for larger state data sizes
|
||||
//at some point we'll need to find a better way to do this
|
||||
$bits = $this->requiredTypeDataBits + $this->requiredStateDataBits;
|
||||
if($bits > Block::INTERNAL_STATE_DATA_BITS){
|
||||
throw new \LogicException("Block state data cannot use more than " . Block::INTERNAL_STATE_DATA_BITS . " bits");
|
||||
}
|
||||
for($stateData = 0; $stateData < (1 << $bits); ++$stateData){
|
||||
$v = clone $this;
|
||||
try{
|
||||
$v->decodeTypeAndStateData($stateData);
|
||||
if($v->computeTypeAndStateData() !== $stateData){
|
||||
throw new \LogicException(static::class . "::decodeStateData() accepts invalid state data (returned " . $v->computeTypeAndStateData() . " for input $stateData)");
|
||||
}
|
||||
}catch(InvalidSerializedRuntimeDataException){ //invalid property combination, leave it
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this block is created, set, or has a neighbouring block update, to re-detect dynamic properties which
|
||||
* are not saved on the world.
|
||||
|
@ -25,11 +25,9 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\BlockBreakInfo as BreakInfo;
|
||||
use pocketmine\block\BlockIdentifier as BID;
|
||||
use pocketmine\data\runtime\InvalidSerializedRuntimeDataException;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use pocketmine\world\light\LightUpdate;
|
||||
use function get_class;
|
||||
use function min;
|
||||
|
||||
/**
|
||||
@ -82,33 +80,6 @@ class RuntimeBlockStateRegistry{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates all the possible valid blockstates for a given block type.
|
||||
*
|
||||
* @phpstan-return \Generator<int, Block, void, void>
|
||||
*/
|
||||
private static function generateAllStatesForType(Block $block) : \Generator{
|
||||
//TODO: this bruteforce approach to discovering all valid states is very inefficient for larger state data sizes
|
||||
//at some point we'll need to find a better way to do this
|
||||
$bits = $block->getRequiredTypeDataBits() + $block->getRequiredStateDataBits();
|
||||
if($bits > Block::INTERNAL_STATE_DATA_BITS){
|
||||
throw new \InvalidArgumentException("Block state data cannot use more than " . Block::INTERNAL_STATE_DATA_BITS . " bits");
|
||||
}
|
||||
for($stateData = 0; $stateData < (1 << $bits); ++$stateData){
|
||||
$v = clone $block;
|
||||
try{
|
||||
$v->decodeTypeAndStateData($stateData);
|
||||
if($v->computeTypeAndStateData() !== $stateData){
|
||||
throw new \LogicException(get_class($block) . "::decodeStateData() accepts invalid state data (returned " . $v->computeTypeAndStateData() . " for input $stateData)");
|
||||
}
|
||||
}catch(InvalidSerializedRuntimeDataException){ //invalid property combination, leave it
|
||||
continue;
|
||||
}
|
||||
|
||||
yield $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a block type to its corresponding type ID. This is necessary for the block to be recognized when loading
|
||||
* from disk, and also when being read at runtime.
|
||||
@ -130,7 +101,7 @@ class RuntimeBlockStateRegistry{
|
||||
|
||||
$this->typeIndex[$typeId] = clone $block;
|
||||
|
||||
foreach(self::generateAllStatesForType($block) as $v){
|
||||
foreach($block->generateStatePermutations() as $v){
|
||||
$this->fillStaticArrays($v->getStateId(), $v);
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ class BlockTest extends TestCase{
|
||||
|
||||
$states = $this->blockFactory->getAllKnownStates();
|
||||
foreach($states as $stateId => $state){
|
||||
self::assertArrayHasKey($stateId, $knownStates, "New block state $stateId (" . $state->getTypeId() . ":" . $state->computeTypeAndStateData() . ", " . print_r($state, true) . ") - consistency check may need regenerating");
|
||||
self::assertArrayHasKey($stateId, $knownStates, "New block state $stateId (" . print_r($state, true) . ") - consistency check may need regenerating");
|
||||
self::assertSame($knownStates[$stateId], $state->getName());
|
||||
}
|
||||
asort($knownStates, SORT_STRING);
|
||||
|
Loading…
x
Reference in New Issue
Block a user