[BASIC] "Maze" generation using ChunkGenerator and BlockPopulator

Discussion in 'Resources' started by codename_B, Jul 12, 2011.

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

    codename_B

    Want to generate a very simple underground "maze" world?
    [​IMG]
    This tutorial will give you a basic framework for building on top of (literally)
    Code:
    package com.ubempire.dungeon;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Random;
    
    import org.bukkit.Material;
    import org.bukkit.World;
    import org.bukkit.generator.BlockPopulator;
    import org.bukkit.generator.ChunkGenerator;
    
    public class DungeonGenerator extends ChunkGenerator {
    
        private byte[] result;
    
        public int getRandom() {
            return ((int) (Math.random() * 3) - 1) * 15;
        }
        public int getRandomer() {
            return ((int) (Math.random() * 3) - 1);
        }
        public List<BlockPopulator> getDefaultPopulators(World world) {
            return Arrays.asList((BlockPopulator) new DungeonPopulator());
        }
    
        // This needs to be set to return true to override minecraft's default
        // behaviour
        @Override
        public boolean canSpawn(World world, int x, int z) {
            double xX = Math.random()*x;
            double zZ = Math.random()*z;
            if(xX>zZ)
            return true;
            else
            return false;
        }
    
        // This converts relative chunk locations to bytes that can be written to
        // the chunk
        public int xyzToByte(int x, int y, int z) {
            return (x * 16 + z) * 128 + y;
        }
    
        @Override
        public byte[] generate(World world, Random rand, int chunkx, int chunkz) {
            result = new byte[32768];
    
            // This will set the floor of each chunk at bedrock level to bedrock
            for (int y = 15; y >= 0; y--) {
                for (int x = 0; x < 16; x++) {
                    for (int z = 0; z < 16; z++) {
                        result[xyzToByte(x, y, z)] = (byte) Material.STONE.getId();
                    }
                }
            }
            int xr = getRandom();
            int zr = getRandom();
            
            for (int y = 4+getRandomer(); y < 16; y++) {
                for (int x = 0; x < 16; x++) {
                    for (int z = 0; z < 16; z++) {
                        if ((x == 0 || x == 15) && (z == 0 || z == 15)) {
                            result[xyzToByte(x, y, z)] = (byte) Material.COBBLESTONE
                                    .getId();
                        } else if (xr == x) {
                            result[xyzToByte(x, y, z)] = (byte) Material.COBBLESTONE
                                    .getId();
                        } else if (zr == z) {
                            result[xyzToByte(x, y, z)] = (byte) Material.COBBLESTONE
                                    .getId();
                        } else {
                            result[xyzToByte(x, y, z)] = (byte) Material.AIR
                                    .getId();
                        }
                    }
                }
            }
            
            return result;
        }
    
    }
    
    Code:
    package com.ubempire.dungeon;
    
    import java.util.Random;
    
    import org.bukkit.Chunk;
    import org.bukkit.World;
    import org.bukkit.generator.BlockPopulator;
    
    public class DungeonPopulator extends BlockPopulator {
    
        @Override
        public void populate(World world, Random rand, Chunk chunk) {
            int y = 5;
            int chunkX = chunk.getX() * 16;
            int chunkZ = chunk.getZ() * 16;
    
            int[] NSEW1 = doNSEW1(world, chunk, y);
            int[] NSEW2 = doNSEW2(world, chunk, y);
            int hasExit = hasExit(NSEW1, NSEW2);
            if (hasExit == -1) {
                for (y = 5; y < 16; y++) {
                    
                        for (int z = 1; z < 15; z++) {
    
                            world.getBlockAt(chunkX,y,chunkZ+z).setTypeId(0);
                            world.getBlockAt(chunkX-1,y,chunkZ+z).setTypeId(0);
                        }
                    }
            }
        }
        
    
        public int getRandom() {
            return (int) (Math.random() * 2) * 15;
        }
    
        public int hasExit(int[] NSEW1, int[] NSEW2) {
            for (int i = 0; i < 4; i++) {
                if (NSEW1[i] == NSEW2[i]) {
                    if ((NSEW1[i] == 0)&&(NSEW2[i] == 0)) {
                        return i;
                    }
                }
            }
            return -1;
        }
    
        public int[] doNSEW1(World world, Chunk chunk, int y) {
            /*
             * Do the main checks for NSEW
             */
            int chunkX = chunk.getX() * 16;
            int chunkZ = chunk.getZ() * 16;
            // check face 1
            int N = world.getBlockTypeIdAt(chunkX, y, chunkZ + 1);
            // check face 2
            int S = world.getBlockTypeIdAt(chunkX + 15, y, chunkZ + 1);
            // check face 3
            int E = world.getBlockTypeIdAt(chunkX + 1, y, chunkZ);
            // check face 4
            int W = world.getBlockTypeIdAt(chunkX + 1, y, chunkZ + 15);
            return new int[] { N, S, E, W };
        }
    
        public int[] doNSEW2(World world, Chunk chunk, int y) {
            /*
             * Do the secondary checks for NSEW
             */
            int chunkX = chunk.getX() * 16;
            int chunkZ = chunk.getZ() * 16;
            // check face 1
            int N = world.getBlockTypeIdAt(chunkX - 1, y, chunkZ + 1);
            // check face 2
            int S = world.getBlockTypeIdAt(chunkX + 16, y, chunkZ + 1);
            // check face 3
            int E = world.getBlockTypeIdAt(chunkX + 1, y, chunkZ - 1);
            // check face 4
            int W = world.getBlockTypeIdAt(chunkX + 1, y, chunkZ + 16);
            return new int[] { N, S, E, W };
        }
    }
    
     
    Zothen, Nightgunner5 and iPhysX like this.
  2. Offline

    Nightgunner5

    Zothen likes this.
  3. Offline

    codename_B

  4. Offline

    Nightgunner5

    com.ubempire.dungeon.DungeonPlugin allows this to be used as a plugin that generates a world named "dungeon", or to create additional worlds by the method in codename_B's tutorial.
    com.ubempire.dungeon.DungeonGenerator is the heart of the generator. It contains a list of populators in the order they should be run, in addition to making the walls and floor.
    com.ubempire.dungeon.DungeonPopulator is the first populator run after the generator. It prevents dungeon rooms from having no neighbors.
    net.llamaslayers.minecraft.banana.populators.PoolPopulator runs next, making pools of water or lava (but not close to the spawn) in about 20% of chunks.
    net.llamaslayers.minecraft.banana.populators.ExplosionPopulator runs after PoolPopulator, making the map look more ancient by making small (half of TNT's power, 37.5%), medium (TNT's power, 12.5%), or large (9-19 activated TNT spawned in the middle of the room, 0.25%) explosions.
    net.llamaslayers.minecraft.banana.populators.RuinsPopulator is the next to run after ExplosionPopulator, and the first populator I programmed. It generates ruins by picking a location and a height, then moving in one or two directions while reducing the height. The end result is something that looks like a crumbling wall.
    net.llamaslayers.minecraft.banana.populators.TorchPopulator runs after RuinsPopulator, adding up to 3 torches in a chunk at random locations where air touches a surface.
    net.llamaslayers.minecraft.banana.populators.CeilingPopulator runs last. It generates a ceiling at the top of the dungeon with holes generated by simplex noise.
     
    codename_B likes this.
  5. Offline

    tips48

    You both are awesome :) I'm good at using x,y,z, but I had absolutely no clue how to make a world.till now
     
  6. Offline

    Nightgunner5

    It's a lot of guess-and-check, mixed with messing around ingame to figure out what would look good.
     
  7. Offline

    tips48

    okay, sweet :p Do you recommend building it in the game first(not to scale examples, etc) or just doing from the plugin?
     
  8. Offline

    Nightgunner5

    I built a few ruins on codename_B's server and blew up a large portion of the dungeon on mine before I coded those populators, but for things like ceiling and torches, it was all coded before testing.
     
  9. Offline

    tips48

    oh cool. How many times did you have to export? :D
     
  10. Offline

    jeffadkins51

    Does it really matter...
    ONTOPIC: Anyways looks great!
     
Thread Status:
Not open for further replies.

Share This Page