1.16.5 Custom ChunkGenerator lagging server.

Discussion in 'Spigot Plugin Development' started by Jonnyo101, Aug 3, 2020.

  1. Hello i am trying to write a chunk generator that will pre-make some walls for me in game.
    How ever when the chunks are generating its causing extreme lag on the server.
    Here is all the information i have collected and the code (Sorry its a lot.)

    The test i am doing that is causing the lag. In the custom world i have a command that will start at cords 0, 0, 0 and then more 500 blocks in the x directions and get the bottom block causing new chunks to load. When running the command it does that 5 times and gets the 5 blocks.

    Here are spigot timings.
    https://timings.spigotmc.org/?url=pakofomeha

    Here is the ChunkGenerator code.
    Code (Java):
      private static BlockData barrier = Material.BARRIER.createBlockData();
        private static final BlockData bedrock = Material.BEDROCK.createBlockData();
        private static final BlockData cobbleStone = Material.COBBLESTONE.createBlockData();
        private static final BlockData stone = Material.STONE.createBlockData();
        private static final BlockData blackwool = Material.BLACK_WOOL.createBlockData();
        private static final BlockData coalblock = Material.COAL_BLOCK.createBlockData();

        private BlockPopulator blockPopulator = new WorldPopulator();

        @Override
        public List<BlockPopulator> getDefaultPopulators(World world) {
            return new ArrayList<>(Collections.singletonList(blockPopulator));
        }

        @Override
        public ChunkData generateChunkData(World world, Random rand, int chunkx, int chunkz, BiomeGrid biome) {
            ChunkData chunkData = createChunkData(world);

            for (int x = 0; x < 16; x++) {
                int realx = (chunkx * 16) + x;
                int distanceFromx = realx % (TerrainManager.terrainSize + TerrainManager.terrainBufferSize);

                for (int z = 0; z < 16; z++) {
                    int realZ = (chunkz * 16) + z;
                    int distanceFromz = realZ % 500;

                    chunkData.setBlock(x, 5, z, barrier);
                    chunkData.setBlock(x, 250, z, barrier);

                    if (distanceFromz == 4 || distanceFromz == 6 || distanceFromz == 35 || (distanceFromz > 250 && distanceFromz < 255)) {
                        setColumn(chunkData, x, z, barrier);
                    }
                    else if (distanceFromz == 0) {
                        setColumn(chunkData, x, z, bedrock);
                    }
                    else if (distanceFromz >= 1 && distanceFromz <= 2) {
                        setColumn(chunkData, x, z, cobbleStone);
                    }
                    else if (distanceFromz == 3) {
                        setColumn(chunkData, x, z, stone);
                    }
                    else if (distanceFromz > -10 && distanceFromz < 0) {
                        setColumn(chunkData, x, z, blackwool);
                    }
                    else if (distanceFromx >= 0 && distanceFromx <= 5) {
                        setColumn(chunkData, x, z, coalblock);
                    }

                }
            }

            return chunkData;

        }

        private void setColumn(ChunkData chunkData, int x, int z, BlockData blockData) {
            for (int y = 1; y < 256; y++) {
                chunkData.setBlock(x, y, z, blockData);
            }
        }
    Here is some visualVM profiling.
    https://prnt.sc/tte6t1

    Any idea on whats causing the lag and a fix i an look at ?

    Edit: Another reason i think the chunk generation is causing the lag is that when i delete the world and start the server the server takes over 50s to generate the spawn chunks.
     
  2. why not use ChunkData#setRegion? i doubt it would fix your issue but something that would make it neater (and slightly more efficient)
    couldn't tell you exactly why its lagging, and what im about to say may not apply depending on how chunk generating is handled, but heres what i know:
    individually setting blocks causes block updates (though there is not a method to prevent block updates with a chunkdata object, so this probably does not apply)
    lighting recalculation is heavy as hell. i dont know if transparent blocks still factor into the light recalculation or not, but if it does, you may be looking at massive relighting with a block as high as 250. try setting the highest block last
     
  3. Yer i looked in to setRegion but they both seem to send at the same point.
    Code (Java):
      public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, IBlockData type) {
            if (xMin <= 15 && yMin < this.maxHeight && zMin <= 15) {
                if (xMin < 0) {
                    xMin = 0;
                }

                if (yMin < 0) {
                    yMin = 0;
                }

                if (zMin < 0) {
                    zMin = 0;
                }

                if (xMax > 16) {
                    xMax = 16;
                }

                if (yMax > this.maxHeight) {
                    yMax = this.maxHeight;
                }

                if (zMax > 16) {
                    zMax = 16;
                }

                if (xMin < xMax && yMin < yMax && zMin < zMax) {
                    for(int y = yMin; y < yMax; ++y) {
                        ChunkSection section = this.getChunkSection(y, true);
                        int offsetBase = y & 15;

                        for(int x = xMin; x < xMax; ++x) {
                            for(int z = zMin; z < zMax; ++z) {
                                section.setType(x, offsetBase, z, type); <<SETS THE BLOCK IN THE CHUNK SECTION FOR EACH BLOCK PASSED IN
                            }
                        }
                    }

                }
            }
        }
    Where in my code.
    Code (Java):
       private void setBlock(int x, int y, int z, IBlockData type) {
            if (x == (x & 15) && y >= 0 && y < this.maxHeight && z == (z & 15)) {
                ChunkSection section = this.getChunkSection(y, true);
                section.setType(x, y & 15, z, type);
                if (type.getBlock().isTileEntity()) {
                    if (this.tiles == null) {
                        this.tiles = new HashSet();
                    }

                    this.tiles.add(new BlockPosition(x, y, z));
                }

            }
        }
    Still ends up using section.setType(x, y & 15, z, type);
    for each block aswell.

    Also i think your right. I dont think that is does lighting updates for each block you add.
     
  4. Also is it not possible to somehow move the generation on other threads? I think so much stuff going on at the same time would impact performance
     
  5. there is but bukkit doesnt support it atm, as thats a huge undertaking. if someone spent the effort figuring out how to do it through NMS, it could be submitted as PR to bukkit and added officially
     
  6. Well i thought am i doing a lot of processing. But is only simple code of some simple if statements and some * and modulus.

    Compared to this post back in 1.14.
    https://www.spigotmc.org/threads/ne...ator-and-caves-1-14-edit-versions-bug.380517/

    His chunk generator seems to do a lot more complex code then what mine does.

    So yer lol... I dont know is there is a (1.16) problem
    Still looking for help on why this is lagging tho.
     
    #6 Jonnyo101, Aug 3, 2020
    Last edited: Aug 3, 2020
  7. Okay just tested the exact same code on 1.13 and it seems to work fine... Guess this is a problem with 1.16 chunk loading. If anyone has a fix please let me know.
     
  8. I mean 1.15 got quite a huge fix on the chunk part,its nost likely from there
     
  9. Bump still looking for a fix for this (in 1.16)
     
  10. Have you override the "isParallelCapable()" methode to return true?
     
  11. Yes i do this does not make any difference.
     
  12. What does your WorldPopulator look like?
     
  13. Nothing.

    public class WorldPopulator extends BlockPopulator {
    @Override
    public void populate(World world, Random random, Chunk chunk) { }
    }