RuntimeBlockStateRegistry: separate permutation expansion from register()

This commit is contained in:
Dylan K. Taylor 2023-02-16 15:41:12 +00:00
parent 75f74454c6
commit 4c3892b2d6
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D

View File

@ -29,6 +29,7 @@ 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;
/**
@ -81,6 +82,34 @@ 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->decodeStateData($stateData);
if($v->computeStateData() !== $stateData){
//TODO: this should probably be a hard error
throw new InvalidSerializedRuntimeDataException(get_class($block) . "::decodeStateData() accepts invalid state data (returned " . $v->computeStateData() . " 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.
@ -102,24 +131,7 @@ class RuntimeBlockStateRegistry{
$this->typeIndex[$typeId] = clone $block;
//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->decodeStateData($stateData);
if($v->computeStateData() !== $stateData){
//if the fullID comes back different, this is a broken state that we can't rely on; map it to default
throw new InvalidSerializedRuntimeDataException("Corrupted state");
}
}catch(InvalidSerializedRuntimeDataException $e){ //invalid property combination, leave it
continue;
}
foreach(self::generateAllStatesForType($block) as $v){
$this->fillStaticArrays($v->getStateId(), $v);
}
}