35 use LegacyRuntimeEnumDescriberTrait;
37 private int $value = 0;
38 private int $offset = 0;
40 public function __construct(
44 public function writeInt(
int $bits,
int $value) :
void{
45 if($this->offset + $bits > $this->maxBits){
46 throw new \InvalidArgumentException(
"Bit buffer cannot be larger than $this->maxBits bits (already have $this->offset bits)");
48 if(($value & (~0 << $bits)) !== 0){
49 throw new \InvalidArgumentException(
"Value $value does not fit into $bits bits");
52 $this->value |= ($value << $this->offset);
53 $this->offset += $bits;
56 public function int(
int $bits,
int &$value) :
void{
57 $this->writeInt($bits, $value);
63 public function boundedInt(
int $bits,
int $min,
int $max,
int &$value) : void{
64 $offset = $this->offset;
65 $this->writeBoundedIntAuto($min, $max, $value);
66 $actualBits = $this->offset - $offset;
67 if($actualBits !== $bits){
68 throw new \InvalidArgumentException(
"Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
72 private function writeBoundedIntAuto(
int $min,
int $max,
int $value) : void{
73 if($value < $min || $value > $max){
74 throw new \InvalidArgumentException(
"Value $value is outside the range $min - $max");
76 $bits = ((int) log($max - $min, 2)) + 1;
77 $this->writeInt($bits, $value - $min);
81 $this->writeBoundedIntAuto($min, $max, $value);
84 protected function writeBool(
bool $value) : void{
85 $this->writeInt(1, $value ? 1 : 0);
88 public function bool(
bool &$value) : void{
89 $this->writeBool($value);
92 public function horizontalFacing(
int &$facing) : void{
93 $this->writeInt(2, match($facing){
98 default =>
throw new \InvalidArgumentException(
"Invalid horizontal facing $facing")
106 $uniqueFaces = array_flip($faces);
107 foreach(Facing::ALL as $facing){
108 $this->writeBool(isset($uniqueFaces[$facing]));
116 $uniqueFaces = array_flip($faces);
117 foreach(Facing::HORIZONTAL as $facing){
118 $this->writeBool(isset($uniqueFaces[$facing]));
122 public function facing(
int &$facing) : void{
123 $this->writeInt(3, match($facing){
130 default =>
throw new \InvalidArgumentException(
"Invalid facing $facing")
134 public function facingExcept(
int &$facing,
int $except) : void{
135 $this->facing($facing);
138 public function axis(
int &$axis) : void{
139 $this->writeInt(2, match($axis){
143 default =>
throw new \InvalidArgumentException(
"Invalid axis $axis")
147 public function horizontalAxis(
int &$axis) : void{
148 $this->writeInt(1, match($axis){
151 default =>
throw new \InvalidArgumentException(
"Invalid horizontal axis $axis")
162 foreach(Facing::HORIZONTAL as $facing){
163 $packed += match($connections[$facing] ??
null){
165 WallConnectionType::SHORT => 1,
166 WallConnectionType::TALL => 2,
170 $this->writeBoundedIntAuto(0, (3 ** 4) - 1, $packed);
180 $this->enumSet($slots, BrewingStandSlot::cases());
183 public function railShape(
int &$railShape) : void{
184 $this->int(4, $railShape);
187 public function straightOnlyRailShape(
int &$railShape) : void{
188 $this->int(3, $railShape);
191 public function enum(\UnitEnum &$case) :
void{
192 $metadata = RuntimeEnumMetadata::from($case);
193 $this->writeInt($metadata->bits, $metadata->enumToInt($case));
196 public function enumSet(array &$set, array $allCases) : void{
197 foreach($allCases as $case){
198 $this->writeBool(isset($set[spl_object_id($case)]));
202 public function getValue() : int{ return $this->value; }
204 public function getOffset() : int{ return $this->offset; }