@Override
  public boolean onProject(IProjector projector, Set<Vector3> fieldBlocks) {
    Set<IBlockFrequency> machines =
        FrequencyGrid.instance().get(((IFortronFrequency) projector).getFrequency());

    for (IBlockFrequency compareProjector : machines) {
      if (compareProjector instanceof IProjector && compareProjector != projector) {
        if (((TileEntity) compareProjector).worldObj == ((TileEntity) projector).worldObj) {
          if (((TileMFFS) compareProjector).isActive()
              && ((IProjector) compareProjector).getMode() != null) {
            Iterator<Vector3> it = fieldBlocks.iterator();

            while (it.hasNext()) {
              Vector3 position = it.next();

              if (((IProjector) compareProjector)
                  .getMode()
                  .isInField((IProjector) compareProjector, position.clone())) {
                it.remove();
              }
            }
          }
        }
      }
    }
    return false;
  }
  @Override
  public Set<Vector3> getInteriorPoints(IFieldInteraction projector) {
    Set<Vector3> fieldBlocks = new HashSet<Vector3>();

    Vector3 posScale = projector.getPositiveScale();
    Vector3 negScale = projector.getNegativeScale();

    int xStretch = posScale.intX() + negScale.intX();
    int yStretch = posScale.intY() + negScale.intY();
    int zStretch = posScale.intZ() + negScale.intZ();
    Vector3 translation = new Vector3(0, -0.4, 0);

    for (float x = -xStretch; x <= xStretch; x++) {
      for (float z = -zStretch; z <= zStretch; z++) {
        for (float y = 0; y <= yStretch; y++) {
          Vector3 position = new Vector3(x, y, z).add(translation);

          if (this.isInField(
              projector, Vector3.translate(position, new Vector3((TileEntity) projector)))) {
            fieldBlocks.add(position);
          }
        }
      }
    }

    return fieldBlocks;
  }
  public void updatePath() {
    if (thread == null && getLink() != null && lastCalcTime <= 0) {
      pathfinder = null;

      Vector3 start = getPosition();
      Vector3 target = new Vector3(getLink().x(), getLink().y(), getLink().z());

      if (start.distance(target) < Settings.MAX_LEVITATOR_DISTANCE) {
        if (canBeMovePath(world(), start) && canBeMovePath(world(), target)) {
          thread = new ThreadLevitatorPathfinding(new PathfinderLevitator(world(), target), start);
          thread.start();
          lastCalcTime = 40;
        }
      }
    }
  }
 public static boolean canBePath(World world, Vector3 position) {
   Block block = Block.blocksList[position.getBlockID(world)];
   return block == null
       || (block instanceof BlockSnow
           || block instanceof BlockVine
           || block instanceof BlockLadder
           || ((block instanceof BlockFluid || block instanceof IFluidBlock)
               && block.blockID != Block.lavaMoving.blockID
               && block.blockID != Block.lavaStill.blockID));
 }
  @Override
  public Set<Vector3> getExteriorPoints(IFieldInteraction projector) {
    final Set<Vector3> fieldBlocks = new HashSet<Vector3>();

    final Vector3 posScale = projector.getPositiveScale();
    final Vector3 negScale = projector.getNegativeScale();

    final int xStretch = posScale.intX() + negScale.intX();
    final int yStretch = posScale.intY() + negScale.intY();
    final int zStretch = posScale.intZ() + negScale.intZ();
    final Vector3 translation = new Vector3(0, -negScale.intY(), 0);

    final int inverseThickness = (int) Math.max((yStretch + zStretch) / 4f, 1);
    System.out.println(inverseThickness);

    for (float y = 0; y <= yStretch; y += 1f) {
      for (float x = -xStretch; x <= xStretch; x += 1f) {
        for (float z = -zStretch; z <= zStretch; z += 1f) {
          double yTest = (y / yStretch) * inverseThickness;
          double xzPositivePlane = (1 - (x / xStretch) - (z / zStretch)) * inverseThickness;
          double xzNegativePlane = (1 + (x / xStretch) - (z / zStretch)) * inverseThickness;

          // Positive Positive Plane
          if (x >= 0 && z >= 0 && Math.round(xzPositivePlane) == Math.round(yTest)) {
            fieldBlocks.add(new Vector3(x, y, z).add(translation));
            fieldBlocks.add(new Vector3(x, y, -z).add(translation));
          }

          // Negative Positive Plane
          if (x <= 0 && z >= 0 && Math.round(xzNegativePlane) == Math.round(yTest)) {
            fieldBlocks.add(new Vector3(x, y, -z).add(translation));
            fieldBlocks.add(new Vector3(x, y, z).add(translation));
          }

          // Ground Level Plane
          if (y == 0 && (Math.abs(x) + Math.abs(z)) < (xStretch + yStretch) / 2) {
            fieldBlocks.add(new Vector3(x, y, z).add(translation));
          }
        }
      }
    }

    return fieldBlocks;
  }
  @Override
  public boolean isInField(IFieldInteraction projector, Vector3 position) {
    Vector3 posScale = projector.getPositiveScale().clone();
    Vector3 negScale = projector.getNegativeScale().clone();

    int xStretch = posScale.intX() + negScale.intX();
    int yStretch = posScale.intY() + negScale.intY();
    int zStretch = posScale.intZ() + negScale.intZ();

    Vector3 projectorPos = new Vector3((TileEntity) projector);
    projectorPos.add(projector.getTranslation());
    projectorPos.add(new Vector3(0, -negScale.intY() + 1, 0));

    Vector3 relativePosition = position.clone().subtract(projectorPos);
    relativePosition.rotate(-projector.getRotationYaw(), -projector.getRotationPitch());

    Cuboid region = new Cuboid(negScale.scale(-1), posScale);

    if (region.isIn(relativePosition) && relativePosition.y > 0) {
      if ((1 - (Math.abs(relativePosition.x) / xStretch) - (Math.abs(relativePosition.z) / zStretch)
          > relativePosition.y / yStretch)) {
        return true;
      }
    }

    return false;
  }
  @Override
  public void update() {
    if (ticks % 60 == 0) {
      updateBounds();
    }

    super.update();

    pushDelay = Math.max(0, pushDelay - 1);

    /** Try to use temp link vectors from save/loads to link. */
    if (saveLinkVector != null) {
      tryLink(saveLinkVector, saveLinkSide);
      saveLinkVector = null;
    }

    if (canFunction()) {
      IInventory inventory = (IInventory) getLatched();

      /** Place items or take items from the inventory into the world. */
      if (!input) {
        renderRotation = Math.min(20, renderRotation + 0.8f);

        /** Attempt to push items out. */
        if (pushDelay == 0) {
          ItemStack retrieved =
              InventoryUtility.takeTopItemFromInventory(
                  inventory, placementSide.getOpposite().getOpposite().ordinal());

          if (retrieved != null) {
            EntityItem entityItem = getItemWithPosition(retrieved);

            if (!world().isRemote) {
              world().spawnEntityInWorld(entityItem);
            }

            pushDelay = Settings.LEVITATOR_PUSH_DELAY;
          }
        }
      } else if (input) {
        renderRotation = Math.max(0, renderRotation - 0.8f);
      }

      final int renderPeriod = 1;
      final boolean renderBeam = ticks % renderPeriod == 0 && hasLink() && getLink().input != input;

      if (!input) {
        if (hasLink()) {
          if (getLink().input) {
            /** Linked usage. */
            if (thread != null) {
              PathfinderLevitator newPath = thread.getPath();

              if (newPath != null) {
                pathfinder = newPath;
                pathfinder.results.add(getPosition());
                thread = null;
              }
            }

            // Push entity along path.
            if (pathfinder != null) {
              List<Vector3> results = pathfinder.results;

              /** Draw default beams. */
              if (renderBeam) {
                Electrical.proxy.renderElectricShock(
                    world(),
                    getBeamSpawnPosition(),
                    getPosition().translate(0.5),
                    EnumColor.DYES[dyeID].toColor(),
                    world().rand.nextFloat() > 0.9);
                Electrical.proxy.renderElectricShock(
                    world(),
                    getLink().getPosition().translate(0.5),
                    getLink().getBeamSpawnPosition(),
                    EnumColor.DYES[dyeID].toColor(),
                    world().rand.nextFloat() > 0.9);
              }

              for (int i = 0; i < results.size(); i++) {
                Vector3 result = results.get(i).clone();

                if (canBeMovePath(world(), result)) {
                  if (i - 1 >= 0) {
                    Vector3 prevResult = results.get(i - 1).clone();

                    Vector3 difference = prevResult.clone().difference(result);
                    final ForgeDirection direction = difference.toForgeDirection();

                    if (renderBeam) {
                      Electrical.proxy.renderElectricShock(
                          world(),
                          prevResult.clone().translate(0.5),
                          result.clone().translate(0.5),
                          EnumColor.DYES[dyeID].toColor(),
                          world().rand.nextFloat() > 0.9);
                    }

                    AxisAlignedBB bounds =
                        AxisAlignedBB.getAABBPool()
                            .getAABB(
                                result.x,
                                result.y,
                                result.z,
                                result.x + 1,
                                result.y + 1,
                                result.z + 1);
                    List<EntityItem> entities =
                        world().getEntitiesWithinAABB(EntityItem.class, bounds);

                    for (EntityItem entityItem : entities) {
                      moveEntity(entityItem, direction, result);
                    }
                  }

                } else {
                  updatePath();
                  break;
                }
              }
            } else {
              updatePath();
            }
          }
        } else if (operationBounds != null) {
          /** Non-linked usage. */
          for (EntityItem entityItem :
              (List<EntityItem>) world().getEntitiesWithinAABB(EntityItem.class, operationBounds)) {
            moveEntity(entityItem, placementSide.getOpposite(), getPosition());
          }

          if (ticks % renderPeriod == 0) {
            Electrical.proxy.renderElectricShock(
                world(),
                getBeamSpawnPosition(),
                new Vector3(
                    operationBounds.maxX - 0.5 - placementSide.offsetX / 3f,
                    operationBounds.maxY - 0.5 - placementSide.offsetY / 3f,
                    operationBounds.maxZ - 0.5 - placementSide.offsetZ / 3f),
                EnumColor.DYES[dyeID].toColor(),
                world().rand.nextFloat() > 0.9);
          }
        }
      }

      lastCalcTime--;
    }
  }