void RLBotBot::RenderTimeToReachBall(const RLGSC::GameState& gs) {
    if (!renderTimeToReachBallEnabled || !ballPredTracker) return;
    rlbot::ScopedRenderer renderer("time_to_reach_renderer");

    auto calculateMinAirTime = [](const Vec& playerPos, const Vec& playerVel, bool hasFlip) {
        constexpr float GRAVITY = 650.0f;
        float timeToGround = RS_MAX(0.0f, (-playerVel.z + std::sqrt(playerVel.z * playerVel.z + 2 * GRAVITY * playerPos.z)) / GRAVITY);
        float timeToSideWall = (playerVel.x != 0.0f) ? RS_MIN(
            std::abs((CommonValues::SIDE_WALL_X - playerPos.x) / playerVel.x),
            std::abs((-CommonValues::SIDE_WALL_X - playerPos.x) / playerVel.x)
        ) : std::numeric_limits<float>::infinity();
        float timeToBackWall = (playerVel.y != 0.0f) ? RS_MIN(
            std::abs((CommonValues::BACK_WALL_Y - playerPos.y) / playerVel.y),
            std::abs((-CommonValues::BACK_WALL_Y - playerPos.y) / playerVel.y)
        ) : std::numeric_limits<float>::infinity();
        float timeToCeiling = (playerVel.z > 0.0f) ? (CommonValues::CEILING_Z - playerPos.z) / playerVel.z : std::numeric_limits<float>::infinity();
        return RS_MIN(RS_MIN(timeToGround, timeToSideWall), RS_MIN(timeToBackWall, timeToCeiling));
        };

    auto getTimeToReachBall = [&calculateMinAirTime](const PlayerData& player, const Vec& ballPos) {
        constexpr float MAX_ROTATION_SPEED = 5.5f;
        constexpr float DIST_REACH_THRESH = 10.0f;
        constexpr float STEP_INTERVAL = 1.0f / 60.0f;
        constexpr float FLIP_FORCE = 500.0f;
        constexpr float AIR_ACCEL = 66.66667f;
        constexpr float BOOST_ACCEL_AIR = 1058.33333f;
        constexpr float MAX_TOTAL_SPEED = 2300.0f;
        constexpr float BRAKE_ACCEL = 3500.0f;
        constexpr float BOOST_ACCEL_GROUND = 991.66667f;
        constexpr float DRIVE_ACCEL = 1600.0f;
        constexpr float MAX_DRIVE_SPEED = 1410.0f;

        const Vec& playerPos = player.phys.pos;
        const Vec& playerForward = player.phys.rotMat.forward;
        const Vec& playerVel = player.phys.vel;
        bool hasFlip = player.carState.HasFlipOrJump();
        float dist = (ballPos - playerPos).Length();
        Vec dirToBall = ballPos - playerPos;
        Vec normalizedDirToBall = dirToBall.Normalized();
        float curVel = playerVel.Dot(normalizedDirToBall);
        float angleDiff = std::acos(RS_CLAMP(playerForward.Dot(normalizedDirToBall), -1.0f, 1.0f));
        float rotTime = angleDiff / MAX_ROTATION_SPEED;
        float t = 0.0f;
        float curDist = dist;

        float minAirTime = calculateMinAirTime(playerPos, playerVel, hasFlip);

        while (t < minAirTime && curDist > DIST_REACH_THRESH) {
            bool hasRotated = t >= rotTime;
            if (hasFlip && t == 0.0f) {
                curVel += FLIP_FORCE;
            }
            float airAccel = AIR_ACCEL + (BOOST_ACCEL_AIR * hasRotated);
            curVel += airAccel * STEP_INTERVAL;
            curVel = RS_MIN(curVel, MAX_TOTAL_SPEED);
            curDist -= curVel * STEP_INTERVAL;
            t += STEP_INTERVAL;
        }

        while (curDist > DIST_REACH_THRESH) {
            bool hasRotated = t >= rotTime;
            if (curVel < 0.0f) {
                curVel += (BRAKE_ACCEL + BOOST_ACCEL_GROUND * hasRotated) * STEP_INTERVAL;
            }
            else if (curVel < MAX_DRIVE_SPEED) {
                curVel += (DRIVE_ACCEL + BOOST_ACCEL_GROUND * hasRotated) * STEP_INTERVAL;
            }
            else if (curVel < MAX_TOTAL_SPEED) {
                curVel += BOOST_ACCEL_GROUND * hasRotated * STEP_INTERVAL;
            }
            else {
                float remainingTime = curDist / curVel;
                return t + remainingTime;
            }
            curVel = RS_MIN(curVel, MAX_TOTAL_SPEED);
            curDist -= curVel * STEP_INTERVAL;
            t += STEP_INTERVAL;
        }

        return t;
        };

    constexpr float PREDICTION_DURATION = 6.0f; // Predict 6 seconds into the future
    int numTicks = static_cast<int>(PREDICTION_DURATION * 120); // Assuming 120 ticks per second

    // Update ball prediction
    RocketSim::BallState currentBallState;
    currentBallState.pos = RocketSim::Vec(gs.ball.pos.x, gs.ball.pos.y, gs.ball.pos.z);
    currentBallState.vel = RocketSim::Vec(gs.ball.vel.x, gs.ball.vel.y, gs.ball.vel.z);
    currentBallState.angVel = RocketSim::Vec(gs.ball.angVel.x, gs.ball.angVel.y, gs.ball.angVel.z);
    currentBallState.rotMat = RocketSim::RotMat(gs.ball.rotMat.forward, gs.ball.rotMat.right, gs.ball.rotMat.up);
    ballPredTracker->UpdatePredManual(currentBallState, numTicks);

    // Find the opponent
    const PlayerData* opponent = nullptr;
    for (const auto& player : gs.players) {
        if (player.team != gs.players[index].team) {
            opponent = &player;
            break;
        }
    }

    if (!opponent) {
        // No opponent found, return early
        return;
    }

    int numPredsToAdd = 8;
    std::vector<float> localTimeToReach(numPredsToAdd);
    std::vector<float> opponentTimeToReach(numPredsToAdd);
    float localPossession = 0.0f;
    float opponentPossession = 0.0f;

    std::vector<rlbot::flat::Vector3> points;
    std::vector<const rlbot::flat::Vector3*> pointPointers;

    for (int i = 0; i < numPredsToAdd; i++) {
        float predTime = (numTicks / 120.f) * ((i + 1) / (float)numPredsToAdd);
        BallState ballState = ballPredTracker->GetBallStateForTime(predTime);

        Vec ballPos(ballState.pos.x, ballState.pos.y, ballState.pos.z);
        localTimeToReach[i] = getTimeToReachBall(gs.players[index], ballPos);
        opponentTimeToReach[i] = getTimeToReachBall(*opponent, ballPos);

        if (localTimeToReach[i] < opponentTimeToReach[i]) {
            localPossession += 1.0f;
        }
        else {
            opponentPossession += 1.0f;
        }

        points.push_back({
            static_cast<float>(ballState.pos.x),
            static_cast<float>(ballState.pos.y),
            static_cast<float>(ballState.pos.z)
            });
        pointPointers.push_back(&points.back());

        std::stringstream localSS, opponentSS;
        localSS << std::fixed << std::setprecision(2) << localTimeToReach[i] << "s";
        opponentSS << std::fixed << std::setprecision(2) << opponentTimeToReach[i] << "s";

        rlbot::flat::Vector3 localTextPos = {
            static_cast<float>(ballState.pos.x),
            static_cast<float>(ballState.pos.y),
            static_cast<float>(ballState.pos.z + 50.0f)
        };
        rlbot::flat::Vector3 opponentTextPos = {
            static_cast<float>(ballState.pos.x),
            static_cast<float>(ballState.pos.y),
            static_cast<float>(ballState.pos.z - 50.0f)
        };

        renderer.DrawString3D(localSS.str(), rlbot::Color::blue, localTextPos, 1.0f, 1.0f);
        renderer.DrawString3D(opponentSS.str(), rlbot::Color::white, opponentTextPos, 1.0f, 1.0f);
    }

    renderer.DrawPolyLine3D(rlbot::Color::yellow, pointPointers);

    float totalPossession = localPossession + opponentPossession;
    localPossession /= totalPossession;
    opponentPossession /= totalPossession;

    // Render possession information
    std::stringstream localSS, opponentSS;
    localSS << "Local player possession: " << std::fixed << std::setprecision(2) << localPossession * 100 << "%";
    opponentSS << "Opponent possession: " << std::fixed << std::setprecision(2) << opponentPossession * 100 << "%";

    renderer.DrawString2D(localSS.str(), rlbot::Color::blue, rlbot::flat::Vector3{ 10, 10, 0 }, 2.0f, 2.0f);
    renderer.DrawString2D(opponentSS.str(), rlbot::Color::white, rlbot::flat::Vector3{ 10, 40, 0 }, 2.0f, 2.0f);

    // Render overall possession summary
    std::stringstream summaryStream;
    summaryStream << "Team Possession - "
        << (gs.players[index].team == Team::BLUE ? "Blue: " : "Orange: ")
        << std::fixed << std::setprecision(2) << localPossession * 100 << "% | "
        << (gs.players[index].team == Team::BLUE ? "Orange: " : "Blue: ")
        << opponentPossession * 100 << "%";
    renderer.DrawString2D(summaryStream.str(), rlbot::Color::white, rlbot::flat::Vector3{ 10, 70, 0 }, 2.0f, 2.0f);
} this code seems too be abit wrong since the lines that are rendered that should only be form the cars too the prediction points can be from the gorund and random spots etc can you fix the logic and check over everything too make sure all the code is really doing what i want it todo