public int[][] carveCavern(int[][] currentBlockArray, int size, int xMin, int xMax, int zMin, int zMax, int paintRadius, float splitPercentage) {
        int x = randGen.nextInt(xMax - xMin) + xMin;
        int z = randGen.nextInt(zMax - zMin) + zMin;
        numberCaves = 2;
        int cave_x1 = 0;
        int cave_z1 = 0;
        int cave_x2 = 0;
        int cave_z2 = 0;
        int currentPaintRadius = paintRadius;
        int angle = 0;
        int distance = 0;
        int[] worldSize = world.getWorldSize();

        cave_x1 = (int) (x + (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.sin(30 * Math.PI / 180));
        cave_z1 = (int) (z - (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.cos(30 * Math.PI / 180));

        for (int i = 0; i < CAVERN_FACTOR; i++) {
            world.PaintAtPoint(currentBlockArray, "CaveBG", currentPaintRadius, x, z, (x / size) * size, size);
            if (i == CAVERN_FACTOR - 1) {
                cave_x2 = (int) (x - (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.sin(30 * Math.PI / 180));
                cave_z2 = (int) (z - (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.cos(30 * Math.PI / 180));
            }
            x += randGen.nextInt(Math.max(currentPaintRadius / 2, 1)) - currentPaintRadius / 2;
            z += randGen.nextInt(Math.max(currentPaintRadius / 4, 1)) - currentPaintRadius / 8;
            currentPaintRadius = randGen.nextInt(paintRadius / 2) + paintRadius / 2;
        }

        angle = randGen.nextInt(25 - 15) + 15;
        distance = randGen.nextInt(40 - 30) + 30;
        int cave_x1_end = (int) (cave_x1 + distance * Math.cos(angle * Math.PI / 180));
        int cave_z1_end = (int) (cave_z1 + distance * Math.sin(angle * Math.PI / 180));
        currentBlockArray = world.PaintLine(currentBlockArray, "CaveBG", CAVE_RADIUS, cave_x1, cave_z1, cave_x1_end, cave_z1_end, 0, 0, worldSize[0], worldSize[1]);
        angle = randGen.nextInt(25 - 15) + 15;
        distance = randGen.nextInt(30 - 20) + 20;
        int cave_x2_end = (int) (cave_x2 - distance * Math.cos(angle * Math.PI / 180));
        int cave_z2_end = (int) (cave_z2 + distance * Math.sin(angle * Math.PI / 180));
        currentBlockArray = world.PaintLine(currentBlockArray, "CaveBG", CAVE_RADIUS, cave_x2, cave_z2, cave_x2_end, cave_z2_end, 0, 0, worldSize[0], worldSize[1]);

        currentBlockArray = carveCave(currentBlockArray, cave_x1_end, cave_z1_end, 0, 0, worldSize[0], worldSize[1], 0.02f, World.direction.Right);
        currentBlockArray = carveCave(currentBlockArray, cave_x2_end, cave_z2_end, 0, 0, worldSize[0], worldSize[1], 0.02f, World.direction.Left);

        // Add cave.
        Game.loadingText = "Digging Caves";
        EIError.debugMsg("Add cave noise", EIError.ErrorLevel.Notice);
        float[][] caveNoise;
        for (int b = 0; b < world.HORIZ_BLOCKS; b++) {
            caveNoise = world.GeneratePerlinNoise(32);
            caveNoise = world.InterpolateData(caveNoise, 32, size);
            for (int i = 0; i < 60; i++) {
                world.PaintWithRandomWalk(currentBlockArray, caveNoise, size, Rand.getRange(5, size / 64), "CaveBG", false, b * size, (b + 1) * size - 1, world.GROUND_LEVEL / 8, world.GROUND_LEVEL, size / 2);
            }
        }

        for(int i = 0; i < 20; i++) {
            drawCrag(currentBlockArray, "CaveBG", Rand.getRange(5, 10), Rand.getRange(0, worldSize[0]), Rand.getRange(size / 8, worldSize[1]), 0, worldSize[0], 0, 3 * worldSize[1] / 4);
        }

        return currentBlockArray;
    }