/** Returns true if at least one block has changed. */
  public static final boolean genBlob(
      DecoratorFeatureGenerator gen, double x, double y, double z, double rad, Block block) {
    boolean generatedSomething = false;
    double radSq = MathUtil.square(rad + 0.5D);
    int size = MathUtil.ceil(rad),
        ix = MathUtil.floor(x),
        iy = MathUtil.floor(y),
        iz = MathUtil.floor(z);
    List<BlockPosM> locs = new ArrayList<BlockPosM>();

    for (int xx = ix - size; xx <= ix + size; xx++) {
      for (int yy = iy - size; yy <= iy + size; yy++) {
        for (int zz = iz - size; zz <= iz + size; zz++) {
          if (MathUtil.distanceSquared(xx - x, yy - y, zz - z) <= radSq) {
            if (gen.getBlock(xx, yy, zz) != block && gen.setBlock(xx, yy, zz, block)) {
              generatedSomething = true;
              locs.add(new BlockPosM(xx, yy, zz));
            }
          }
        }
      }
    }

    return generatedSomething;
  }
  @Override
  public void generate(DecoratorFeatureGenerator gen, Random rand) {
    List<BlockPosM> blocks = gen.getUsedLocations();
    if (blocks.isEmpty()) return;

    int amount = amountGen.generate(rand, minAmount, maxAmount);

    for (int attempts = minAttempts + rand.nextInt(maxAttempts - minAttempts + 1), xx, yy, zz;
        attempts > 0 && amount > 0 && !blocks.isEmpty();
        attempts--) {
      BlockPosM loc = blocks.remove(rand.nextInt(blocks.size()));
      if (gen.getBlock(loc.x, loc.y, loc.z) != Blocks.end_stone
          || gen.getBlock(loc.x, loc.y - 1, loc.z) != Blocks.end_stone) continue;

      byte airDir = -1;

      for (byte dir = 0; dir < 4; dir++) {
        if (gen.getBlock(loc.x + Direction.offsetX[dir], loc.y, loc.z + Direction.offsetZ[dir])
            == Blocks.air) {
          if (airDir == -1) airDir = dir;
          else {
            airDir = -1;
            break;
          }
        }
      }

      if (airDir == -1) continue;

      xx = loc.x + Direction.offsetX[airDir];
      yy = loc.y;
      zz = loc.z + Direction.offsetZ[airDir];
      Block block;

      if (!requireBlockBelow) {
        gen.setBlock(loc.x, loc.y, loc.z, liquid);
        continue;
      }

      while (--yy >= -16) {
        if ((block = gen.getBlock(xx, yy, zz)) == Blocks.end_stone) {
          if (gen.getBlock(xx, yy - 1, zz) == Blocks.end_stone) {
            gen.setBlock(loc.x, loc.y, loc.z, liquid);
            gen.setBlock(xx, yy, zz, Blocks.air);
            --amount;
            break;
          }
        } else if (block != Blocks.air) break;
      }
    }
  }