void RLBotBot::RenderGlobalBallPred(const RLGSC::GameState& gs) {
    if (!renderBallPredictionsEnabled) return;

    rlbot::ScopedRenderer renderer("global_ballpred_renderer");

    const Arena* arena = predictionArena;
    if (!arena) return;

    BallPred& ballPred = BallPred::getInstance();
    ballPred.Update(arena);  // Update prediction for the current arena

    // Time intervals and precision settings for refinement
    constexpr float INITIAL_INTERVAL = 0.5f;  // Start with 0.5s interval
    constexpr float MIN_INTERVAL = 0.01f;  // Minimum interval (1ms)
    constexpr int MAX_STEPS = 6;  // Max refinement steps (0.5s -> 0.25s -> 0.125s, etc.)
    constexpr float MAX_PRED_TIME = 2.0f;  // Total prediction time (2 seconds)

    std::vector<rlbot::flat::Vector3> points;
    float currentTime = 0.0f;

    // Start with the initial interval
    for (float interval = INITIAL_INTERVAL; interval >= MIN_INTERVAL; interval /= 2.0f) {
        // Refine the time intervals with each step
        for (int step = 0; step <= MAX_STEPS; step++) {
            if (currentTime > MAX_PRED_TIME) break;

            PhysObj ballState = ballPred.GetAtTime(currentTime);  // Get ball state at current time
            points.push_back(rlbot::flat::Vector3{
                static_cast<float>(ballState.pos.x),
                static_cast<float>(ballState.pos.y),
                static_cast<float>(ballState.pos.z)
                });

            currentTime += interval;  // Move to the next refined time
        }
    }

    // Render lines between consecutive points
    for (size_t i = 0; i < points.size() - 1; i++) {
        renderer.DrawLine3D(rlbot::Color::yellow, points[i], points[i + 1]);
    }

    // Draw a green dot at the last predicted point
    if (!points.empty()) {
        renderer.DrawRect3D(
            rlbot::Color::green,
            points.back(),
            10,
            10,
            true,
            true
        );
    }
} class TimeToReachCalculatorv2 {
public:
    static float calculateTimeToReach(const PlayerData& player, const Vec& targetPos) {
        const auto& car = player;
        Vec carPos = car.phys.pos;
        Vec carVel = car.phys.vel;
        Vec toTargetVec = targetPos - carPos;
        Vec dirToTarget = toTargetVec.Normalized();
        float dist = toTargetVec.Length() - CommonValues::BALL_RADIUS;
        float vel = carVel.Dot(dirToTarget);
        float rotTime = calculateRotationTime(player, targetPos);
        float timeToSurface = calculateTimeToReachAnySurface(car);

        // Estimate time to reach the target using only aerial acceleration
        float estimatedAerialTime = 0.0f;
        float estDist = dist;
        float estVel = vel;
        const float MAX_AERIAL_ACCEL = AIR_ACCEL + BOOST_ACCEL_AIR;

        // Simulation parameters to prevent infinite loops
        const float MAX_SIMULATION_TIME = 10.0f; // seconds
        const int MAX_ITERATIONS = static_cast<int>(MAX_SIMULATION_TIME / STEP_INTERVAL);
        int iteration = 0;

        // Simulate time to reach the target using aerial acceleration
        while (estDist > DIST_REACH_THRESH && iteration < MAX_ITERATIONS) {
            // Apply maximum aerial acceleration
            estVel += MAX_AERIAL_ACCEL * STEP_INTERVAL;
            if (estVel > MAX_TOTAL_SPEED) {
                estVel = MAX_TOTAL_SPEED;
            }

            // Update the remaining distance
            estDist -= estVel * STEP_INTERVAL;

            // Increment the estimated time
            estimatedAerialTime += STEP_INTERVAL;
            iteration++;
        }

        // Determine whether to use aerial acceleration throughout
        bool useAerial = estimatedAerialTime < timeToSurface;
        //RG_LOG(useAerial);
        float t = 0.0f;
        float curDist = dist;
        float curVel = vel;
        iteration = 0;

        for (; curDist > DIST_REACH_THRESH && t < MAX_SIMULATION_TIME; t += STEP_INTERVAL, curDist -= curVel * STEP_INTERVAL, iteration++) {
            bool hasRotated = t >= rotTime;

            // Initial Flip Force
            if (curVel < MAX_TOTAL_SPEED && t == 0.0f) {
                curVel += FLIP_FORCE;
                if (curVel > MAX_TOTAL_SPEED) {
                    curVel = MAX_TOTAL_SPEED;
                }
            }

            if (useAerial) {
                // Apply Aerial-Based Acceleration
                if (curVel < MAX_DRIVE_SPEED) {
                    // Driving in air
                    curVel += (AIR_ACCEL + BOOST_ACCEL_AIR * hasRotated) * STEP_INTERVAL;
                }
                else if (curVel < MAX_TOTAL_SPEED) {
                    // Boosting in air
                    curVel += BOOST_ACCEL_AIR * STEP_INTERVAL;
                }
            }
            else {
                // Apply Ground-Based Acceleration
                if (curVel < 0.0f) {
                    // Braking on ground
                    curVel += (BRAKE_ACCEL + BOOST_ACCEL_GROUND * hasRotated) * STEP_INTERVAL;
                }
                else if (curVel < MAX_DRIVE_SPEED) {
                    // Driving on ground
                    curVel += (DRIVE_ACCEL + BOOST_ACCEL_GROUND * hasRotated) * STEP_INTERVAL;
                }
                else if (curVel < MAX_TOTAL_SPEED) {
                    // Boosting on ground
                    curVel += (BOOST_ACCEL_GROUND + (hasRotated ? BOOST_ACCEL_GROUND * STEP_INTERVAL : 0.0f));
                }
            }

            // Cap Velocity at MAX_TOTAL_SPEED
            if (curVel >= MAX_TOTAL_SPEED) {
                float remainingDist = curDist;
                float additionalTime = remainingDist / curVel;
                return t + additionalTime;
            }

            // Prevent negative velocity (optional safeguard)
            if (curVel < 0.0f) {
                curVel = 0.0f;
            }
        }

        return t;
    }

private:
    // Constants
    static constexpr float SIDE_WALL_X = 4096.0f;
    static constexpr float CLOSE_DISTANCE = 10.0f;
    static constexpr float NEAR_WALL_DISTANCE = 4077.0f;
    static constexpr float Z_THRESHOLD = 256.0f;
    static constexpr float EPSILON = 1e-3f;
    static constexpr float DIST_REACH_THRESH = 80.0f;
    static constexpr float STEP_INTERVAL = 1.0f / 60.0f;
    static constexpr float FLIP_FORCE = 495.0f;
    static constexpr float AIR_ACCEL = 133.334f;
    static constexpr float BOOST_ACCEL_AIR = 2116.666f;
    static constexpr float MAX_TOTAL_SPEED = 2300.0f;
    static constexpr float BRAKE_ACCEL = 3500.0f;
    static constexpr float BOOST_ACCEL_GROUND = 1983.332f;
    static constexpr float DRIVE_ACCEL = 1600.0f;
    static constexpr float MAX_DRIVE_SPEED = 1410.0f;
    static constexpr float GRAVITY_Z = -650.0f;
    static constexpr float BACK_WALL_Y = 5120.0f;
    static constexpr float NEG_BACK_WALL_Y = -5120.0f;
    static constexpr float MAX_BACKWALL_Y = 5100.0f;
    static constexpr float BOOST_ACCEL_POS = 1000.0f;
    static constexpr float BOOST_ACCEL_NEG = -1000.0f;
    static constexpr float FLOOR_Z = 18.0f;
    static constexpr float BOOST_ACCEL_DOWN = -1000.0f;
    static constexpr float MAX_TIME = 10.0f;
    static constexpr float JUMP_IMPULSE = 291.667f;
    static constexpr float GROUND_Z_THRESHOLD = 50.0f;
    static constexpr float MAX_SIMULATION_TIME = 10.0f;


    static float calculateTimeToReachAir(const PlayerData& player, const Vec& targetPos) {
        Vec carPos = player.phys.pos;
        Vec carVel = player.phys.vel;
        Vec dirToTarget = (targetPos - carPos).Normalized();
        float dist = (targetPos - carPos).Length() - CommonValues::BALL_RADIUS;
        float vel = carVel.Dot(dirToTarget);
        float rotTime = calculateRotationTime(player, targetPos);

        float t = 0;
        for (float curDist = dist, curVel = vel; curDist > DIST_REACH_THRESH; t += STEP_INTERVAL, curDist -= curVel * STEP_INTERVAL) {
            bool hasRotated = t >= rotTime;

            if (curVel < MAX_TOTAL_SPEED && t == 0) {
                // Initial jump/dodge impulse
                curVel += JUMP_IMPULSE;
            }

            // Apply air acceleration and boost
            float accel = AIR_ACCEL + (hasRotated ? BOOST_ACCEL_AIR : 0);
            curVel += accel * STEP_INTERVAL;

            // Apply gravity (project it onto the direction to target)
            float gravityComponent = GRAVITY_Z * dirToTarget.z;
            curVel += gravityComponent * STEP_INTERVAL;

            if (curVel >= MAX_TOTAL_SPEED) {
                return t + (curDist / curVel);
            }
        }

        return t;
    }

    static float calculateTimeToSideWalls(const PlayerData& player) {
        const Vec& pos = player.phys.pos;
        const Vec& vel = player.phys.vel;

        float minTime = std::numeric_limits<float>::infinity();

        if (std::abs(pos.x) >= NEAR_WALL_DISTANCE && std::abs(pos.x) <= SIDE_WALL_X) {
            return 0.0f;
        }

        if (vel.x > EPSILON) {
            float a = 0.5f * DRIVE_ACCEL;
            float b = vel.x;
            float c = pos.x - SIDE_WALL_X;

            float discriminant = b * b - 4.0f * a * c;

            if (discriminant >= 0.0f) {
                float sqrtD = std::sqrt(discriminant);
                float t1 = (-b + sqrtD) / (2.0f * a);
                float t2 = (-b - sqrtD) / (2.0f * a);

                if (t1 > EPSILON && t1 < minTime) {
                    minTime = t1;
                }
                if (t2 > EPSILON && t2 < minTime) {
                    minTime = t2;
                }
            }
        }

        if (vel.x < -EPSILON) {
            float a = 0.5f * (-DRIVE_ACCEL);
            float b = vel.x;
            float c = pos.x + SIDE_WALL_X;

            float discriminant = b * b - 4.0f * a * c;

            if (discriminant >= 0.0f) {
                float sqrtD = std::sqrt(discriminant);
                float t1 = (-b + sqrtD) / (2.0f * a);
                float t2 = (-b - sqrtD) / (2.0f * a);

                if (t1 > EPSILON && t1 < minTime) {
                    minTime = t1;
                }
                if (t2 > EPSILON && t2 < minTime) {
                    minTime = t2;
                }
            }
        }

        return minTime;
    }

    static float calculateTimeToBackWalls(const PlayerData& player) {
        const Vec& pos = player.phys.pos;
        const Vec& vel = player.phys.vel;

        float minTime = std::numeric_limits<float>::infinity();

        if (pos.y >= MAX_BACKWALL_Y || pos.y <= -MAX_BACKWALL_Y) {
            return 0.0f;
        }

        if (pos.y >= BACK_WALL_Y || pos.y <= NEG_BACK_WALL_Y) {
            return 0.0f;
        }

        if (vel.y > EPSILON) {
            float a = 0.5f * BOOST_ACCEL_POS;
            float b = vel.y;
            float c = pos.y - BACK_WALL_Y;

            float discriminant = b * b - 4.0f * a * c;

            if (discriminant >= 0.0f) {
                float sqrtD = std::sqrt(discriminant);
                float t1 = (-b + sqrtD) / (2.0f * a);
                float t2 = (-b - sqrtD) / (2.0f * a);

                if (t1 > EPSILON && t1 < minTime) {
                    minTime = t1;
                }
                if (t2 > EPSILON && t2 < minTime) {
                    minTime = t2;
                }
            }
        }

        if (vel.y < -EPSILON) {
            float a = 0.5f * BOOST_ACCEL_NEG;
            float b = vel.y;
            float c = pos.y - NEG_BACK_WALL_Y;

            float discriminant = b * b - 4.0f * a * c;

            if (discriminant >= 0.0f) {
                float sqrtD = std::sqrt(discriminant);
                float t1 = (-b + sqrtD) / (2.0f * a);
                float t2 = (-b - sqrtD) / (2.0f * a);

                if (t1 > EPSILON && t1 < minTime) {
                    minTime = t1;
                }
                if (t2 > EPSILON && t2 < minTime) {
                    minTime = t2;
                }
            }
        }

        return minTime;
    }

    static float calculateTimeToFloor(const PlayerData& player) {
        const Vec& pos = player.phys.pos;
        const Vec& vel = player.phys.vel;

        if (pos.z <= FLOOR_Z) {
            return 0.0f;
        }

        float totalAccel = GRAVITY_Z + BOOST_ACCEL_DOWN;

        float a = 0.5f * totalAccel;
        float b = vel.z;
        float c = pos.z - FLOOR_Z;

        float discriminant = b * b - 4.0f * a * c;

        if (discriminant < 0.0f) {
            return std::numeric_limits<float>::infinity();
        }

        float sqrtD = std::sqrt(discriminant);
        float t1 = (-b - sqrtD) / (2.0f * a);
        float t2 = (-b + sqrtD) / (2.0f * a);

        float timeToFloor = std::numeric_limits<float>::infinity();

        if (t1 > 0.0f) {
            timeToFloor = t1;
        }
        if (t2 > 0.0f && t2 < timeToFloor) {
            timeToFloor = t2;
        }

        return timeToFloor;
    }

    

    static float calculateTimeToReachAnySurface(const PlayerData& player) {
        // Calculate individual times to each surface
        float timeToSideWalls = calculateTimeToSideWalls(player);
        // RG_LOG(timeToSideWalls); // Uncomment if logging is needed

        float timeToBackWalls = calculateTimeToBackWalls(player);
        //RG_LOG(timeToBackWalls); // Uncomment if logging is needed

        float timeToFloor = calculateTimeToFloor(player);
        // RG_LOG(timeToFloor); // Uncomment if logging is needed

        // Assign identifier variables for clarity
        float minTimeBetweenBackWallsAndFloor = RS_MIN(timeToBackWalls, timeToFloor);

        // Now find the minimum time among side walls and the previously computed minimum
        float minTime = RS_MIN(timeToSideWalls, minTimeBetweenBackWallsAndFloor);

        return minTime;
    }

    static float calculateRotationTime(const PlayerData& player, const Vec& targetPos) {
        constexpr float MAX_ANG_VEL = 5.5f * 0.9f;

        Vec playerPos = player.phys.pos;
        Vec playerForward = player.phys.rotMat.forward;
        Vec dirToTarget = (targetPos - playerPos).Normalized();
        float dotProduct = RS_CLAMP(playerForward.Dot(dirToTarget), -1.0f, 1.0f);
        float angleDiff = std::acos(dotProduct);

        return angleDiff / MAX_ANG_VEL;
    }
};you should specify the interval
not the amount of prediction points
you should find the closest reach margin with like 0.5s interval
then check neighboring times at 0.25s
then at 0.125s
etc
until you find the best tick
like a trinary search