How do you determine if a chunk has been loaded and populated?

Discussion in 'Plugin Development' started by El_Minadero, Jan 6, 2014.

Thread Status:
Not open for further replies.
  1. Offline


    I have a block populator that changes all ores to stone, and several methods that are called after which are supposed to change some blocks in previously loaded chunks to gold ore. I've been going off the assumption that world.isChunkLoaded(x,z) only returns true if the chunk has been loaded and populated. Based on this output:
    that is obviously not the case XD.
    So then, how do I determine if a chunk has been:
    -loaded and populated
    -populated, but not loaded
    -not populated and not loaded?
  2. Offline


    Let us assume that World.isChunkLoaded(int, int) only check if the chunk is loaded. Let us assume also that is uses a simple null check in World.getChunk(int, int). Well being that we have only found a way to check if the chunk is loaded let us hypothesize that the Chunk object has a method to check population. Let's say that is it Chunk.isPopulated(), well we would construct our code like so:
    1. //some arbitrary conditions to get to this point
    2. if(world.getChunk(x, y) != null) {
    3. Chunk myChunk = world.getChunk(x, y);//this checked if it is loaded
    4. if(myChunk.isPopulated()) {
    5. //do other stuff
    6. }
    7. }

    However what if the Chunk class does not contain an isPopulated method? We can check block population in the chunk by checking each block in the chunk, if this is the case you might want to do some more research on the topic because this idea is a bit foggy but I would assume you would check if each block exists in the chunk.
  3. Offline


    just to be sure, if the world.getChunkAt(x,y) returns null, then it won't force generate the chunk, and will retrieve info on the chunk from file without loading it right?
  4. Offline


    From what I've seen, getChunk(x, y, false) doesn't return null under normal circumastances - even if the chunk isn't generated yet, you'll still get a Chunk back.

    The only way I've found to do an "is generated" check is very hacky, but seems to work ok. It uses NMS though. Feel free to check out my reflection-based code, it's loosely based on how PowerNBT does its thing.

    Or if you're ok with not using reflection, this is as easy as checking NMS Chunk.done, since it happens to be public.
  5. Offline


    Hmm, it doesn't seem to work that well. Here's the three important parts of code that I have:
    1. if(Bukkit.getWorlds().get(0).isChunkLoaded(x, z)) //returns true if loaded
    2. {
    3. Chunk testChunk = Bukkit.getWorlds().get(0).getChunkAt(x,z);
    4. if(testChunk.getBlock(1, 1, 1)==null)//is not populated, save to file
    5. {
    6. writeChunkInfo(key, partition,true);
    7. }
    8. else//is populated and loaded
    9. {
    10. if(loadedMap==null)
    11. {
    12. loadedMap = new HashMap<String,String[][][]>();
    13. }
    14. loadedMap.put(key, partition);
    15. }
    16. }
    17. else//not loaded
    18. {
    19. if(Bukkit.getWorlds().get(0).loadChunk(x,z,false))//true, is populated
    20. {
    21. Bukkit.getWorlds().get(0).unloadChunk(x,z);
    22. writeChunkInfo(key, partition,false);
    23. }
    24. else//false, not populated
    25. {
    26. writeChunkInfo(key, partition,true);
    27. }
    28. }

    loadedMap is a Hashmap with key "chunkxcoord:chunkzcoord" and value String[][][] (representing blocks that have to be changed at that chunk.

    WriteChunkInfo writes the String[][][] object to the ChunkInfo file if passed true, and writes to PrevChunkInfo if false.

    The main Block Populator is this:

    1. public void populate(World world, Random rand, Chunk chunk)
    2. {
    3. OreReplacer.removeOres(chunk);
    4. //go populate unpopulated chunk
    5. OreGenerator.getOresFromChunk(chunk);
    6. if(VeinChunkReadWrite.loadedMap!=null)
    7. {
    8. drawOtherOres(VeinChunkReadWrite.loadedMap);
    9. VeinChunkReadWrite.loadedMap=null;
    10. }
    11. String[][][] oldOres = VeinChunkReadWrite.readChunks(LineDrawingUtilityClass.convertToKey(chunk.getX(),chunk.getZ()),true);
    12. if(oldOres !=null)
    13. {
    14. //DebugLogger.console("Drawing veins in existing chunk");
    15. VeinDrawer.drawVein(oldOres, chunk);
    16. }
    17. VeinChunkReadWrite.deleteChunkInfo(LineDrawingUtilityClass.convertToKey(chunk.getX(),chunk.getZ()),true);

    VeinDrawer places ore blocks at the coordinates, OreReplacer replaces all ores with stone, and DrawOtherOres force draws ores in chunks that have already been populated and are loaded (well at least that was the intent).

    The last piece of Code is supposed to draw the vein parts in chunks that have already been populated but not loaded
    1. @EventHandler
    2. public void onLoad(ChunkLoadEvent event)
    3. {
    4. if(event.getChunk().getBlock(1, 1,1).getType()==Material.BEDROCK)//load blocks into already populated chunk
    5. {
    6. String[][][] draw = VeinChunkReadWrite.readChunks(LineDrawingUtilityClass.convertToKey(event.getChunk().getX(), event.getChunk().getZ()), false);
    7. if(draw !=null)
    8. {
    9. //DebugLogger.console("Drawing veins in existing chunk");
    10. VeinDrawer.drawVein(draw, event.getChunk());
    11. }
    12. VeinChunkReadWrite.deleteChunkInfo(LineDrawingUtilityClass.convertToKey(event.getChunk().getX(), event.getChunk().getZ()), false);
    13. }
    14. }

    it uses an event handler and it checks to see if coordinate 1,1,1 is bedrock to see if its a chunk thats already been populated. My guess is that its either this check, or the initial partitioning function thats not quite right. In any case, here's the result:
Thread Status:
Not open for further replies.

Share This Page