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 void growLeafNode(World world, int x, int y, int z) {
   for (int xOffset = -3; xOffset <= 3; xOffset++)
     for (int zOffset = -3; zOffset <= 3; zOffset++) {
       if ((Math.abs(xOffset) != 3 || Math.abs(zOffset) != 3)
           && (Math.abs(xOffset) != 3 || Math.abs(zOffset) != 2)
           && (Math.abs(xOffset) != 2 || Math.abs(zOffset) != 3)
           && (xOffset != 0 || zOffset != 0))
         if (world.getBlockId(x + xOffset, y, z + zOffset) == 0)
           setBlockAndMetadata(
               world,
               x + xOffset,
               y,
               z + zOffset,
               TreeBlock.LEAVES.getID(),
               TreeBlock.LEAVES.getMetadata());
       if (Math.abs(xOffset) >= 3
           || Math.abs(zOffset) >= 3
           || Math.abs(xOffset) == 2 && Math.abs(zOffset) == 2) continue;
       if (world.getBlockId(x + xOffset, y - 1, z + zOffset) == 0)
         setBlockAndMetadata(
             world,
             x + xOffset,
             y - 1,
             z + zOffset,
             TreeBlock.LEAVES.getID(),
             TreeBlock.LEAVES.getMetadata());
       if (world.getBlockId(x + xOffset, y + 1, z + zOffset) != 0) continue;
       setBlockAndMetadata(
           world,
           x + xOffset,
           y + 1,
           z + zOffset,
           TreeBlock.LEAVES.getID(),
           TreeBlock.LEAVES.getMetadata());
     }
 }
  public void generateBranches(
      World world, Random rand, int x, int y, int z, int height, int width) {
    int branchCount = BRANCHES_BASE_NUMBER + rand.nextInt(BRANCHES_EXTRA);

    // Make sure that the width is even
    width = (width % 2 == 1) ? width + 1 : width;

    // Cache the offset
    int offset = width / 2;

    // The max distance for branches to generate
    int branchStart = (int) (height * TRUNK_BRANCHES_START);
    int maxBranchHeight = height - ((int) (height * TRUNK_BRANCHES_START)) - 3;
    int trunkStart = (int) (height * TRUNK_HEIGHT_PERCENT);
    int trunkRange = height - trunkStart;
    int[] start = {0, 0, 0};
    int[] end = {0, 0, 0};
    Queue<int[]> branches = new LinkedList<int[]>();

    // generate the corner markers
    // setBlockAndMetadata(world, x-width, y + 10, z-width, TreeBlock.TRUNK.getID(), 0);
    // setBlockAndMetadata(world, x-width, y + 10, z+width, TreeBlock.TRUNK.getID(), 0);
    // setBlockAndMetadata(world, x+width, y + 10, z-width, TreeBlock.TRUNK.getID(), 0);
    // setBlockAndMetadata(world, x+width, y + 10, z+width, TreeBlock.TRUNK.getID(), 0);

    // Generate some test branches
    for (int branch = 0; branch < branchCount; branch++) {
      // The end position
      end[0] = rand.nextInt(width + 1) - offset + x;
      end[1] = rand.nextInt(maxBranchHeight) + branchStart + y;
      end[2] = rand.nextInt(width + 1) - offset + z;

      // Max of tree height
      // Min of branch start
      start[1] =
          Math.max(
              branchStart + y,
              Math.min(height, rand.nextInt(Math.max(end[1] - branchStart - y, 1)) + y));

      if (end[0] > x && end[2] > z) {
        start[0] = x + 1;
        start[2] = z + 1;
      } else if (end[0] > x) {
        start[0] = x + 1;
        start[2] = z;
      } else if (end[2] > z) {
        start[0] = x;
        start[2] = z + 1;
      } else {
        start[0] = x;
        start[2] = z;
      }

      // Place the branch
      placeBlockLine(start, end, TreeBlock.KNEE_LOG.get(), world);

      int[] node = new int[] {end[0], end[1], end[2]};

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

    // Generate the leaf clusters
    Iterator<int[]> itt = branches.iterator();
    while (itt.hasNext()) {
      int[] cluster = itt.next();
      generateLeafCluster(
          world,
          cluster[0],
          cluster[1],
          cluster[2],
          CLUSTER_HEIGHT + rand.nextInt(CLUSTER_HEIGHT_VARIANCE),
          CLUSTER_DIAMATER + rand.nextInt(CLUSTER_DIAMATER_VARIANCE),
          TreeBlock.LEAVES.get());
    }
  }