@Override
  public void writeToNBT(NBTTagCompound nbtTags) {
    super.writeToNBT(nbtTags);

    if (fluidTank.getFluid() != null) {
      nbtTags.setTag("fluidTank", fluidTank.writeToNBT(new NBTTagCompound()));
    }

    NBTTagList recurringList = new NBTTagList();

    for (Object3D wrapper : recurringNodes) {
      NBTTagCompound tagCompound = new NBTTagCompound();
      wrapper.write(tagCompound);
      recurringList.appendTag(tagCompound);
    }

    if (recurringList.tagCount() != 0) {
      nbtTags.setTag("recurringNodes", recurringList);
    }

    NBTTagList cleaningList = new NBTTagList();

    for (Object3D obj : cleaningNodes) {
      cleaningList.appendTag(obj.write(new NBTTagCompound()));
    }

    if (cleaningList.tagCount() != 0) {
      nbtTags.setTag("cleaningNodes", cleaningList);
    }
  }
  @Override
  public boolean placeBlockAt(
      ItemStack stack,
      EntityPlayer player,
      World world,
      int x,
      int y,
      int z,
      int side,
      float hitX,
      float hitY,
      float hitZ,
      int metadata) {
    boolean place =
        super.placeBlockAt(stack, player, world, x, y, z, side, hitX, hitY, hitZ, metadata);

    if (place) {
      TileEntityEnergyCube tileEntity = (TileEntityEnergyCube) world.getBlockTileEntity(x, y, z);
      tileEntity.tier = ((IEnergyCube) stack.getItem()).getEnergyCubeTier(stack);
      tileEntity.electricityStored = getEnergy(stack);

      ((ISustainedInventory) tileEntity).setInventory(getInventory(stack));

      if (!world.isRemote) {
        PacketHandler.sendPacket(
            Transmission.ALL_CLIENTS,
            new PacketTileEntity()
                .setParams(Object3D.get(tileEntity), tileEntity.getNetworkedData(new ArrayList())));
      }
    }

    return place;
  }
  @Override
  public void readFromNBT(NBTTagCompound nbtTags) {
    super.readFromNBT(nbtTags);

    if (nbtTags.hasKey("fluidTank")) {
      fluidTank.readFromNBT(nbtTags.getCompoundTag("fluidTank"));
    }

    if (nbtTags.hasKey("recurringNodes")) {
      NBTTagList tagList = nbtTags.getTagList("recurringNodes");

      for (int i = 0; i < tagList.tagCount(); i++) {
        recurringNodes.add(Object3D.read((NBTTagCompound) tagList.tagAt(i)));
      }
    }

    if (nbtTags.hasKey("cleaningNodes")) {
      NBTTagList tagList = nbtTags.getTagList("cleaningNodes");

      for (int i = 0; i < tagList.tagCount(); i++) {
        cleaningNodes.add(Object3D.read((NBTTagCompound) tagList.tagAt(i)));
      }
    }
  }
  public boolean clean(boolean take) {
    boolean took = false;
    if (!worldObj.isRemote) {
      for (Object3D wrapper : cleaningNodes) {
        if (MekanismUtils.isDeadFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)) {
          if (fluidTank.getFluid() != null
              && MekanismUtils.getFluidId(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)
                  == fluidTank.getFluid().fluidID) {
            took = true;
            if (take) {
              worldObj.setBlockToAir(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord);
            }
          }
        }
      }

      for (Object3D wrapper : recurringNodes) {
        if (MekanismUtils.isDeadFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)) {
          if (fluidTank.getFluid() != null
              && MekanismUtils.getFluidId(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)
                  == fluidTank.getFluid().fluidID) {
            took = true;
            if (take) {
              worldObj.setBlockToAir(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord);
            }
          }
        }
      }

      for (ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS) {
        Object3D wrapper = Object3D.get(this).getFromSide(orientation);

        if (MekanismUtils.isDeadFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)) {
          if (fluidTank.getFluid() != null
              && MekanismUtils.getFluidId(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)
                  == fluidTank.getFluid().fluidID) {
            took = true;
            if (take) {
              worldObj.setBlockToAir(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord);
            }
          }
        }
      }
    }

    return took;
  }
  @Override
  public void onUpdate() {
    ChargeUtils.discharge(2, this);

    if (inventory[0] != null) {
      if (fluidTank.getFluid() != null
          && fluidTank.getFluid().amount >= FluidContainerRegistry.BUCKET_VOLUME) {
        if (FluidContainerRegistry.isEmptyContainer(inventory[0])) {
          ItemStack tempStack =
              FluidContainerRegistry.fillFluidContainer(fluidTank.getFluid(), inventory[0]);

          if (tempStack != null) {
            if (inventory[1] == null) {
              fluidTank.drain(FluidContainerRegistry.BUCKET_VOLUME, true);

              inventory[1] = tempStack;
              inventory[0].stackSize--;

              if (inventory[0].stackSize <= 0) {
                inventory[0] = null;
              }
            } else if (tempStack.isItemEqual(inventory[1])
                && tempStack.getMaxStackSize() > inventory[1].stackSize) {
              fluidTank.drain(FluidContainerRegistry.BUCKET_VOLUME, true);

              inventory[1].stackSize++;
              inventory[0].stackSize--;

              if (inventory[0].stackSize <= 0) {
                inventory[0] = null;
              }
            }
          }
        }
      }
    }

    if (!worldObj.isRemote && worldObj.getWorldTime() % 20 == 0) {
      if (getEnergy() >= 100
          && (fluidTank.getFluid() == null
              || fluidTank.getFluid().amount + FluidContainerRegistry.BUCKET_VOLUME <= 10000)) {
        if (suck(true)) {
          PacketHandler.sendPacket(
              Transmission.CLIENTS_RANGE,
              new PacketTileEntity()
                  .setParams(Object3D.get(this), getNetworkedData(new ArrayList())),
              Object3D.get(this),
              50D);
        }

        clean(true);
      }
    }

    super.onUpdate();

    if (fluidTank.getFluid() != null) {
      for (ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS) {
        TileEntity tileEntity = Object3D.get(this).getFromSide(orientation).getTileEntity(worldObj);

        if (tileEntity instanceof IFluidHandler) {
          FluidStack toDrain =
              new FluidStack(fluidTank.getFluid(), Math.min(100, fluidTank.getFluidAmount()));
          fluidTank.drain(
              ((IFluidHandler) tileEntity).fill(orientation.getOpposite(), toDrain, true), true);

          if (fluidTank.getFluid() == null || fluidTank.getFluid().amount <= 0) {
            break;
          }
        }
      }
    }
  }
  public boolean suck(boolean take) {
    List<Object3D> tempPumpList =
        Arrays.asList(recurringNodes.toArray(new Object3D[recurringNodes.size()]));
    Collections.shuffle(tempPumpList);

    for (ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS) {
      Object3D wrapper = Object3D.get(this).getFromSide(orientation);

      if (MekanismUtils.isFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)) {
        if (fluidTank.getFluid() == null
            || MekanismUtils.getFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)
                .isFluidEqual(fluidTank.getFluid())) {
          if (take) {
            setEnergy(getEnergy() - 100);
            recurringNodes.add(new Object3D(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord));
            fluidTank.fill(
                MekanismUtils.getFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord),
                true);
            worldObj.setBlockToAir(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord);
          }

          return true;
        }
      }
    }

    for (Object3D wrapper : cleaningNodes) {
      if (MekanismUtils.isFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)) {
        if (fluidTank.getFluid() != null
            && MekanismUtils.getFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)
                .isFluidEqual(fluidTank.getFluid())) {
          if (take) {
            setEnergy(getEnergy() - 100);
            fluidTank.fill(
                MekanismUtils.getFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord),
                true);
            worldObj.setBlockToAir(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord);
          }

          return true;
        }
      }
    }

    for (Object3D wrapper : tempPumpList) {
      if (MekanismUtils.isFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)) {
        if (fluidTank.getFluid() == null
            || MekanismUtils.getFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord)
                .isFluidEqual(fluidTank.getFluid())) {
          if (take) {
            setEnergy(electricityStored - 100);
            fluidTank.fill(
                MekanismUtils.getFluid(worldObj, wrapper.xCoord, wrapper.yCoord, wrapper.zCoord),
                true);
            worldObj.setBlockToAir(wrapper.xCoord, wrapper.yCoord, wrapper.zCoord);
          }

          return true;
        }
      }

      for (ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS) {
        Object3D side = wrapper.getFromSide(orientation);

        if (Object3D.get(this).distanceTo(side) <= 80) {
          if (MekanismUtils.isFluid(worldObj, side.xCoord, side.yCoord, side.zCoord)) {
            if (fluidTank.getFluid() == null
                || MekanismUtils.getFluid(worldObj, side.xCoord, side.yCoord, side.zCoord)
                    .isFluidEqual(fluidTank.getFluid())) {
              if (take) {
                setEnergy(electricityStored - 100);
                recurringNodes.add(side);
                fluidTank.fill(
                    MekanismUtils.getFluid(worldObj, side.xCoord, side.yCoord, side.zCoord), true);
                worldObj.setBlockToAir(side.xCoord, side.yCoord, side.zCoord);
              }

              return true;
            }
          }
        }
      }

      cleaningNodes.add(wrapper);
      recurringNodes.remove(wrapper);
    }

    return false;
  }