public void generateBranches(
      World world, Random rand, int x, int y, int z, int height, double radius) {
    int branchCount = BRANCHES_BASE_NUMBER + rand.nextInt(BRANCHES_EXTRA);
    double curAngle = 0.0D;

    double[] average = {0, 0, 0};
    int[] start = {x, y, z};
    Queue<int[]> branches = new LinkedList<int[]>();

    // Generate the branches
    for (int i = 0; i < branchCount; i++) {
      // Get the branch radius and height
      double angle = (rand.nextInt(50) + 35) / 90.0D;
      double thisHeight = (height + 1) * Math.sin(angle) / 1.3;
      double thisRadius = radius * Math.cos(angle);

      // Get the branch rotation
      curAngle +=
          (rand.nextInt(360 / branchCount) + (360 / branchCount))
              / 90.0D; //  + (360.0D/branchCount) / 180.0D ;

      int x1 = (int) ((thisRadius) * Math.cos(curAngle));
      int z1 = (int) ((thisRadius) * Math.sin(curAngle));

      // Add the the average count
      average[0] += x1;
      average[1] += thisHeight;
      average[2] += z1;

      // Add to the branch list
      int[] node = new int[] {x1 + x, (int) thisHeight + y, z1 + z};

      // Add the branch end for leaf generation
      branches.add(node);

      // Generate the branch
      placeBlockLine(start, node, TreeBlock.TRUNK.get(), world);
    }

    // Place the branch tips
    Iterator<int[]> itt = branches.iterator();
    while (itt.hasNext()) {
      int[] cluster = itt.next();
      generateLeafCluster(world, cluster[0], cluster[1], cluster[2], 2, 1, TreeBlock.LEAVES.get());
    }

    // Calculate the center position
    average[0] /= branchCount;
    average[1] = (branchCount / average[1]) + 2.3D;
    average[2] /= branchCount;

    // Generate the canopy
    generateCanopy(
        world, rand, average[0] + x, y, average[2] + z, radius, height, TreeBlock.LEAVES.get());

    // Generate the center cone
    generateVerticalCone(world, x, y, z, height - 1, .75, 2, TreeBlock.LEAVES.get());
  }
  private boolean generateTree(World world, Random rand, int x, int y, int z) {
    final int below = world.getBlockId(x, y - 1, z);
    final int height = rand.nextInt(BASE_HEIGHT_VARIANCE) + BASE_HEIGHT;
    int width = CANOPY_WIDTH + rand.nextInt(CANOPY_WIDTH_VARIANCE);
    final int chunkCheck = width + 1;

    // Make sure that a tree can grow on the soil
    if (!TreeSoilRegistry.isValidSoil(Integer.valueOf(world.getBlockId(x, y - 1, z)))
        || !TreeSoilRegistry.isValidSoil(Integer.valueOf(world.getBlockId(x + 1, y - 1, z)))
        || !TreeSoilRegistry.isValidSoil(Integer.valueOf(world.getBlockId(x, y - 1, z + 1)))
        || !TreeSoilRegistry.isValidSoil(Integer.valueOf(world.getBlockId(x + 1, y - 1, z + 1))))
      return false;

    // make sure that we have room to grow the tree
    if (y >= 256 - height - 4) return false;

    // Make sure that the tree can fit in the world
    if (y < 1 || y + height + 4 > 256) return false;

    // Make sure the cunks are loaded
    if (!world.checkChunksExist(
        x - chunkCheck,
        y - chunkCheck,
        z - chunkCheck,
        x + chunkCheck,
        y + chunkCheck,
        z + chunkCheck)) return false;

    // Draw the main trunk
    if (place2x2Trunk(
        x, y, z, (int) (height * TRUNK_HEIGHT_PERCENT), TreeBlock.TRUNK.get(), world)) {
      // Draw the knees
      generateKnees(world, rand, x, y, z);

      // Generate the branches
      generateBranches(world, rand, x, y, z, height, width);

      // Place the topper leaves
      generateLeafCluster(
          world,
          x,
          (int) (height * TRUNK_HEIGHT_PERCENT) + y,
          z,
          4 + rand.nextInt(CLUSTER_HEIGHT_VARIANCE),
          4 + rand.nextInt(CLUSTER_DIAMATER_VARIANCE),
          TreeBlock.LEAVES.get());

      // We generated a tree
      return true;
    }

    return false;
  }
  private boolean generateTree(World world, Random rand, int x, int y, int z) {
    final int height = rand.nextInt(BASE_HEIGHT_VARIANCE) + BASE_HEIGHT;
    final double radius = (CANOPY_WIDTH + rand.nextInt(CANOPY_WIDTH_VARIANCE)) / 2.0D;
    final int chunkCheck = (int) Math.ceil(radius) + 1;

    // Make sure that a tree can grow on the soil
    if (!TreeSoilRegistry.isValidSoil(Integer.valueOf(world.getBlockId(x, y - 1, z)))) return false;

    // make sure that we have room to grow the tree
    if (y >= 256 - height - 4) return false;

    // Make sure that the tree can fit in the world
    if (y < 1 || y + height + 4 > 256) return false;

    // Make sure that all the needed chunks are loaded
    if (!world.checkChunksExist(
        x - chunkCheck,
        y - chunkCheck,
        z - chunkCheck,
        x + chunkCheck,
        y + chunkCheck,
        z + chunkCheck)) return false;

    // Draw the main trunk
    if (place1x1Trunk(
        x, y, z, (int) (height * TRUNK_HEIGHT_PERCENT), TreeBlock.TRUNK.get(), world)) {
      // Generate the branches
      generateBranches(
          world,
          rand,
          x,
          y + (int) (height * TRUNK_HEIGHT_PERCENT),
          z,
          height - (int) (height * TRUNK_HEIGHT_PERCENT) - 2,
          radius);

      return true;
    }

    return false;
  }