@Override
  public void updateEntity() {
    super.updateEntity();

    if (FMLCommonHandler.instance().getEffectiveSide().isClient()) return;

    if (++searchTicks > 20) {
      shipCore = searchShipCore();
      searchTicks = 0;
    }

    // Warp core is not found
    if (!isDeploying && shipCore == null) {
      setActive(false); // disable scanner
      return;
    }

    if (!isActive) { // inactive
      if (++laserTicks > 20) {
        PacketHandler.sendBeamPacket(
            worldObj,
            new Vector3(this).translate(0.5D),
            new Vector3(shipCore.xCoord, shipCore.yCoord, shipCore.zCoord).translate(0.5D),
            0f,
            1f,
            0f,
            40,
            0,
            100);
        laserTicks = 0;
      }
    } else if (!isDeploying) { // active and scanning
      if (++laserTicks > 5) {
        laserTicks = 0;

        for (int i = 0; i < shipCore.maxX - shipCore.minX; i++) {
          int x = shipCore.minX + i;
          int randomZ = shipCore.minZ + worldObj.rand.nextInt(shipCore.maxZ - shipCore.minZ);

          worldObj.playSoundEffect(
              xCoord + 0.5f, yCoord, zCoord + 0.5f, "warpdrive:lowlaser", 4F, 1F);
          float r = 0.0f, g = 0.0f, b = 0.0f;

          switch (worldObj.rand.nextInt(6)) {
            case 0:
              r = 1.0f;
              g = b = 0;
              break;

            case 1:
              r = b = 0;
              g = 1.0f;
              break;

            case 2:
              r = g = 0;
              b = 1.0f;
              break;

            case 3:
              r = b = 0.5f;
              g = 0;
              break;

            case 4:
              r = g = 1.0f;
              b = 0;
              break;

            case 5:
              r = 1.0f;
              b = 0.5f;
              g = 0f;
              break;

            default:
              break;
          }

          PacketHandler.sendBeamPacket(
              worldObj,
              new Vector3(this).translate(0.5D),
              new Vector3(x, shipCore.maxY, randomZ).translate(0.5D),
              r,
              g,
              b,
              15,
              0,
              100);
        }
      }

      if (++scanTicks > 20 * (1 + shipCore.shipMass / 10)) {
        setActive(false); // disable scanner
        scanTicks = 0;
      }
    } else { // active and deploying
      if (++deployDelayTicks < 20) return;

      deployDelayTicks = 0;

      int blocks =
          Math.min(WarpDriveConfig.G_BLOCKS_PER_TICK, blocksToDeployCount - currentDeployIndex);

      if (blocks == 0) {
        isDeploying = false;
        setActive(false); // disable scanner
        return;
      }

      for (int index = 0; index < blocks; index++) {
        if (currentDeployIndex >= blocksToDeployCount) {
          isDeploying = false;
          setActive(false); // disable scanner
          break;
        }

        // Deploy single block
        JumpBlock jb = blocksToDeploy[currentDeployIndex];

        if (jb != null && !WarpDriveConfig.BLOCKS_ANCHOR.contains(jb.block)) {
          Block blockAtTarget = worldObj.getBlock(targetX + jb.x, targetY + jb.y, targetZ + jb.z);
          if (blockAtTarget == Blocks.air
              || WarpDriveConfig.BLOCKS_EXPANDABLE.contains(blockAtTarget)) {
            jb.deploy(worldObj, targetX, targetY, targetZ);

            if (worldObj.rand.nextInt(100) <= 10) {
              worldObj.playSoundEffect(
                  xCoord + 0.5f, yCoord, zCoord + 0.5f, "warpdrive:lowlaser", 4F, 1F);

              PacketHandler.sendBeamPacket(
                  worldObj,
                  new Vector3(this).translate(0.5D),
                  new Vector3(targetX + jb.x, targetY + jb.y, targetZ + jb.z).translate(0.5D),
                  0f,
                  1f,
                  0f,
                  15,
                  0,
                  100);
            }
          }
        }

        currentDeployIndex++;
      }
    }
  }
  // Returns error code and reason string
  private int deployShip(
      String fileName, int offsetX, int offsetY, int offsetZ, StringBuilder reason) {
    // Load schematic
    NBTTagCompound schematic = readNBTFromFile(WarpDriveConfig.G_SCHEMALOCATION + "/" + fileName);
    if (schematic == null) {
      reason.append("Schematic not found or unknow error reading it.");
      return -1;
    }

    // Compute geometry
    short width = schematic.getShort("Width");
    short height = schematic.getShort("Height");
    short length = schematic.getShort("Length");

    targetX = xCoord + offsetX;
    targetY = yCoord + offsetY;
    targetZ = zCoord + offsetZ;
    blocksToDeployCount = width * height * length;

    // Validate context
    {
      // Check distance
      double dX = xCoord - targetX;
      double dY = yCoord - targetY;
      double dZ = zCoord - targetZ;
      double distance = MathHelper.sqrt_double(dX * dX + dY * dY + dZ * dZ);

      if (distance > WarpDriveConfig.SS_MAX_DEPLOY_RADIUS_BLOCKS) {
        reason.append("Cannot deploy ship so far away from scanner.");
        return 5;
      }

      // Consume energy
      if (!consumeEnergy(getDeploymentEnergyCost(blocksToDeployCount), false)) {
        reason.append(
            "Insufficient energy (" + getDeploymentEnergyCost(blocksToDeployCount) + " required)");
        return 1;
      }

      // Check specified area for occupation by blocks
      // If specified area occupied, break deploying with error message
      int occupiedBlockCount = 0;
      for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
          for (int z = 0; z < length; z++) {
            if (!worldObj.isAirBlock(targetX + x, targetY + y, targetZ + z)) occupiedBlockCount++;
          }
        }
      }
      if (occupiedBlockCount > 0) {
        reason.append(
            "Deploying area occupied with " + occupiedBlockCount + " blocks. Can't deploy ship.");
        return 2;
      }
    }

    // Set deployment variables
    blocksToDeploy = new JumpBlock[blocksToDeployCount];
    isDeploying = true;
    currentDeployIndex = 0;

    // Read blocks and TileEntities from NBT to internal storage array
    NBTTagList localBlocks = (NBTTagList) schematic.getTag("Blocks");
    byte localMetadata[] = schematic.getByteArray("Data");

    // Load Tile Entities
    NBTTagCompound[] tileEntities = new NBTTagCompound[blocksToDeployCount];
    NBTTagList tileEntitiesList =
        schematic.getTagList(
            "TileEntities", new NBTTagByteArray(new byte[0]).getId()); // TODO: 0 is not correct

    for (int i = 0; i < tileEntitiesList.tagCount(); i++) {
      NBTTagCompound teTag = tileEntitiesList.getCompoundTagAt(i);
      int teX = teTag.getInteger("x");
      int teY = teTag.getInteger("y");
      int teZ = teTag.getInteger("z");

      tileEntities[teX + (teY * length + teZ) * width] = teTag;
    }

    // Create list of blocks to deploy
    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        for (int z = 0; z < length; z++) {
          int index = x + (y * length + z) * width;
          JumpBlock jb = new JumpBlock();

          jb.x = x;
          jb.y = y;
          jb.z = z;
          jb.block = Block.getBlockFromName(localBlocks.getStringTagAt(index));
          jb.blockMeta = (localMetadata[index]) & 0xFF;
          jb.blockNBT = tileEntities[index];

          if (jb.block != null) {

            if (WarpDriveConfig.LOGGING_BUILDING) {
              if (tileEntities[index] == null) {
                WarpDrive.logger.info(
                    "[ShipScanner] Adding block to deploy: "
                        + jb.block.getUnlocalizedName()
                        + " (no tile entity)");
              } else {
                WarpDrive.logger.info(
                    "[ShipScanner] Adding block to deploy: "
                        + jb.block.getUnlocalizedName()
                        + " with tile entity "
                        + tileEntities[index].getString("id"));
              }
            }

            blocksToDeploy[index] = jb;
          } else {
            jb = null;

            blocksToDeploy[index] = jb;
          }
        }
      }
    }

    setActive(true);
    reason.append("Ship deploying...");
    return 3;
  }