1. The forums will be archived and moved to a read only mode in about 2 weeks (mid march).

Solved getHighestBlockAt

Discussion in 'Development' started by SavionLegendZzz, Feb 28, 2019.

  1. SavionLegendZzz

    SavionLegendZzz Slime

    Messages:
    75
    GitHub:
    savionlegends
    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
     
  2. Diduhless

    Diduhless Baby Zombie

    Messages:
    199
    GitHub:
    Diduhless
    +1, the same thing happens to me
     
  3. Muqsit

    Muqsit Chicken

    Messages:
    1,548
    GitHub:
    muqsit
    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->$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.
     
    Last edited: Mar 1, 2019
  4. SavionLegendZzz

    SavionLegendZzz Slime

    Messages:
    75
    GitHub:
    savionlegends
    This worked thank you!
     
    Muqsit likes this.
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.