Skip to content

Commit

Permalink
More improvements, optimize getCollisionBlocks() too
Browse files Browse the repository at this point in the history
  • Loading branch information
dktapps committed Feb 2, 2025
1 parent 195241a commit 08d27be
Showing 1 changed file with 53 additions and 29 deletions.
82 changes: 53 additions & 29 deletions src/world/World.php
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ class World implements ChunkManager{

private \Logger $logger;

private RuntimeBlockStateRegistry $blockStateRegistry;

/**
* @phpstan-return ChunkPosHash
*/
Expand Down Expand Up @@ -488,6 +490,7 @@ public function __construct(
$this->displayName = $this->provider->getWorldData()->getName();
$this->logger = new \PrefixedLogger($server->getLogger(), "World: $this->displayName");

$this->blockStateRegistry = RuntimeBlockStateRegistry::getInstance();
$this->minY = $this->provider->getWorldMinY();
$this->maxY = $this->provider->getWorldMaxY();

Expand Down Expand Up @@ -559,7 +562,7 @@ private function initRandomTickBlocksFromConfig(ServerConfigGroup $cfg) : void{
}catch(BlockStateDeserializeException){
continue;
}
$block = RuntimeBlockStateRegistry::getInstance()->fromStateId(GlobalBlockStateHandlers::getDeserializer()->deserialize($blockStateData));
$block = $this->blockStateRegistry->fromStateId(GlobalBlockStateHandlers::getDeserializer()->deserialize($blockStateData));
}else{
//TODO: we probably ought to log an error here
continue;
Expand All @@ -570,7 +573,7 @@ private function initRandomTickBlocksFromConfig(ServerConfigGroup $cfg) : void{
}
}

foreach(RuntimeBlockStateRegistry::getInstance()->getAllKnownStates() as $state){
foreach($this->blockStateRegistry->getAllKnownStates() as $state){
$dontTickName = $dontTickBlocks[$state->getTypeId()] ?? null;
if($dontTickName === null && $state->ticksRandomly()){
$this->randomTickBlocks[$state->getStateId()] = true;
Expand Down Expand Up @@ -1394,7 +1397,7 @@ private function tickChunk(int $chunkX, int $chunkZ) : void{
$entity->onRandomUpdate();
}

$blockFactory = RuntimeBlockStateRegistry::getInstance();
$blockFactory = $this->blockStateRegistry;
foreach($chunk->getSubChunks() as $Y => $subChunk){
if(!$subChunk->isEmptyFast()){
$k = 0;
Expand Down Expand Up @@ -1528,13 +1531,18 @@ public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false)

$collides = [];

$collisionInfo = $this->blockStateRegistry->collisionInfo;
if($targetFirst){
for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getBlockAt($x, $y, $z);
if($block->collidesWithBB($bb)){
return [$block];
$stateCollisionInfo = $this->getBlockCollisionInfo($x, $y, $z, $collisionInfo);
if(match($stateCollisionInfo){
RuntimeBlockStateRegistry::COLLISION_CUBE => true,
RuntimeBlockStateRegistry::COLLISION_NONE => false,
default => $this->getBlockAt($x, $y, $z)->collidesWithBB($bb)
}){
return [$this->getBlockAt($x, $y, $z)];
}
}
}
Expand All @@ -1543,9 +1551,13 @@ public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false)
for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){
for($y = $minY; $y <= $maxY; ++$y){
$block = $this->getBlockAt($x, $y, $z);
if($block->collidesWithBB($bb)){
$collides[] = $block;
$stateCollisionInfo = $this->getBlockCollisionInfo($x, $y, $z, $collisionInfo);
if(match($stateCollisionInfo){
RuntimeBlockStateRegistry::COLLISION_CUBE => true,
RuntimeBlockStateRegistry::COLLISION_NONE => false,
default => $this->getBlockAt($x, $y, $z)->collidesWithBB($bb)
}){
$collides[] = $this->getBlockAt($x, $y, $z);
}
}
}
Expand All @@ -1555,6 +1567,28 @@ public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false)
return $collides;
}

/**
* @param int[] $collisionInfo
* @phpstan-param array<int, int> $collisionInfo
*/
private function getBlockCollisionInfo(int $x, int $y, int $z, array $collisionInfo) : int{
if(!$this->isInWorld($x, $y, $z)){
return RuntimeBlockStateRegistry::COLLISION_NONE;
}
$chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE);
if($chunk === null){
return RuntimeBlockStateRegistry::COLLISION_NONE;
}
$stateId = $chunk
->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)
->getBlockStateId(
$x & SubChunk::COORD_MASK,
$y & SubChunk::COORD_MASK,
$z & SubChunk::COORD_MASK
);
return $collisionInfo[$stateId];
}

/**
* Returns a list of all block AABBs which overlap the full block area at the given coordinates.
* This checks a padding of 1 block around the coordinates to account for oversized AABBs of blocks like fences.
Expand All @@ -1567,14 +1601,7 @@ public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false)
* @phpstan-return list<AxisAlignedBB>
*/
private function getBlockCollisionBoxesForCell(int $x, int $y, int $z, array $collisionInfo) : array{
if($y < $this->minY || $y > $this->maxY){
return [];
}
$stateId = $this
->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)
?->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK) ?? Block::EMPTY_STATE_ID;

$stateCollisionInfo = $collisionInfo[$stateId] ?? throw new AssumptionFailedError("This should always exist");
$stateCollisionInfo = $this->getBlockCollisionInfo($x, $y, $z, $collisionInfo);
$boxes = match($stateCollisionInfo){
RuntimeBlockStateRegistry::COLLISION_NONE => [],
RuntimeBlockStateRegistry::COLLISION_CUBE => [AxisAlignedBB::one()->offset($x, $y, $z)],
Expand All @@ -1585,17 +1612,14 @@ private function getBlockCollisionBoxesForCell(int $x, int $y, int $z, array $co
if($stateCollisionInfo !== RuntimeBlockStateRegistry::COLLISION_CUBE){
$cellBB = null;
foreach(Facing::OFFSET as [$dx, $dy, $dz]){
$offsetX = $x + $dx;
$offsetY = $y + $dy;
if($offsetY < $this->minY || $offsetY > $this->maxY){
continue;
}
$stateId = $this
->getChunk(($x + $dx) >> Chunk::COORD_BIT_SIZE, ($z + $dz) >> Chunk::COORD_BIT_SIZE)
?->getBlockStateId(($x + $dx) & Chunk::COORD_MASK, $offsetY, ($z + $dz) & Chunk::COORD_MASK) ?? Block::EMPTY_STATE_ID;
if($collisionInfo[$stateId] === RuntimeBlockStateRegistry::COLLISION_MAY_OVERFLOW){
$offsetZ = $z + $dz;
$stateCollisionInfo = $this->getBlockCollisionInfo($offsetX, $offsetY, $offsetZ, $collisionInfo);
if($stateCollisionInfo === RuntimeBlockStateRegistry::COLLISION_MAY_OVERFLOW){
//avoid allocating this unless it's needed
$cellBB ??= AxisAlignedBB::one()->offset($x, $y, $z);
$extraBoxes = $this->getBlockAt($x + $dx, $offsetY, $z + $dz)->getCollisionBoxes();
$extraBoxes = $this->getBlockAt($offsetX, $offsetY, $offsetZ)->getCollisionBoxes();
foreach($extraBoxes as $extraBox){
if($extraBox->intersectsWith($cellBB)){
$boxes[] = $extraBox;
Expand All @@ -1622,7 +1646,7 @@ public function getBlockCollisionBoxes(AxisAlignedBB $bb) : array{

$collides = [];

$collisionInfo = RuntimeBlockStateRegistry::getInstance()->collisionInfo;
$collisionInfo = $this->blockStateRegistry->collisionInfo;

for($z = $minZ; $z <= $maxZ; ++$z){
for($x = $minX; $x <= $maxX; ++$x){
Expand Down Expand Up @@ -1825,7 +1849,7 @@ public function updateAllLight(int $x, int $y, int $z) : void{
return;
}

$blockFactory = RuntimeBlockStateRegistry::getInstance();
$blockFactory = $this->blockStateRegistry;
$this->timings->doBlockSkyLightUpdates->startTiming();
if($this->skyLightUpdate === null){
$this->skyLightUpdate = new SkyLightUpdate(new SubChunkExplorer($this), $blockFactory->lightFilter, $blockFactory->blocksDirectSkyLight);
Expand Down Expand Up @@ -1944,7 +1968,7 @@ public function getBlockAt(int $x, int $y, int $z, bool $cached = true, bool $ad

$chunk = $this->chunks[$chunkHash] ?? null;
if($chunk !== null){
$block = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK));
$block = $this->blockStateRegistry->fromStateId($chunk->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK));
}else{
$addToCache = false;
$block = VanillaBlocks::AIR();
Expand Down Expand Up @@ -2603,7 +2627,7 @@ public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{
$localY = $tilePosition->getFloorY();
$localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK;

$newBlock = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($localX, $localY, $localZ));
$newBlock = $this->blockStateRegistry->fromStateId($chunk->getBlockStateId($localX, $localY, $localZ));
$expectedTileClass = $newBlock->getIdInfo()->getTileClass();
if(
$expectedTileClass === null || //new block doesn't expect a tile
Expand Down

0 comments on commit 08d27be

Please sign in to comment.