mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 08:44:01 +00:00
Further refactors to prepare for y=-64 lower limit
This commit is contained in:
parent
b844c4266d
commit
eb9a68edee
@ -867,6 +867,7 @@ This version features substantial changes to the network system, improving coher
|
||||
- `World->populateChunk()` has been split into `World->requestChunkPopulation()` and `World->orderChunkPopulation()`.
|
||||
- The following API methods have changed behaviour:
|
||||
- `World->getChunk()` no longer tries to load chunks from disk. If the chunk is not already in memory, null is returned. (This behaviour now properly matches other `ChunkManager` implementations.)
|
||||
- `World->getHighestBlockAt()` now returns `null` instead of `-1` if the target X/Z column contains no blocks.
|
||||
- The following methods now throw `WorldException` when targeting ungenerated terrain:
|
||||
- `World->getSafeSpawn()` (previously it just silently returned the input position)
|
||||
- `World->getHighestBlockAt()` (previously it returned -1)
|
||||
|
@ -49,7 +49,7 @@ class ChorusFruit extends Food{
|
||||
|
||||
$origin = $consumer->getPosition();
|
||||
$minX = $origin->getFloorX() - 8;
|
||||
$minY = min($origin->getFloorY(), $consumer->getWorld()->getWorldHeight()) - 8;
|
||||
$minY = min($origin->getFloorY(), $consumer->getWorld()->getMaxY()) - 8;
|
||||
$minZ = $origin->getFloorZ() - 8;
|
||||
|
||||
$maxX = $minX + 16;
|
||||
|
@ -45,9 +45,14 @@ interface ChunkManager{
|
||||
public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void;
|
||||
|
||||
/**
|
||||
* Returns the height of the world
|
||||
* Returns the lowest buildable Y coordinate of the world
|
||||
*/
|
||||
public function getWorldHeight() : int;
|
||||
public function getMinY() : int;
|
||||
|
||||
/**
|
||||
* Returns the highest buildable Y coordinate of the world
|
||||
*/
|
||||
public function getMaxY() : int;
|
||||
|
||||
/**
|
||||
* Returns whether the specified coordinates are within the valid world boundaries, taking world format limitations
|
||||
|
@ -35,13 +35,13 @@ class SimpleChunkManager implements ChunkManager{
|
||||
protected $chunks = [];
|
||||
|
||||
/** @var int */
|
||||
protected $worldHeight;
|
||||
private $minY;
|
||||
/** @var int */
|
||||
private $maxY;
|
||||
|
||||
/**
|
||||
* SimpleChunkManager constructor.
|
||||
*/
|
||||
public function __construct(int $worldHeight = World::Y_MAX){
|
||||
$this->worldHeight = $worldHeight;
|
||||
public function __construct(int $minY, int $maxY){
|
||||
$this->minY = $minY;
|
||||
$this->maxY = $maxY;
|
||||
}
|
||||
|
||||
public function getBlockAt(int $x, int $y, int $z) : Block{
|
||||
@ -71,14 +71,18 @@ class SimpleChunkManager implements ChunkManager{
|
||||
$this->chunks = [];
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
return $this->worldHeight;
|
||||
public function getMinY() : int{
|
||||
return $this->minY;
|
||||
}
|
||||
|
||||
public function getMaxY() : int{
|
||||
return $this->maxY;
|
||||
}
|
||||
|
||||
public function isInWorld(int $x, int $y, int $z) : bool{
|
||||
return (
|
||||
$x <= Limits::INT32_MAX and $x >= Limits::INT32_MIN and
|
||||
$y < $this->worldHeight and $y >= 0 and
|
||||
$y < $this->maxY and $y >= $this->minY and
|
||||
$z <= Limits::INT32_MAX and $z >= Limits::INT32_MIN
|
||||
);
|
||||
}
|
||||
|
@ -174,7 +174,9 @@ class World implements ChunkManager{
|
||||
private $providerGarbageCollectionTicker = 0;
|
||||
|
||||
/** @var int */
|
||||
private $worldHeight;
|
||||
private $minY;
|
||||
/** @var int */
|
||||
private $maxY;
|
||||
|
||||
/** @var ChunkLoader[] */
|
||||
private $loaders = [];
|
||||
@ -383,7 +385,8 @@ class World implements ChunkManager{
|
||||
$this->displayName = $this->provider->getWorldData()->getName();
|
||||
$this->logger = new \PrefixedLogger($server->getLogger(), "World: $this->displayName");
|
||||
|
||||
$this->worldHeight = $this->provider->getWorldHeight();
|
||||
$this->minY = $this->provider->getWorldMinY();
|
||||
$this->maxY = $this->provider->getWorldMaxY();
|
||||
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.level.preparing", [$this->displayName]));
|
||||
$this->generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator(), true);
|
||||
@ -1335,7 +1338,7 @@ class World implements ChunkManager{
|
||||
public function isInWorld(int $x, int $y, int $z) : bool{
|
||||
return (
|
||||
$x <= Limits::INT32_MAX and $x >= Limits::INT32_MIN and
|
||||
$y < $this->worldHeight and $y >= 0 and
|
||||
$y < $this->maxY and $y >= $this->minY and
|
||||
$z <= Limits::INT32_MAX and $z >= Limits::INT32_MIN
|
||||
);
|
||||
}
|
||||
@ -2089,10 +2092,10 @@ class World implements ChunkManager{
|
||||
/**
|
||||
* Gets the highest block Y value at a specific $x and $z
|
||||
*
|
||||
* @return int 0-255, or -1 if the column is empty
|
||||
* @return int|null 0-255, or null if the column is empty
|
||||
* @throws WorldException if the terrain is not generated
|
||||
*/
|
||||
public function getHighestBlockAt(int $x, int $z) : int{
|
||||
public function getHighestBlockAt(int $x, int $z) : ?int{
|
||||
if(($chunk = $this->loadChunk($x >> 4, $z >> 4)) !== null){
|
||||
return $chunk->getHighestBlockAt($x & 0x0f, $z & 0x0f);
|
||||
}
|
||||
@ -2481,7 +2484,7 @@ class World implements ChunkManager{
|
||||
$spawn = $this->getSpawnLocation();
|
||||
}
|
||||
|
||||
$max = $this->worldHeight;
|
||||
$max = $this->maxY;
|
||||
$v = $spawn->floor();
|
||||
$chunk = $this->getOrLoadChunkAtPosition($v);
|
||||
if($chunk === null){
|
||||
@ -2491,7 +2494,7 @@ class World implements ChunkManager{
|
||||
$z = (int) $v->z;
|
||||
$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){
|
||||
for(; $y > $this->minY; --$y){
|
||||
if($this->getBlockAt($x, $y, $z)->isFullCube()){
|
||||
if($wasAir){
|
||||
$y++;
|
||||
@ -2502,7 +2505,7 @@ class World implements ChunkManager{
|
||||
}
|
||||
}
|
||||
|
||||
for(; $y >= 0 and $y < $max; ++$y){
|
||||
for(; $y >= $this->minY 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);
|
||||
@ -2575,8 +2578,12 @@ class World implements ChunkManager{
|
||||
return $this->provider->getWorldData()->getSeed();
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
return $this->worldHeight;
|
||||
public function getMinY() : int{
|
||||
return $this->minY;
|
||||
}
|
||||
|
||||
public function getMaxY() : int{
|
||||
return $this->maxY;
|
||||
}
|
||||
|
||||
public function getDifficulty() : int{
|
||||
|
@ -131,17 +131,17 @@ class Chunk{
|
||||
* @param int $x 0-15
|
||||
* @param int $z 0-15
|
||||
*
|
||||
* @return int 0-255, or -1 if there are no blocks in the column
|
||||
* @return int|null 0-255, or null if there are no blocks in the column
|
||||
*/
|
||||
public function getHighestBlockAt(int $x, int $z) : int{
|
||||
public function getHighestBlockAt(int $x, int $z) : ?int{
|
||||
for($y = $this->subChunks->count() - 1; $y >= 0; --$y){
|
||||
$height = $this->getSubChunk($y)->getHighestBlockAt($x, $z) | ($y << 4);
|
||||
if($height !== -1){
|
||||
return $height;
|
||||
$height = $this->getSubChunk($y)->getHighestBlockAt($x, $z);
|
||||
if($height !== null){
|
||||
return $height | ($y << 4);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,9 +96,9 @@ class SubChunk{
|
||||
return $this->blockLayers;
|
||||
}
|
||||
|
||||
public function getHighestBlockAt(int $x, int $z) : int{
|
||||
public function getHighestBlockAt(int $x, int $z) : ?int{
|
||||
if(count($this->blockLayers) === 0){
|
||||
return -1;
|
||||
return null;
|
||||
}
|
||||
for($y = 15; $y >= 0; --$y){
|
||||
if($this->blockLayers[0]->get($x, $y, $z) !== $this->emptyBlockId){
|
||||
@ -106,7 +106,7 @@ class SubChunk{
|
||||
}
|
||||
}
|
||||
|
||||
return -1; //highest block not in this subchunk
|
||||
return null; //highest block not in this subchunk
|
||||
}
|
||||
|
||||
public function getBlockSkyLightArray() : LightArray{
|
||||
|
@ -36,10 +36,15 @@ interface WorldProvider{
|
||||
*/
|
||||
public function __construct(string $path);
|
||||
|
||||
/**
|
||||
* Returns the lowest buildable Y coordinate of this world
|
||||
*/
|
||||
public function getWorldMinY() : int;
|
||||
|
||||
/**
|
||||
* Gets the build height limit of this world
|
||||
*/
|
||||
public function getWorldHeight() : int;
|
||||
public function getWorldMaxY() : int;
|
||||
|
||||
public function getPath() : string;
|
||||
|
||||
|
@ -132,7 +132,11 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
|
||||
return new BedrockWorldData($this->getPath() . DIRECTORY_SEPARATOR . "level.dat");
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
public function getWorldMinY() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getWorldMaxY() : int{
|
||||
return 256;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,11 @@ class Anvil extends RegionWorldProvider{
|
||||
return 19133;
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
public function getWorldMinY() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getWorldMaxY() : int{
|
||||
//TODO: add world height options
|
||||
return 256;
|
||||
}
|
||||
|
@ -106,7 +106,11 @@ class McRegion extends RegionWorldProvider{
|
||||
return 19132;
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
public function getWorldMinY() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getWorldMaxY() : int{
|
||||
//TODO: add world height options
|
||||
return 128;
|
||||
}
|
||||
|
@ -50,7 +50,11 @@ class PMAnvil extends RegionWorldProvider{
|
||||
return -1; //Not a PC format, only PocketMine-MP
|
||||
}
|
||||
|
||||
public function getWorldHeight() : int{
|
||||
public function getWorldMinY() : int{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getWorldMaxY() : int{
|
||||
return 256;
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,9 @@ class GeneratorRegisterTask extends AsyncTask{
|
||||
/** @var int */
|
||||
public $worldId;
|
||||
/** @var int */
|
||||
public $worldHeight = World::Y_MAX;
|
||||
public $worldMinY;
|
||||
/** @var int */
|
||||
public $worldMaxY;
|
||||
|
||||
/**
|
||||
* @param mixed[] $generatorSettings
|
||||
@ -54,7 +56,8 @@ class GeneratorRegisterTask extends AsyncTask{
|
||||
$this->settings = igbinary_serialize($generatorSettings);
|
||||
$this->seed = $world->getSeed();
|
||||
$this->worldId = $world->getId();
|
||||
$this->worldHeight = $world->getWorldHeight();
|
||||
$this->worldMinY = $world->getMinY();
|
||||
$this->worldMaxY = $world->getMaxY();
|
||||
}
|
||||
|
||||
public function onRun() : void{
|
||||
@ -63,6 +66,6 @@ class GeneratorRegisterTask extends AsyncTask{
|
||||
* @see Generator::__construct()
|
||||
*/
|
||||
$generator = new $this->generatorClass($this->seed, igbinary_unserialize($this->settings));
|
||||
ThreadLocalGeneratorContext::register(new ThreadLocalGeneratorContext($generator, $this->worldHeight), $this->worldId);
|
||||
ThreadLocalGeneratorContext::register(new ThreadLocalGeneratorContext($generator, $this->worldMinY, $this->worldMaxY), $this->worldId);
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class PopulationTask extends AsyncTask{
|
||||
throw new AssumptionFailedError("Generator context should have been initialized before any PopulationTask execution");
|
||||
}
|
||||
$generator = $context->getGenerator();
|
||||
$manager = new SimpleChunkManager($context->getWorldHeight());
|
||||
$manager = new SimpleChunkManager($context->getWorldMinY(), $context->getWorldMaxY());
|
||||
|
||||
/** @var Chunk[] $chunks */
|
||||
$chunks = [];
|
||||
|
@ -47,15 +47,21 @@ final class ThreadLocalGeneratorContext{
|
||||
|
||||
/** @var Generator */
|
||||
private $generator;
|
||||
/** @var int */
|
||||
private $worldHeight;
|
||||
|
||||
public function __construct(Generator $generator, int $worldHeight){
|
||||
/** @var int */
|
||||
private $worldMinY;
|
||||
/** @var int */
|
||||
private $worldMaxY;
|
||||
|
||||
public function __construct(Generator $generator, int $worldMinY, int $worldMaxY){
|
||||
$this->generator = $generator;
|
||||
$this->worldHeight = $worldHeight;
|
||||
$this->worldMinY = $worldMinY;
|
||||
$this->worldMaxY = $worldMaxY;
|
||||
}
|
||||
|
||||
public function getGenerator() : Generator{ return $this->generator; }
|
||||
|
||||
public function getWorldHeight() : int{ return $this->worldHeight; }
|
||||
public function getWorldMinY() : int{ return $this->worldMinY; }
|
||||
|
||||
public function getWorldMaxY() : int{ return $this->worldMaxY; }
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class LightPopulationTask extends AsyncTask{
|
||||
public function onRun() : void{
|
||||
$chunk = FastChunkSerializer::deserialize($this->chunk);
|
||||
|
||||
$manager = new SimpleChunkManager();
|
||||
$manager = new SimpleChunkManager(World::Y_MIN, World::Y_MAX);
|
||||
$manager->setChunk($this->chunkX, $this->chunkZ, $chunk);
|
||||
|
||||
$blockFactory = BlockFactory::getInstance();
|
||||
|
@ -178,7 +178,7 @@ class SkyLightUpdate extends LightUpdate{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$result = HeightArray::fill(0);
|
||||
$result = HeightArray::fill(World::Y_MIN);
|
||||
if($maxSubChunkY === -1){ //whole column is definitely empty
|
||||
return $result;
|
||||
}
|
||||
@ -188,16 +188,16 @@ class SkyLightUpdate extends LightUpdate{
|
||||
$y = null;
|
||||
for($subChunkY = $maxSubChunkY; $subChunkY >= 0; $subChunkY--){
|
||||
$subHighestBlockY = $chunk->getSubChunk($subChunkY)->getHighestBlockAt($x, $z);
|
||||
if($subHighestBlockY !== -1){
|
||||
if($subHighestBlockY !== null){
|
||||
$y = ($subChunkY * 16) + $subHighestBlockY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($y === null){ //no blocks in the column
|
||||
$result->set($x, $z, 0);
|
||||
$result->set($x, $z, World::Y_MIN);
|
||||
}else{
|
||||
for(; $y >= 0; --$y){
|
||||
for(; $y >= World::Y_MIN; --$y){
|
||||
if($directSkyLightBlockers[$chunk->getFullBlock($x, $y, $z)]){
|
||||
$result->set($x, $z, $y + 1);
|
||||
break;
|
||||
@ -221,7 +221,10 @@ class SkyLightUpdate extends LightUpdate{
|
||||
*/
|
||||
private static function recalculateHeightMapColumn(Chunk $chunk, int $x, int $z, \SplFixedArray $directSkyLightBlockers) : int{
|
||||
$y = $chunk->getHighestBlockAt($x, $z);
|
||||
for(; $y >= 0; --$y){
|
||||
if($y === null){
|
||||
return World::Y_MIN;
|
||||
}
|
||||
for(; $y >= World::Y_MIN; --$y){
|
||||
if($directSkyLightBlockers[$chunk->getFullBlock($x, $y, $z)]){
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user