44 public const COLLISION_CUSTOM = 0;
45 public const COLLISION_CUBE = 1;
46 public const COLLISION_NONE = 2;
47 public const COLLISION_MAY_OVERFLOW = 3;
53 private array $fullList = [];
60 private array $typeIndex = [];
66 public array $light = [];
71 public array $lightFilter = [];
76 public array $blocksDirectSkyLight = [];
81 public array $blastResistance = [];
88 public array $collisionInfo = [];
90 public function __construct(){
92 $this->
register($block);
102 public function register(
Block $block) : void{
103 $typeId = $block->getTypeId();
105 if(isset($this->typeIndex[$typeId])){
106 throw new \InvalidArgumentException(
"Block ID $typeId is already used by another block");
109 $this->typeIndex[$typeId] = clone $block;
111 foreach($block->generateStatePermutations() as $v){
112 $this->fillStaticArrays($v->getStateId(), $v);
122 private static function overridesBlockMethod(\Closure $closure) : bool{
123 $declarer = (new \ReflectionFunction($closure))->getClosureScopeClass();
124 return $declarer !==
null && $declarer->getName() !== Block::class;
136 private static function calculateCollisionInfo(Block $block) : int{
138 self::overridesBlockMethod($block->getModelPositionOffset(...)) ||
139 self::overridesBlockMethod($block->readStateFromWorld(...))
145 return self::COLLISION_MAY_OVERFLOW;
150 $boxes = $block->getCollisionBoxes();
151 if(count($boxes) === 0){
152 return self::COLLISION_NONE;
156 count($boxes) === 1 &&
157 $boxes[0]->minX === 0.0 &&
158 $boxes[0]->minY === 0.0 &&
159 $boxes[0]->minZ === 0.0 &&
160 $boxes[0]->maxX === 1.0 &&
161 $boxes[0]->maxY === 1.0 &&
162 $boxes[0]->maxZ === 1.0
164 return self::COLLISION_CUBE;
167 foreach($boxes as $box){
169 $box->minX < 0 || $box->maxX > 1 ||
170 $box->minY < 0 || $box->maxY > 1 ||
171 $box->minZ < 0 || $box->maxZ > 1
173 return self::COLLISION_MAY_OVERFLOW;
177 return self::COLLISION_CUSTOM;
180 private function fillStaticArrays(
int $index, Block $block) : void{
181 $fullId = $block->getStateId();
182 if($index !== $fullId){
183 throw new AssumptionFailedError(
"Cannot fill static arrays for an invalid blockstate");
185 $this->fullList[$index] = $block;
186 $this->blastResistance[$index] = $block->getBreakInfo()->getBlastResistance();
187 $this->light[$index] = $block->getLightLevel();
188 $this->lightFilter[$index] = min(15, $block->getLightFilter() + LightUpdate::BASE_LIGHT_FILTER);
189 if($block->blocksDirectSkyLight()){
190 $this->blocksDirectSkyLight[$index] =
true;
193 $this->collisionInfo[$index] = self::calculateCollisionInfo($block);
197 public function fromStateId(
int $stateId) : Block{
199 throw new \InvalidArgumentException(
"Block state ID cannot be negative");
201 if(isset($this->fullList[$stateId])) {
202 $block = clone $this->fullList[$stateId];
204 $typeId = $stateId >> Block::INTERNAL_STATE_DATA_BITS;
205 $stateData = ($stateId ^ $typeId) & Block::INTERNAL_STATE_DATA_MASK;
206 $block =
new UnknownBlock(
new BID($typeId),
new BlockTypeInfo(BreakInfo::instant()), $stateData);
217 return $this->fullList;