offset + $bits > $this->maxBits){ throw new \InvalidArgumentException("Bit buffer cannot be larger than $this->maxBits bits (already have $this->offset bits)"); } if(($value & (~0 << $bits)) !== 0){ throw new \InvalidArgumentException("Value $value does not fit into $bits bits"); } $this->value |= ($value << $this->offset); $this->offset += $bits; return $this; } /** @return $this */ public function writeBoundedInt(int $bits, int $min, int $max, int $value) : self{ if($value < $min || $value > $max){ throw new \InvalidArgumentException("Value $value is outside the range $min - $max"); } $this->writeInt($bits, $value - $min); return $this; } /** @return $this */ public function writeBool(bool $value) : self{ return $this->writeInt(1, $value ? 1 : 0); } /** @return $this */ public function writeHorizontalFacing(int $facing) : self{ return $this->writeInt(2, match($facing){ Facing::NORTH => 0, Facing::EAST => 1, Facing::SOUTH => 2, Facing::WEST => 3, default => throw new \InvalidArgumentException("Invalid horizontal facing $facing") }); } public function writeFacing(int $facing) : self{ return $this->writeInt(3, match($facing){ 0 => Facing::DOWN, 1 => Facing::UP, 2 => Facing::NORTH, 3 => Facing::SOUTH, 4 => Facing::WEST, 5 => Facing::EAST, default => throw new \InvalidArgumentException("Invalid facing $facing") }); } public function writeAxis(int $axis) : self{ return $this->writeInt(2, match($axis){ Axis::X => 0, Axis::Z => 1, Axis::Y => 2, default => throw new \InvalidArgumentException("Invalid axis $axis") }); } public function writeHorizontalAxis(int $axis) : self{ return $this->writeInt(1, match($axis){ Axis::X => 0, Axis::Z => 1, default => throw new \InvalidArgumentException("Invalid horizontal axis $axis") }); } /** * @param WallConnectionType[] $connections * @phpstan-param array $connections */ public function writeWallConnections(array $connections) : self{ //TODO: we can pack this into 7 bits instead of 8 foreach(Facing::HORIZONTAL as $facing){ $this->writeBoundedInt(2, 0, 2, match($connections[$facing] ?? null){ null => 0, WallConnectionType::SHORT() => 1, WallConnectionType::TALL() => 2, default => throw new AssumptionFailedError("Unreachable") }); } return $this; } public function getValue() : int{ return $this->value; } public function getOffset() : int{ return $this->offset; } }