public static double getTimeToHit(
      double bulletSpeed, Vector3f playerPos, Vector3f enemyPos, Vector3f enemyPredictedPos) {

    double d = CommFun.getDistanceBetweenPositions(playerPos, enemyPos);
    double v = bulletSpeed;
    double u = CommFun.getDistanceBetweenPositions(enemyPos, enemyPredictedPos);

    Vector3f vec1 = CommFun.getNormalizedDirectionVector(playerPos, enemyPos);
    Vector3f vec2 = CommFun.getNormalizedDirectionVector(enemyPos, enemyPredictedPos);

    double alpha = Math.toRadians(vec1.angle(vec2));

    double delta =
        4 * d * d * u * u * Math.cos(alpha) * Math.cos(alpha) + 4 * (v * v - u * u) * d * d;

    double t = (2 * d * u * Math.cos(alpha) + Math.sqrt(delta)) / (2 * (v * v - u * u));

    double t2 = (2 * d * u * Math.cos(alpha) - Math.sqrt(delta)) / (2 * (v * v - u * u));

    //                System.out.println("t="+t+" v="+v+" d="+d+" u="+u+" t2="+t2);

    if (Double.isNaN(t)) {
      t = 1;
    }

    return t;
  }
  public static FiringInstructions getNewPredictingFiringInstructions(
      MapBotBase bot, FiringDecision fd, float bulletSpeed) {
    Vector3f playerPos = bot.getBotPosition();
    Vector3f enemyPos = fd.enemyInfo.getBestVisibleEnemyPart(bot);

    // Calculate the time to hit
    double timeToHit = getTimeToHit(bulletSpeed, playerPos, enemyPos, fd.enemyInfo.predictedPos);
    if (timeToHit <= 1.5) {
      timeToHit = 1f;
    }

    // We add to enemy position the movement that the enemy is predicted to do in timeToHit.
    Vector3f hitPoint = CommFun.cloneVector(enemyPos);
    // movement is between bot position, not the visible part of the bot
    Vector3f movement =
        CommFun.getMovementBetweenVectors(
            fd.enemyInfo.getObjectPosition(), fd.enemyInfo.predictedPos);
    movement = CommFun.multiplyVectorByScalar(movement, (float) timeToHit);
    hitPoint.add(movement);

    return new FiringInstructions(CommFun.getNormalizedDirectionVector(playerPos, hitPoint));
  }