@SideOnly(Side.CLIENT)
 public final int getScaledStoredEnergyClient(int scale) {
   float maxEnergy = getMaxStoredEnergy();
   return MathUtil.floatEquals(maxEnergy, 0F)
       ? -1
       : MathUtil.ceil(storedEnergy * (double) scale / maxEnergy);
 }
 @SideOnly(Side.CLIENT)
 protected static final float getRenderDistanceMp() {
   return MathUtil.clamp(
       1F - MathUtil.square(Minecraft.getMinecraft().gameSettings.renderDistanceChunks) / 300F,
       0F,
       1F); // 16 chunks -> max 256
 }
 public static boolean setItemEnergy(ItemDamagePair pair, float energyUnits) {
   if (!MathUtil.floatEquals(
       getItemEnergy(new ItemStack(pair.item, 1, pair.damage == -1 ? 0 : pair.damage)), 0F))
     return false;
   items.put(pair, EnergyChunkData.energyDrainUnit * energyUnits);
   return true;
 }
  public <T extends EntityLiving> Consumer<T> spawnOnFloor(final Predicate<BlockInfo> blockFinder) {
    return entity -> {
      final Random rand = entity.worldObj.rand;
      final double posX = area.x1 + rand.nextDouble() * (area.x2 - area.x1);
      final double posZ = area.z1 + rand.nextDouble() * (area.z2 - area.z1);
      final int posY =
          Pos.getTopBlock(
                  entity.worldObj,
                  MathUtil.floor(posX),
                  MathUtil.floor(posZ),
                  area.y1 + rand.nextInt(1 + area.y2 - area.y1),
                  blockFinder)
              .getY();

      entity.setPosition(posX, posY + 1D, posZ);
    };
  }
  public float drainEnergy(float amount, TileEntityAbstractEnergyInventory tile) {
    if (data.getEnergyLevel() >= EnergyChunkData.minSignificantEnergy)
      PacketPipeline.sendToAllAround(this, 64D, new C10ParticleEnergyTransfer(tile, this));

    float left = data.drainEnergy(amount);
    if (!MathUtil.floatEquals(left, amount)) synchronize();
    return left;
  }
  public float addEnergy(float amount, TileEntityAbstractEnergyInventory tile) {
    if (data.getEnergyLevel() < data.getMaxEnergyLevel())
      PacketPipeline.sendToAllAround(this, 64D, new C10ParticleEnergyTransfer(tile, this));

    float left = data.addEnergy(amount);
    if (!MathUtil.floatEquals(left, amount)) synchronize();
    return left;
  }
  /**
   * Returns true to apply default vanilla values to fog position. Can be overridden to configure
   * fog GL settings.
   */
  @SideOnly(Side.CLIENT)
  public boolean setupFog() {
    float voidFactor = (float) EndTerritory.getVoidFactor(Minecraft.getMinecraft().thePlayer);
    float fogMultiplier = Math.max(1F, MathUtil.square(voidFactor * 0.8F + 0.8F));

    GL11.glFogi(GL11.GL_FOG_MODE, GL11.GL_EXP2);
    GL11.glFogf(GL11.GL_FOG_DENSITY, getFogDensity() * fogMultiplier);
    GL11.glHint(GL11.GL_FOG_HINT, GL11.GL_DONT_CARE);
    return true;
  }
  public <T extends EntityLiving> IGroupLocationFinder<T> groupOnFloor(
      final double minDistance, final double maxDistance, final Predicate<BlockInfo> blockFinder) {
    return (parentEntity, groupedEntity) -> {
      final Random rand = parentEntity.worldObj.rand;
      final Vec offset =
          Vec.xzRandom(rand)
              .multiplied(minDistance + rand.nextDouble() * (maxDistance - minDistance));
      final double posX = parentEntity.posX + offset.x;
      final double posZ = parentEntity.posZ + offset.z;
      final int posY =
          Pos.getTopBlock(
                  parentEntity.worldObj,
                  MathUtil.floor(posX),
                  MathUtil.floor(posZ),
                  MathUtil.floor(parentEntity.posY + maxDistance),
                  blockFinder)
              .getY();

      groupedEntity.setPosition(posX, posY + 1D, posZ);
    };
  }
  /** 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;
  }
 @SideOnly(Side.CLIENT)
 public final int getScaledTimeClient(int scale) {
   if (time == 0 && timeStep == 0) return -1;
   return MathUtil.ceil(time * (double) scale / totalTime);
 }
 @Override
 public void writeToNBT(NBTTagCompound nbt) {
   super.writeToNBT(nbt);
   if (!MathUtil.floatEquals(storedEnergy, 0F)) nbt.setFloat("storedEng", storedEnergy);
 }
 @Override
 @SideOnly(Side.CLIENT)
 public IIcon getIcon(int side, int meta) {
   return iconArray[MathUtil.clamp(meta, 0, iconArray.length - 1)];
 }