public void generateStructures(World world, Random rand, BlockPos position, int radius) {
   for (int i = 0; radius >= 0 && i < 3; ++i) {
     int j = radius + rand.nextInt(2);
     int k = (radius + rand.nextInt(2));
     int l = radius + rand.nextInt(2);
     float f = (float) (j + k + l) * 0.333F + 0.5F;
     for (BlockPos blockpos :
         BlockPos.getAllInBox(position.add(-j, -k, -l), position.add(j, k, l))) {
       if (blockpos.distanceSq(position) <= (double) (f * f)
           && world.isAirBlock(blockpos)
           && world
               .getBlockState(blockpos.down())
               .getBlock()
               .getUnlocalizedName()
               .contains("frozen")) {
         int chance = rand.nextInt(100);
         if (chance < 4) {
           int chance2 = rand.nextInt(20);
           System.out.println(chance2);
           switch (chance2) {
             default:
               generateGoldPile(world, rand, blockpos);
               break;
             case 1:
               generateArchNS(world, rand, blockpos);
               break;
             case 2:
               generateArchEW(world, rand, blockpos);
               break;
           }
         }
       }
     }
   }
 }
Example #2
0
 /**
  * Return an {@link AxisAlignedBB} that controls the visible scope of a {@link
  * TileEntitySpecialRenderer} associated with this {@link TileEntity} Defaults to the collision
  * bounding box {@link Block#getCollisionBoundingBoxFromPool(World, int, int, int)} associated
  * with the block at this location.
  *
  * @return an appropriately size {@link AxisAlignedBB} for the {@link TileEntity}
  */
 @SideOnly(Side.CLIENT)
 public net.minecraft.util.math.AxisAlignedBB getRenderBoundingBox() {
   net.minecraft.util.math.AxisAlignedBB bb = INFINITE_EXTENT_AABB;
   Block type = getBlockType();
   BlockPos pos = getPos();
   if (type == Blocks.ENCHANTING_TABLE) {
     bb = new net.minecraft.util.math.AxisAlignedBB(pos, pos.add(1, 1, 1));
   } else if (type == Blocks.CHEST || type == Blocks.TRAPPED_CHEST) {
     bb = new net.minecraft.util.math.AxisAlignedBB(pos.add(-1, 0, -1), pos.add(2, 2, 2));
   } else if (type != null && type != Blocks.BEACON) {
     net.minecraft.util.math.AxisAlignedBB cbb = null;
     try {
       cbb =
           worldObj
               .getBlockState(getPos())
               .getCollisionBoundingBox(worldObj, pos)
               .addCoord(pos.getX(), pos.getY(), pos.getZ());
     } catch (Exception e) {
       // We have to capture any exceptions that may occur here because BUKKIT servers like to send
       // the tile entity data BEFORE the chunk data, you know, the OPPOSITE of what vanilla does!
       // So we can not GARENTEE that the world state is the real state for the block...
       // So, once again in the long line of US having to accommodate BUKKIT breaking things,
       // here it is, assume that the TE is only 1 cubic block. Problem with this is that it may
       // cause the TileEntity renderer to error further down the line! But alas, nothing we can
       // do.
       cbb =
           new net.minecraft.util.math.AxisAlignedBB(
               getPos().add(-1, 0, -1), getPos().add(1, 1, 1));
     }
     if (cbb != null) bb = cbb;
   }
   return bb;
 }
 float getGrowthSpeed(World world, BlockPos pos, IBlockState sate, int light) {
   float growth = 0.125f * (light - 11);
   if (world.canBlockSeeSky(pos)) growth += 2f;
   IBlockState soil = world.getBlockState(pos.add(0, -1, 0));
   if (soil.getBlock().isFertile(world, pos.add(0, -1, 0))) growth *= 1.5f;
   return 1f + growth;
 }
 @Override
 public void grow(World world, Random rand, BlockPos pos, IBlockState state) {
   int meta = this.getMetaFromState(state);
   if (meta < getMaxMeta(meta)) {
     int span = getMaxMeta(meta) - meta;
     int newMeta = meta + rand.nextInt(span) + 1;
     if (newMeta != meta) world.setBlockState(pos, this.getStateFromMeta(newMeta));
     meta = newMeta;
   }
   if (meta == 4 && world.isAirBlock(pos.add(0, 1, 0)))
     world.setBlockState(pos.add(0, 1, 0), this.getStateFromMeta(meta + 1));
 }
  /** returns whether or not there is space for a tree to grow at a certain position */
  private boolean isSpaceAt(World worldIn, BlockPos leavesPos, int height) {
    boolean flag = true;

    if (leavesPos.getY() >= 1 && leavesPos.getY() + height + 1 <= 256) {
      for (int i = 0; i <= 1 + height; ++i) {
        int j = 2;

        if (i == 0) {
          j = 1;
        } else if (i >= 1 + height - 2) {
          j = 2;
        }

        for (int k = -j; k <= j && flag; ++k) {
          for (int l = -j; l <= j && flag; ++l) {
            if (leavesPos.getY() + i < 0
                || leavesPos.getY() + i >= 256
                || !this.isReplaceable(worldIn, leavesPos.add(k, i, l))) {
              flag = false;
            }
          }
        }
      }

      return flag;
    } else {
      return false;
    }
  }
 @Override
 public void updateTick(World world, BlockPos pos, IBlockState state, Random random) {
   this.checkAndDropBlock(world, pos, state);
   int light = world.getLight(pos);
   if (light >= 12) {
     int meta = this.getMetaFromState(state);
     if (meta > 4) return;
     float growth = this.getGrowthSpeed(world, pos, state, light);
     if (random.nextInt((int) (50F / growth) + 1) == 0) {
       if (this.getMaxMeta(meta) != meta) {
         meta++;
         world.setBlockState(pos, this.getStateFromMeta(meta));
       }
       if (meta > 3 && world.isAirBlock(pos.add(0, 1, 0)))
         world.setBlockState(pos.add(0, 1, 0), this.getStateFromMeta(meta + 1));
     }
   }
 }
 @Override
 public boolean canBlockStay(World world, BlockPos pos, IBlockState state) {
   boolean b = super.canBlockStay(world, pos, state);
   if (this.getMetaFromState(state) == 5) {
     IBlockState stateBelow = world.getBlockState(pos.add(0, -1, 0));
     b = stateBelow.getBlock().equals(this) && this.getMetaFromState(stateBelow) == getMaxMeta(0);
   }
   return b;
 }
 public static void burnGround(World world, Random rand, BlockPos position, int radius) {
   for (int i = 0; radius >= 0 && i < 3; ++i) {
     int j = radius + rand.nextInt(2);
     int k = (radius + rand.nextInt(2));
     int l = radius + rand.nextInt(2);
     float f = (float) (j + k + l) * 0.333F + 0.5F;
     for (BlockPos blockpos :
         BlockPos.getAllInBox(position.add(-j, -k, -l), position.add(j, k, l))) {
       if (blockpos.distanceSq(position) <= (double) (f * f)) {
         IBlockState state = world.getBlockState(blockpos);
         if (state.getMaterial() == Material.GRASS
             || state.getMaterial() == Material.CRAFTED_SNOW && world.canBlockSeeSky(blockpos)) {
           world.setBlockState(blockpos, ModBlocks.frozenGrass.getDefaultState());
         } else if (state.getMaterial() == Material.GROUND && state.getBlock() == Blocks.DIRT
             || state.getMaterial() == Material.CRAFTED_SNOW && !world.canBlockSeeSky(blockpos)) {
           world.setBlockState(blockpos, ModBlocks.frozenDirt.getDefaultState());
         } else if (state.getMaterial() == Material.GROUND && state.getBlock() == Blocks.GRAVEL) {
           world.setBlockState(blockpos, ModBlocks.frozenGravel.getDefaultState());
         } else if (state.getMaterial() == Material.ROCK
             && (state.getBlock() == Blocks.COBBLESTONE
                 || state.getBlock().getUnlocalizedName().contains("cobblestone"))) {
           world.setBlockState(blockpos, ModBlocks.frozenCobblestone.getDefaultState());
         } else if (state.getMaterial() == Material.ROCK) {
           world.setBlockState(blockpos, ModBlocks.frozenStone.getDefaultState());
         } else if (state.getBlock() == Blocks.GRASS_PATH) {
           world.setBlockState(blockpos, ModBlocks.frozenGrassPath.getDefaultState());
         } else if (state.getMaterial() == Material.WOOD) {
           world.setBlockState(blockpos, ModBlocks.ash.getDefaultState());
         } else if (state.getMaterial() == Material.LEAVES
             || state.getMaterial() == Material.PLANTS
             || state.getBlock() == Blocks.SNOW_LAYER) {
           world.setBlockState(blockpos, Blocks.AIR.getDefaultState());
         }
       }
     }
   }
 }
  /** grow leaves in a circle */
  protected void growLeavesLayer(World worldIn, BlockPos layerCenter, int width) {
    int i = width * width;

    for (int j = -width; j <= width; ++j) {
      for (int k = -width; k <= width; ++k) {
        if (j * j + k * k <= i) {
          BlockPos blockpos = layerCenter.add(j, 0, k);
          IBlockState state = worldIn.getBlockState(blockpos);

          if (state.getBlock().isAir(state, worldIn, blockpos)
              || state.getBlock().isLeaves(state, worldIn, blockpos)) {
            this.setBlockAndNotifyAdequately(worldIn, blockpos, this.leavesMetadata);
          }
        }
      }
    }
  }
  @Override
  public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand) {
    if (worldIn.getGameRules().getBoolean("doFireTick")) {
      if (!canPlaceBlockAt(worldIn, pos)) worldIn.setBlockToAir(pos);

      if (worldIn.isRaining() && canDie(worldIn, pos)) worldIn.setBlockToAir(pos);
      else {
        int i = state.getValue(AGE).intValue();

        if (i < 4) {
          state = state.withProperty(AGE, Integer.valueOf(i + rand.nextInt(3) / 2));
          worldIn.setBlockState(pos, state, 4);
        }

        worldIn.scheduleUpdate(pos, this, tickRate(worldIn) + rand.nextInt(10));

        if (!canNeighborCatchFire(worldIn, pos)) {
          if (!worldIn.getBlockState(pos.down()).isSideSolid(worldIn, pos.down(), EnumFacing.UP)
              || i > 3) worldIn.setBlockToAir(pos);

          return;
        }

        if (!this.canCatchFire(worldIn, pos.down(), EnumFacing.UP)
            && i >= 4
            && rand.nextInt(4) == 0) {
          worldIn.setBlockToAir(pos);
          return;
        }

        boolean flag1 = worldIn.isBlockinHighHumidity(pos);
        int j = 0;

        if (flag1) j = -50;

        tryCatchFire(worldIn, pos.east(), 300 + j, rand, i, EnumFacing.WEST);
        tryCatchFire(worldIn, pos.west(), 300 + j, rand, i, EnumFacing.EAST);
        tryCatchFire(worldIn, pos.down(), 250 + j, rand, i, EnumFacing.UP);
        tryCatchFire(worldIn, pos.up(), 250 + j, rand, i, EnumFacing.DOWN);
        tryCatchFire(worldIn, pos.north(), 300 + j, rand, i, EnumFacing.SOUTH);
        tryCatchFire(worldIn, pos.south(), 300 + j, rand, i, EnumFacing.NORTH);

        for (int k = -1; k <= 1; ++k)
          for (int l = -1; l <= 1; ++l)
            for (int i1 = -1; i1 <= 4; ++i1)
              if (k != 0 || i1 != 0 || l != 0) {
                int j1 = 100;

                if (i1 > 1) j1 += (i1 - 1) * 100;

                BlockPos blockpos = pos.add(k, i1, l);
                int k1 = getNeighborEncouragement(worldIn, blockpos);

                if (k1 > 0) {
                  int l1 = (k1 + 40 + worldIn.getDifficulty().getDifficultyId() * 7) / (i + 30);

                  if (flag1) l1 /= 2;

                  if (l1 > 0
                      && rand.nextInt(j1) <= l1
                      && (!worldIn.isRaining() || !canDie(worldIn, blockpos))) {
                    int i2 = i + rand.nextInt(5) / 4;

                    if (i2 > 15) i2 = 15;

                    worldIn.setBlockState(
                        blockpos, state.withProperty(AGE, Integer.valueOf(i2)), 3);
                  }
                }
              }
      }
    }
  }
  @Override
  public void onUpdate() {
    super.onUpdate();

    if (supertile.getWorld().isRemote || redstoneSignal > 0) return;

    if (ticksExisted % 10 == 0) {
      IBlockState filter = getUnderlyingBlock();

      boolean scanned = false;
      List<BlockPos> validPositions = new ArrayList<>();

      int rangePlace = getRange();
      int rangePlaceY = getRangeY();

      BlockPos pos = supertile.getPos();

      List<EntityItem> items =
          supertile
              .getWorld()
              .getEntitiesWithinAABB(
                  EntityItem.class,
                  new AxisAlignedBB(
                      supertile.getPos().add(-RANGE, -RANGE_Y, -RANGE),
                      supertile.getPos().add(RANGE + 1, RANGE_Y + 1, RANGE + 1)));
      int slowdown = getSlowdownFactor();
      for (EntityItem item : items) {
        int age;
        try {
          age = (int) MethodHandles.itemAge_getter.invokeExact(item);
        } catch (Throwable t) {
          continue;
        }

        if (age < (60 + slowdown) || item.isDead) continue;

        ItemStack stack = item.getEntityItem();
        Item stackItem = stack.getItem();
        if (stackItem instanceof ItemBlock
            || stackItem instanceof ItemBlockSpecial
            || stackItem instanceof ItemRedstone
            || stackItem instanceof IFlowerPlaceable) {
          if (!scanned) {
            for (BlockPos pos_ :
                BlockPos.getAllInBox(
                    pos.add(-rangePlace, -rangePlaceY, -rangePlace),
                    pos.add(rangePlace, rangePlaceY, rangePlace))) {
              IBlockState stateAbove = supertile.getWorld().getBlockState(pos_.up());
              Block blockAbove = stateAbove.getBlock();
              BlockPos up = pos_.up();
              if (filter == supertile.getWorld().getBlockState(pos_)
                  && (blockAbove.isAir(stateAbove, supertile.getWorld(), up)
                      || blockAbove.isReplaceable(supertile.getWorld(), up)))
                validPositions.add(up);
            }

            scanned = true;
          }

          if (!validPositions.isEmpty()) {
            BlockPos coords =
                validPositions.get(supertile.getWorld().rand.nextInt(validPositions.size()));

            IBlockState stateToPlace = null;
            if (stackItem instanceof IFlowerPlaceable)
              stateToPlace =
                  ((IFlowerPlaceable) stackItem).getBlockToPlaceByFlower(stack, this, coords);
            if (stackItem instanceof ItemBlock)
              stateToPlace =
                  ((ItemBlock) stackItem)
                      .block.getStateFromMeta(stackItem.getMetadata(stack.getItemDamage()));
            else if (stackItem instanceof ItemBlockSpecial)
              stateToPlace =
                  ((Block)
                          ReflectionHelper.getPrivateValue(
                              ItemBlockSpecial.class,
                              (ItemBlockSpecial) stackItem,
                              LibObfuscation.REED_ITEM))
                      .getDefaultState();
            else if (stackItem instanceof ItemRedstone)
              stateToPlace = Blocks.REDSTONE_WIRE.getDefaultState();

            if (stateToPlace != null) {
              if (stateToPlace.getBlock().canPlaceBlockAt(supertile.getWorld(), coords)) {
                supertile.getWorld().setBlockState(coords, stateToPlace, 1 | 2);
                if (ConfigHandler.blockBreakParticles)
                  supertile.getWorld().playEvent(2001, coords, Block.getStateId(stateToPlace));
                validPositions.remove(coords);

                TileEntity tile = supertile.getWorld().getTileEntity(coords);
                if (tile != null && tile instanceof ISubTileContainer) {
                  ISubTileContainer container = (ISubTileContainer) tile;
                  String subtileName = ItemBlockSpecialFlower.getType(stack);
                  container.setSubTile(subtileName);
                  SubTileEntity subtile = container.getSubTile();
                  subtile.onBlockPlacedBy(
                      supertile.getWorld(),
                      coords,
                      supertile.getWorld().getBlockState(coords),
                      null,
                      stack);
                }

                if (stackItem instanceof IFlowerPlaceable)
                  ((IFlowerPlaceable) stackItem).onBlockPlacedByFlower(stack, this, coords);

                stack.stackSize--;
                if (stack.stackSize <= 0) item.setDead();

                if (mana > 1) mana--;
                return;
              }
            }
          }
        }
      }
    }
  }
  @Override
  public void populate(int chunkX, int chunkZ) {
    BlockFalling.fallInstantly = true;

    int worldX = chunkX * 16;
    int worldZ = chunkZ * 16;
    BlockPos blockPos = new BlockPos(worldX, 0, worldZ);
    Biome biome = worldObj.getBiomeGenForCoords(blockPos.add(16, 0, 16));
    BiomeDecorator decorator = biome.theBiomeDecorator;
    int worldHeight = worldObj.provider.getActualHeight();

    ForgeEventFactory.onChunkPopulate(true, this, worldObj, rand, chunkX, chunkZ, false);

    int x, y, z;

    if (CavelandConfig.generateLakes) {
      if (TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, false, EventType.LAKE)) {
        x = rand.nextInt(16) + 8;
        y = rand.nextInt(worldHeight - 16);
        z = rand.nextInt(16) + 8;

        lakeWaterGen.generate(worldObj, rand, blockPos.add(x, y, z));
      }

      if (rand.nextInt(30) == 0
          && TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, false, EventType.LAVA)) {
        x = rand.nextInt(16) + 8;
        y = rand.nextInt(worldHeight / 2);
        z = rand.nextInt(16) + 8;

        lakeLavaGen.generate(worldObj, rand, blockPos.add(x, y, z));
      }
    }

    MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Pre(worldObj, rand, blockPos));

    MinecraftForge.ORE_GEN_BUS.post(new OreGenEvent.Pre(worldObj, rand, blockPos));

    for (CaveVein vein : CavelandConfig.veinManager.getCaveVeins()) {
      vein.generateVeins(worldObj, rand, blockPos);
    }

    MinecraftForge.ORE_GEN_BUS.post(new OreGenEvent.Post(worldObj, rand, blockPos));

    for (int i = 0; i < 10; ++i) {
      x = rand.nextInt(16) + 8;
      y = rand.nextInt(worldHeight - 10);
      z = rand.nextInt(16) + 8;

      acresiaGen.generate(worldObj, rand, blockPos.add(x, y, z));
    }

    for (int i = 0; i < 15; ++i) {
      x = rand.nextInt(16) + 8;
      y = rand.nextInt(worldHeight / 2 - 10) + worldHeight / 2;
      z = rand.nextInt(16) + 8;

      acresiaGen.generate(worldObj, rand, blockPos.add(x, y, z));
    }

    if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.SHROOM)) {
      for (int i = 0; i < 5; ++i) {
        x = rand.nextInt(16) + 8;
        y = rand.nextInt(worldHeight - 10);
        z = rand.nextInt(16) + 8;

        decorator.mushroomBrownGen.generate(worldObj, rand, blockPos.add(x, y, z));
      }

      for (int i = 0; i < 5; ++i) {
        x = rand.nextInt(16) + 8;
        y = rand.nextInt(worldHeight - 10);
        z = rand.nextInt(16) + 8;

        decorator.mushroomRedGen.generate(worldObj, rand, blockPos.add(x, y, z));
      }
    }

    if (BiomeDictionary.isBiomeOfType(biome, Type.SANDY)) {
      if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.CACTUS)) {
        for (int i = 0; i < 80; ++i) {
          x = rand.nextInt(16) + 8;
          y = rand.nextInt(worldHeight - 5);
          z = rand.nextInt(16) + 8;

          decorator.cactusGen.generate(worldObj, rand, blockPos.add(x, y, z));
        }
      }

      if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.DEAD_BUSH)) {
        for (int i = 0; i < 10; ++i) {
          x = rand.nextInt(16) + 8;
          y = rand.nextInt(worldHeight - 5);
          z = rand.nextInt(16) + 8;

          deadBushGen.generate(worldObj, rand, blockPos.add(x, y, z));
        }
      }
    } else {
      if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.FLOWERS)) {
        for (int i = 0; i < 8; ++i) {
          x = rand.nextInt(16) + 8;
          y = rand.nextInt(worldHeight - 5);
          z = rand.nextInt(16) + 8;

          decorator.yellowFlowerGen.generate(worldObj, rand, blockPos.add(x, y, z));
        }
      }

      for (int i = 0; i < 18; ++i) {
        x = rand.nextInt(16) + 8;
        y = rand.nextInt(worldHeight - 5);
        z = rand.nextInt(16) + 8;

        biome.getRandomWorldGenForGrass(rand).generate(worldObj, rand, blockPos.add(x, y, z));
      }

      if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.TREE)) {
        WorldGenAbstractTree treeGen = null;

        if (BiomeDictionary.isBiomeOfType(biome, Type.JUNGLE)) {
          treeGen =
              new WorldGenTreesPerverted(
                  false, 4 + rand.nextInt(7), BlockPlanks.EnumType.JUNGLE, true);
        } else if (BiomeDictionary.isBiomeOfType(biome, Type.FOREST)
            || !BiomeDictionary.isBiomeOfType(biome, Type.PLAINS)
            || rand.nextInt(10) == 0) {
          if (BiomeDictionary.isBiomeOfType(biome, Type.COLD)) {
            treeGen = new WorldGenSpruceTreePerverted(false);
          } else if (rand.nextInt(3) == 0) {
            treeGen = new WorldGenBirchTreePerverted(false, false);
          } else {
            treeGen = new WorldGenTreesPerverted(false, 3, BlockPlanks.EnumType.OAK, true);
          }
        }

        if (treeGen != null) {
          for (int i = 0; i < 80; ++i) {
            x = rand.nextInt(16) + 8;
            y = rand.nextInt(worldHeight);
            z = rand.nextInt(16) + 8;

            BlockPos pos = blockPos.add(x, y, z);

            if (treeGen.generate(worldObj, rand, pos)) {
              treeGen.generateSaplings(worldObj, rand, pos);
            }
          }

          for (int i = 0; i < 60; ++i) {
            x = rand.nextInt(16) + 8;
            y = 8 + rand.nextInt(5);
            z = rand.nextInt(16) + 8;

            BlockPos pos = blockPos.add(x, y, z);

            if (treeGen.generate(worldObj, rand, pos)) {
              treeGen.generateSaplings(worldObj, rand, pos);
            }
          }
        }
      }

      if (decorator.generateLakes) {
        if (BiomeDictionary.isBiomeOfType(biome, Type.WATER)) {
          if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.LAKE_WATER)) {
            for (int i = 0; i < 150; ++i) {
              x = rand.nextInt(16) + 8;
              y = rand.nextInt(rand.nextInt(worldHeight - 16) + 10);
              z = rand.nextInt(16) + 8;

              liquidWaterGen.generate(worldObj, rand, blockPos.add(x, y, z));
            }
          }
        } else {
          if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.LAKE_WATER)) {
            for (int i = 0; i < 100; ++i) {
              x = rand.nextInt(16) + 8;
              y = rand.nextInt(rand.nextInt(worldHeight - 16) + 10);
              z = rand.nextInt(16) + 8;

              liquidWaterGen.generate(worldObj, rand, blockPos.add(x, y, z));
            }
          }

          if (TerrainGen.decorate(worldObj, rand, blockPos, Decorate.EventType.LAKE_LAVA)) {
            for (int i = 0; i < 20; ++i) {
              x = rand.nextInt(16) + 8;
              y = rand.nextInt(worldHeight / 2);
              z = rand.nextInt(16) + 8;

              liquidLavaGen.generate(worldObj, rand, blockPos.add(x, y, z));
            }
          }
        }
      }
    }

    MinecraftForge.EVENT_BUS.post(new DecorateBiomeEvent.Post(worldObj, rand, blockPos));

    ForgeEventFactory.onChunkPopulate(false, this, worldObj, rand, chunkX, chunkZ, false);

    BlockFalling.fallInstantly = false;
  }
 // canBonemeal
 @Override
 public boolean canUseBonemeal(World world, Random rand, BlockPos pos, IBlockState state) {
   int meta = this.getMetaFromState(state);
   if (meta < getMaxMeta(meta)) return true;
   else return meta == 4 && !world.getBlockState(pos.add(0, 1, 0)).getBlock().equals(this);
 }
 // isNotGrown
 @Override
 public boolean canGrow(World world, BlockPos pos, IBlockState state, boolean isClient) {
   int meta = this.getMetaFromState(state);
   if (meta < getMaxMeta(meta)) return true;
   else return meta == 4 && !world.getBlockState(pos.add(0, 1, 0)).getBlock().equals(this);
 }
 @Override
 public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block) {
   super.neighborChanged(state, world, pos, block);
   if (this.getMetaFromState(state) < getMaxMeta(0))
     world.notifyBlockOfStateChange(pos.add(0, 1, 0), this);
 }
  @Override
  public boolean generate(World world, Random rand, BlockPos pos) {
    int i1 = rand.nextInt(2) + 2;
    int j1 = -i1 - 1;
    int k1 = i1 + 1;
    int i2 = rand.nextInt(2) + 2;
    int j2 = -i2 - 1;
    int k2 = i2 + 1;
    int count = 0;

    for (int x = j1; x <= k1; ++x) {
      for (int y = -1; y <= 4; ++y) {
        for (int z = j2; z <= k2; ++z) {
          BlockPos blockpos = pos.add(x, y, z);
          Material material = world.getBlockState(blockpos).getMaterial();
          boolean flag = material.isSolid();

          if (y == -1 && !flag) {
            return false;
          }

          if (y == 4 && !flag) {
            return false;
          }

          if ((x == j1 || x == k1 || z == j2 || z == k2)
              && y == 0
              && world.isAirBlock(blockpos)
              && world.isAirBlock(blockpos.up())) {
            ++count;
          }
        }
      }
    }

    if (count >= 1 && count <= 5) {
      int type = rand.nextInt(2);
      IBlockState state1;
      IBlockState state2;

      switch (type) {
        case 1:
          state1 = Blocks.STONEBRICK.getDefaultState();
          state2 =
              Blocks.STONEBRICK
                  .getDefaultState()
                  .withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.MOSSY);
        default:
          state1 = Blocks.COBBLESTONE.getDefaultState();
          state2 = Blocks.MOSSY_COBBLESTONE.getDefaultState();
      }

      for (int x = j1; x <= k1; ++x) {
        for (int y = 3; y >= -1; --y) {
          for (int z = j2; z <= k2; ++z) {
            BlockPos blockpos = pos.add(x, y, z);

            if (x != j1 && y != -1 && z != j2 && x != k1 && y != 4 && z != k2) {
              if (world.getBlockState(blockpos).getBlock() != Blocks.CHEST) {
                world.setBlockToAir(blockpos);
              }
            } else if (blockpos.getY() >= 0
                && !world.getBlockState(blockpos.down()).getMaterial().isSolid()) {
              world.setBlockToAir(blockpos);
            } else if (world.getBlockState(blockpos).getMaterial().isSolid()
                && world.getBlockState(blockpos).getBlock() != Blocks.CHEST) {
              if (y == -1 && rand.nextInt(4) != 0) {
                world.setBlockState(blockpos, state2, 2);
              } else {
                world.setBlockState(blockpos, state1, 2);
              }
            }
          }
        }
      }

      for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
          int x = pos.getX() + rand.nextInt(i1 * 2 + 1) - i1;
          int y = pos.getY();
          int z = pos.getZ() + rand.nextInt(i2 * 2 + 1) - i2;
          BlockPos blockpos = new BlockPos(x, y, z);

          if (world.isAirBlock(blockpos)) {
            count = 0;

            for (EnumFacing face : EnumFacing.Plane.HORIZONTAL) {
              if (world.getBlockState(blockpos.offset(face)).getMaterial().isSolid()) {
                ++count;
              }
            }

            if (count == 1) {
              world.setBlockState(
                  blockpos,
                  Blocks.CHEST.correctFacing(world, blockpos, Blocks.CHEST.getDefaultState()),
                  2);

              TileEntity tile = world.getTileEntity(blockpos);

              if (tile != null && tile instanceof TileEntityChest) {
                ((TileEntityChest) tile)
                    .setLootTable(LootTableList.CHESTS_SIMPLE_DUNGEON, rand.nextLong());
              }

              break;
            }
          }
        }
      }

      world.setBlockState(pos, Blocks.MOB_SPAWNER.getDefaultState(), 2);

      TileEntity tile = world.getTileEntity(pos);

      if (tile != null && tile instanceof TileEntityMobSpawner) {
        ((TileEntityMobSpawner) tile).getSpawnerBaseLogic().setEntityName(pickMobSpawner(rand));
      } else {
        CaveLog.warning(
            "Failed to fetch mob spawner entity at ("
                + pos.getX()
                + ", "
                + pos.getY()
                + ", "
                + pos.getZ()
                + ")");
      }

      return true;
    }

    return false;
  }