RuntimeDataDescriber: Introduce boundedIntAuto, replacing boundedInt

closes #6096
boundedIntAuto automatically calculates the correct number of bits to use based on the given bounds. The bounds must be constant, of course.
This commit is contained in:
Dylan K. Taylor 2023-10-17 12:03:43 +01:00
parent 18b711aca8
commit d0d16cdeb7
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
23 changed files with 78 additions and 29 deletions

View File

@ -50,7 +50,7 @@ final class AmethystCluster extends Transparent{
private int $stage = self::STAGE_CLUSTER; private int $stage = self::STAGE_CLUSTER;
public function describeBlockItemState(RuntimeDataDescriber $w) : void{ public function describeBlockItemState(RuntimeDataDescriber $w) : void{
$w->boundedInt(2, self::STAGE_SMALL_BUD, self::STAGE_CLUSTER, $this->stage); $w->boundedIntAuto(self::STAGE_SMALL_BUD, self::STAGE_CLUSTER, $this->stage);
} }
public function getStage() : int{ return $this->stage; } public function getStage() : int{ return $this->stage; }

View File

@ -52,7 +52,7 @@ class Anvil extends Transparent implements Fallable{
private int $damage = self::UNDAMAGED; private int $damage = self::UNDAMAGED;
public function describeBlockItemState(RuntimeDataDescriber $w) : void{ public function describeBlockItemState(RuntimeDataDescriber $w) : void{
$w->boundedInt(2, self::UNDAMAGED, self::VERY_DAMAGED, $this->damage); $w->boundedIntAuto(self::UNDAMAGED, self::VERY_DAMAGED, $this->damage);
} }
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{

View File

@ -58,7 +58,7 @@ class Bamboo extends Transparent{
protected int $leafSize = self::NO_LEAVES; protected int $leafSize = self::NO_LEAVES;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(2, self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize); $w->boundedIntAuto(self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize);
$w->bool($this->thick); $w->bool($this->thick);
$w->bool($this->ready); $w->bool($this->ready);
} }

View File

@ -37,7 +37,7 @@ class Cake extends BaseCake{
protected int $bites = 0; protected int $bites = 0;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, 0, self::MAX_BITES, $this->bites); $w->boundedIntAuto(0, self::MAX_BITES, $this->bites);
} }
/** /**

View File

@ -48,7 +48,7 @@ class Candle extends Transparent{
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$this->encodeLitState($w); $this->encodeLitState($w);
$w->boundedInt(2, self::MIN_COUNT, self::MAX_COUNT, $this->count); $w->boundedIntAuto(self::MIN_COUNT, self::MAX_COUNT, $this->count);
} }
public function getCount() : int{ return $this->count; } public function getCount() : int{ return $this->count; }

View File

@ -49,7 +49,7 @@ class CaveVines extends Flowable{
protected bool $head = false; protected bool $head = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(5, 0, self::MAX_AGE, $this->age); $w->boundedIntAuto(0, self::MAX_AGE, $this->age);
$w->bool($this->berries); $w->bool($this->berries);
$w->bool($this->head); $w->bool($this->head);
} }

View File

@ -48,7 +48,7 @@ class CocoaBlock extends Transparent{
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing); $w->horizontalFacing($this->facing);
$w->boundedInt(2, 0, self::MAX_AGE, $this->age); $w->boundedIntAuto(0, self::MAX_AGE, $this->age);
} }
/** /**

View File

@ -42,7 +42,7 @@ class DaylightSensor extends Transparent{
protected bool $inverted = false; protected bool $inverted = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(4, 0, 15, $this->signalStrength); $w->boundedIntAuto(0, 15, $this->signalStrength);
$w->bool($this->inverted); $w->bool($this->inverted);
} }

View File

@ -39,7 +39,7 @@ class Farmland extends Transparent{
protected int $wetness = 0; //"moisture" blockstate property in PC protected int $wetness = 0; //"moisture" blockstate property in PC
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, 0, self::MAX_WETNESS, $this->wetness); $w->boundedIntAuto(0, self::MAX_WETNESS, $this->wetness);
} }
public function getWetness() : int{ return $this->wetness; } public function getWetness() : int{ return $this->wetness; }

View File

@ -38,7 +38,7 @@ abstract class FillableCauldron extends Transparent{
private int $fillLevel = self::MIN_FILL_LEVEL; private int $fillLevel = self::MIN_FILL_LEVEL;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, self::MIN_FILL_LEVEL, self::MAX_FILL_LEVEL, $this->fillLevel); $w->boundedIntAuto(self::MIN_FILL_LEVEL, self::MAX_FILL_LEVEL, $this->fillLevel);
} }
public function getFillLevel() : int{ return $this->fillLevel; } public function getFillLevel() : int{ return $this->fillLevel; }

View File

@ -35,7 +35,7 @@ final class Light extends Flowable{
private int $level = self::MAX_LIGHT_LEVEL; private int $level = self::MAX_LIGHT_LEVEL;
public function describeBlockItemState(RuntimeDataDescriber $w) : void{ public function describeBlockItemState(RuntimeDataDescriber $w) : void{
$w->boundedInt(4, self::MIN_LIGHT_LEVEL, self::MAX_LIGHT_LEVEL, $this->level); $w->boundedIntAuto(self::MIN_LIGHT_LEVEL, self::MAX_LIGHT_LEVEL, $this->level);
} }
public function getLightLevel() : int{ return $this->level; } public function getLightLevel() : int{ return $this->level; }

View File

@ -49,7 +49,7 @@ abstract class Liquid extends Transparent{
protected bool $still = false; protected bool $still = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, 0, self::MAX_DECAY, $this->decay); $w->boundedIntAuto(0, self::MAX_DECAY, $this->decay);
$w->bool($this->falling); $w->bool($this->falling);
$w->bool($this->still); $w->bool($this->still);
} }

View File

@ -47,7 +47,7 @@ class PinkPetals extends Flowable{
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing); $w->horizontalFacing($this->facing);
$w->boundedInt(2, self::MIN_COUNT, self::MAX_COUNT, $this->count); $w->boundedIntAuto(self::MIN_COUNT, self::MAX_COUNT, $this->count);
} }
public function getCount() : int{ public function getCount() : int{

View File

@ -47,7 +47,7 @@ class RedstoneRepeater extends Flowable{
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing); $w->horizontalFacing($this->facing);
$w->boundedInt(2, self::MIN_DELAY, self::MAX_DELAY, $this->delay); $w->boundedIntAuto(self::MIN_DELAY, self::MAX_DELAY, $this->delay);
$w->bool($this->powered); $w->bool($this->powered);
} }

View File

@ -39,7 +39,7 @@ class SeaPickle extends Transparent{
protected bool $underwater = false; protected bool $underwater = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(2, self::MIN_COUNT, self::MAX_COUNT, $this->count); $w->boundedIntAuto(self::MIN_COUNT, self::MAX_COUNT, $this->count);
$w->bool($this->underwater); $w->bool($this->underwater);
} }

View File

@ -47,7 +47,7 @@ class SnowLayer extends Flowable implements Fallable{
protected int $layers = self::MIN_LAYERS; protected int $layers = self::MIN_LAYERS;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, self::MIN_LAYERS, self::MAX_LAYERS, $this->layers); $w->boundedIntAuto(self::MIN_LAYERS, self::MAX_LAYERS, $this->layers);
} }
public function getLayers() : int{ return $this->layers; } public function getLayers() : int{ return $this->layers; }

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block\utils; namespace pocketmine\block\utils;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\data\runtime\RuntimeDataDescriber;
use function log;
/** /**
* This trait is used for blocks that have an age property. * This trait is used for blocks that have an age property.
@ -34,7 +33,7 @@ trait AgeableTrait{
protected int $age = 0; protected int $age = 0;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(((int) log(self::MAX_AGE, 2)) + 1, 0, self::MAX_AGE, $this->age); $w->boundedIntAuto(0, self::MAX_AGE, $this->age);
} }
public function getAge() : int{ return $this->age; } public function getAge() : int{ return $this->age; }

View File

@ -29,7 +29,7 @@ trait AnalogRedstoneSignalEmitterTrait{
protected int $signalStrength = 0; protected int $signalStrength = 0;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(4, 0, 15, $this->signalStrength); $w->boundedIntAuto(0, 15, $this->signalStrength);
} }
public function getOutputSignalStrength() : int{ return $this->signalStrength; } public function getOutputSignalStrength() : int{ return $this->signalStrength; }

View File

@ -31,7 +31,7 @@ trait SignLikeRotationTrait{
private $rotation = 0; private $rotation = 0;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->boundedInt(4, 0, 15, $this->rotation); $w->boundedIntAuto(0, 15, $this->rotation);
} }
public function getRotation() : int{ return $this->rotation; } public function getRotation() : int{ return $this->rotation; }

View File

@ -38,8 +38,17 @@ use pocketmine\math\Facing;
interface RuntimeDataDescriber extends RuntimeEnumDescriber{ interface RuntimeDataDescriber extends RuntimeEnumDescriber{
public function int(int $bits, int &$value) : void; public function int(int $bits, int &$value) : void;
/**
* @deprecated Use {@link RuntimeDataDescriber::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void; public function boundedInt(int $bits, int $min, int $max, int &$value) : void;
/**
* Same as boundedInt() but automatically calculates the required number of bits from the range.
* The range bounds must be constant.
*/
public function boundedIntAuto(int $min, int $max, int &$value) : void;
public function bool(bool &$value) : void; public function bool(bool &$value) : void;
public function horizontalFacing(int &$facing) : void; public function horizontalFacing(int &$facing) : void;

View File

@ -31,6 +31,7 @@ use pocketmine\math\Facing;
use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\AssumptionFailedError;
use function get_class; use function get_class;
use function intdiv; use function intdiv;
use function log;
use function spl_object_id; use function spl_object_id;
final class RuntimeDataReader implements RuntimeDataDescriber{ final class RuntimeDataReader implements RuntimeDataDescriber{
@ -58,7 +59,20 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
$value = $this->readInt($bits); $value = $this->readInt($bits);
} }
protected function readBoundedInt(int $bits, int $min, int $max) : int{ /**
* @deprecated Use {@link self::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{
$offset = $this->offset;
$this->boundedIntAuto($min, $max, $value);
$actualBits = $this->offset - $offset;
if($this->offset !== $offset + $bits){
throw new \InvalidArgumentException("Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
}
}
private function readBoundedIntAuto(int $min, int $max) : int{
$bits = ((int) log($max - $min, 2)) + 1;
$result = $this->readInt($bits) + $min; $result = $this->readInt($bits) + $min;
if($result < $min || $result > $max){ if($result < $min || $result > $max){
throw new InvalidSerializedRuntimeDataException("Value is outside the range $min - $max"); throw new InvalidSerializedRuntimeDataException("Value is outside the range $min - $max");
@ -66,8 +80,8 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
return $result; return $result;
} }
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{ public function boundedIntAuto(int $min, int $max, int &$value) : void{
$value = $this->readBoundedInt($bits, $min, $max); $value = $this->readBoundedIntAuto($min, $max);
} }
protected function readBool() : bool{ protected function readBool() : bool{
@ -162,7 +176,7 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
public function wallConnections(array &$connections) : void{ public function wallConnections(array &$connections) : void{
$result = []; $result = [];
$offset = 0; $offset = 0;
$packed = $this->readBoundedInt(7, 0, (3 ** 4) - 1); $packed = $this->readBoundedIntAuto(0, (3 ** 4) - 1);
foreach(Facing::HORIZONTAL as $facing){ foreach(Facing::HORIZONTAL as $facing){
$type = intdiv($packed, (3 ** $offset)) % 3; $type = intdiv($packed, (3 ** $offset)) % 3;
if($type !== 0){ if($type !== 0){

View File

@ -26,6 +26,7 @@ namespace pocketmine\data\runtime;
use pocketmine\block\utils\BrewingStandSlot; use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use function count; use function count;
use function log;
final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
use LegacyRuntimeEnumDescriberTrait; use LegacyRuntimeEnumDescriberTrait;
@ -44,8 +45,20 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
$this->addBits($bits); $this->addBits($bits);
} }
/**
* @deprecated Use {@link self::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{ public function boundedInt(int $bits, int $min, int $max, int &$value) : void{
$this->addBits($bits); $currentBits = $this->bits;
$this->boundedIntAuto($min, $max, $value);
$actualBits = $this->bits - $currentBits;
if($actualBits !== $bits){
throw new \InvalidArgumentException("Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
}
}
public function boundedIntAuto(int $min, int $max, int &$value) : void{
$this->addBits(((int) log($max - $min, 2)) + 1);
} }
public function bool(bool &$value) : void{ public function bool(bool &$value) : void{

View File

@ -28,6 +28,7 @@ use pocketmine\block\utils\WallConnectionType;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use function array_flip; use function array_flip;
use function log;
use function spl_object_id; use function spl_object_id;
final class RuntimeDataWriter implements RuntimeDataDescriber{ final class RuntimeDataWriter implements RuntimeDataDescriber{
@ -56,15 +57,28 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
$this->writeInt($bits, $value); $this->writeInt($bits, $value);
} }
protected function writeBoundedInt(int $bits, int $min, int $max, int $value) : void{ /**
* @deprecated Use {@link self::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{
$offset = $this->offset;
$this->writeBoundedIntAuto($min, $max, $value);
$actualBits = $this->offset - $offset;
if($actualBits !== $bits){
throw new \InvalidArgumentException("Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
}
}
private function writeBoundedIntAuto(int $min, int $max, int $value) : void{
if($value < $min || $value > $max){ if($value < $min || $value > $max){
throw new \InvalidArgumentException("Value $value is outside the range $min - $max"); throw new \InvalidArgumentException("Value $value is outside the range $min - $max");
} }
$bits = ((int) log($max - $min, 2)) + 1;
$this->writeInt($bits, $value - $min); $this->writeInt($bits, $value - $min);
} }
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{ public function boundedIntAuto(int $min, int $max, int &$value) : void{
$this->writeBoundedInt($bits, $min, $max, $value); $this->writeBoundedIntAuto($min, $max, $value);
} }
protected function writeBool(bool $value) : void{ protected function writeBool(bool $value) : void{
@ -153,7 +167,7 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
} * (3 ** $offset); } * (3 ** $offset);
$offset++; $offset++;
} }
$this->writeBoundedInt(7, 0, (3 ** 4) - 1, $packed); $this->writeBoundedIntAuto(0, (3 ** 4) - 1, $packed);
} }
/** /**