World->getSafeSpawn() now throws if the target is in ungenerated terrain, instead of silently returning the default

this WILL cause crashes in some cases on slower machines (#2724), but it's
better than randomly spawning at the top of the map.
This commit is contained in:
Dylan K. Taylor 2020-11-26 19:36:33 +00:00
parent 4520e425c1
commit fd99445c5b

View File

@ -2371,6 +2371,9 @@ class World implements ChunkManager{
return abs($X - $spawnX) <= 1 and abs($Z - $spawnZ) <= 1;
}
/**
* @throws WorldException if the terrain is not generated
*/
public function getSafeSpawn(?Vector3 $spawn = null) : Position{
if(!($spawn instanceof Vector3) or $spawn->y < 1){
$spawn = $this->getSpawnLocation();
@ -2379,31 +2382,31 @@ class World implements ChunkManager{
$max = $this->worldHeight;
$v = $spawn->floor();
$chunk = $this->getOrLoadChunkAtPosition($v, false);
if($chunk === null || !$chunk->isGenerated()){
throw new WorldException("Cannot find a safe spawn point in non-generated terrain");
}
$x = (int) $v->x;
$y = $v->y;
$z = (int) $v->z;
if($chunk !== null and $chunk->isGenerated()){
$y = (int) min($max - 2, $v->y);
$wasAir = $this->getBlockAt($x, $y - 1, $z)->getId() === BlockLegacyIds::AIR; //TODO: bad hack, clean up
for(; $y > 0; --$y){
if($this->getBlockAt($x, $y, $z)->isFullCube()){
if($wasAir){
$y++;
break;
}
}else{
$wasAir = true;
$y = (int) min($max - 2, $v->y);
$wasAir = $this->getBlockAt($x, $y - 1, $z)->getId() === BlockLegacyIds::AIR; //TODO: bad hack, clean up
for(; $y > 0; --$y){
if($this->getBlockAt($x, $y, $z)->isFullCube()){
if($wasAir){
$y++;
break;
}
}else{
$wasAir = true;
}
}
for(; $y >= 0 and $y < $max; ++$y){
if(!$this->getBlockAt($x, $y + 1, $z)->isFullCube()){
if(!$this->getBlockAt($x, $y, $z)->isFullCube()){
return new Position($spawn->x, $y === (int) $spawn->y ? $spawn->y : $y, $spawn->z, $this);
}
}else{
++$y;
for(; $y >= 0 and $y < $max; ++$y){
if(!$this->getBlockAt($x, $y + 1, $z)->isFullCube()){
if(!$this->getBlockAt($x, $y, $z)->isFullCube()){
return new Position($spawn->x, $y === (int) $spawn->y ? $spawn->y : $y, $spawn->z, $this);
}
}else{
++$y;
}
}