When i use getHighestBlockAt it returns -1 no matter the x(int) and z(int) coords PHP: $y = $this->getLevelByName()->getHighestBlockAt($x, $z); Note: '$this->getLevelByName()' is my WorldGenerator class to return an instance of \pocketmine\level\Level
That's the normal behaviour of the function for chunks that aren't generated. You'll need to wait for the chunk to generate before calling that method. I did something similar to combat the problem of teleporting players to a random spot in the wilderness. PHP: /** @var Position $pos */// $pos = Position instance with x = random, y = 0, z = random.RegionUtils::onChunkGenerate($pos, function() use($player, $pos) : void{ $pos->y = $pos->getLevel()->getHighestBlockAt($pos->x, $pos->z) + 1; $player->teleport($pos);}); The 2nd parameter would be called once the chunk has been generated. How does onChunkGenerate work? onChunkGenerate first calls Level->isChunkPopulated(chunkX, chunkZ). If the chunk is populated, you can directly call the callable (parameter 2). Or else, you'll need to wait until the Chunk->isPopulated(), which is where it gets tricky. In this case, the function registers a ChunkLoader to the chunk. If you don't know how to register a ChunkLoader to a chunk, you can read this post. This implementation utilizes two methods of the ChunkLoader class. PHP: // class implementing ChunkLoader public function onChunkLoaded(Chunk $chunk){ if(!$chunk->isPopulated()){ // Chunk is empty, so populate it. $this->level->populateChunk($this->getX(), $this->getZ()); return; } $this->onComplete(); } public function onChunkPopulated(Chunk $chunk){ $this->onComplete(); } private function onComplete() : void{ $this->level->unregisterChunkLoader($this, $this->getX(), $this->getZ()); // This IS necessary, or you'll end up with few chunks not loading at all -> memory leaks. ($this->callable)(); // call the callable you passed in parameter 2 of RegionUtils::onChunkGenerate. } And that's it. There's another way to do this using ChunkLoadEvent and ChunkPopulateEvent which doesn't include implementing a ChunkLoader. But that can cause a few issues, possibly memory leaks if you aren't also handling ChunkUnloadEvent. I've used the method before and there were a few cases where my callable wouldn't be getting called. So I recommend sticking to the ChunkLoader method. ChunkLoader keeps the chunk loaded until the chunk doesn't have any more ChunkLoaders. So you don't need to handle ChunkUnloadEvent in the case of ChunkLoaders. But make sure you're unregistering them once they're no longer needed so you don't end up with unnecessary chunks that are being held hostage because you forgot to remove the ChunkLoaders after use.