@Override
	public byte[] generate(World world, Random random, int chunkX, int chunkY) {
        byte[] result = new byte[32768];
                
        int worldHeight = world.getMaxHeight();
        int halfHeight = (int)(worldHeight / 2);
        int realX = 0;
        int realZ = 0;
        int pos;
                
        int waterlevel = plugin.config.getInt("generators.hills.waterlevel", 64);
        
        double scale = plugin.config.getDouble("generators.hills.scale", 64.0);
        int octaves = plugin.config.getInt("generators.hills.octaves", 8);
        int variance = plugin.config.getInt("generators.hills.variance", 16);

        SimplexOctaveGenerator gen = new SimplexOctaveGenerator(new Random(world.getSeed()), octaves);
        gen.setScale(1 / scale);
        
        for (int x = 0; x < 16; x++) {
       		for (int z = 0; z < 16; z++) {
    			realX = (chunkX * 16) + x;
    			realZ = (chunkY * 16) + z;
    			
    			int height = (int)Math.ceil(gen.noise(realX, realZ, 0.5, 0.5) * variance) + halfHeight;
    			
    			for (int y = 0; y < (height > waterlevel ? height : waterlevel); y++) {
    				pos = (x * 16 + z) * worldHeight + y;
    				
    				if (y == 0) {
    					result[pos] = matBedrock;
    				} else if (y < height - (random.nextInt(5) + 3)) {
    					result[pos] = matStone;
    				} else if (y < height - 1) {
    					result[pos] = matDirt;
    				} else if (y == height - 1) {
    					result[pos] = matGrass;
    				} else {
    					result[pos] = matWater;
    				}
    			}
       		}
        }
        
        return result;
	}