make a new function called timewallexsrap this is an exstraption version that uses logic like this // New reward cutoff logic
float goalY = RLConst::SOCCAR_GOAL_SCORE_BASE_THRESHOLD_Y * (player.team == Team::BLUE ? 1 : -1);
float distToGoalY = std::abs(ball.pos.y - goalY);
float extrapScoreTime = distToGoalY / std::max(std::abs(ball.vel.y), 0.01f);
Vec extrapScorePos = ball.pos + ball.vel * extrapScoreTime;
extrapScorePos.z += CommonValues::GRAVITY_Z * (extrapScoreTime * extrapScoreTime) / 2;
if (extrapScoreTime <= MIN_SCORE_TIME || extrapScorePos.z >= MAX_EXTRAP_Z) {
                reward = 0.0f; // Disable reward if the ball is about to score or go too high
} but just for the car and the walls the nwhen its done finding the closest wall it then renders  to rlbot a line from the car too the point on the wall the exstraption logic thinks is the spot the player is landing on     if (!renderTimeToReachBallEnabled || !ballPredTracker) return;
    rlbot::ScopedRenderer renderer("time_to_reach_renderer");

    constexpr float PREDICTION_DURATION = 6.0f;
    constexpr int NUM_PREDICTION_POINTS = 8;

    // 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);
    int numTicks = static_cast<int>(PREDICTION_DURATION * 120);
    ballPredTracker->UpdatePredManual(currentBallState, numTicks);

    const auto& ballPredData = ballPredTracker->predData;
    size_t predictionInterval = ballPredData.size() / NUM_PREDICTION_POINTS;

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

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

    for (size_t j = 0; j < NUM_PREDICTION_POINTS; ++j) {
        size_t index = j * predictionInterval;
        if (index >= ballPredData.size()) break;

        Vec ballPos(ballPredData[index].pos.x, ballPredData[index].pos.y, ballPredData[index].pos.z);
        localTimeToReach[j] = calculateTimeToReach(gs, ballPos);

        if (opponent) {
            RLGSC::GameState opponentGs = gs;
            opponentGs.players[this->index] = *opponent;
            opponentTimeToReach[j] = calculateTimeToReach(opponentGs, ballPos);
            if (localTimeToReach[j] < opponentTimeToReach[j]) {
                localPossession += 1.0f;
            }
            else {
                opponentPossession += 1.0f;
            }
        }
        else {
            localPossession += 1.0f;
        }
    }

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

    // Define Rocket League colors
    rlbot::Color rocketLeagueBlue{ 0, 153, 255, 255 };
    rlbot::Color rocketLeagueOrange{ 235, 141, 31, 255 };

    // Determine the dominant team and color
    bool isLocalDominant = localPossession >= opponentPossession;
    rlbot::Color dominantColor = isLocalDominant ?
        (gs.players[this->index].team == Team::BLUE ? rocketLeagueBlue : rocketLeagueOrange) :
        (gs.players[this->index].team == Team::BLUE ? rocketLeagueOrange : rocketLeagueBlue);

    // Get the position of the car with the best possession
    rlbot::flat::Vector3 bestCarPos;
    if (isLocalDominant) {
        bestCarPos = {
            static_cast<float>(gs.players[this->index].phys.pos.x),
            static_cast<float>(gs.players[this->index].phys.pos.y),
            static_cast<float>(gs.players[this->index].phys.pos.z)
        };
    }
    else if (opponent) {
        bestCarPos = {
            static_cast<float>(opponent->phys.pos.x),
            static_cast<float>(opponent->phys.pos.y),
            static_cast<float>(opponent->phys.pos.z)
        };
    }

    // Render the single line from the best car to the ball
    rlbot::flat::Vector3 ballPos = {
        static_cast<float>(gs.ball.pos.x),
        static_cast<float>(gs.ball.pos.y),
        static_cast<float>(gs.ball.pos.z)
    };
    renderer.DrawLine3D(dominantColor, bestCarPos, ballPos);

    // Render time to ball inside the ball
    float timeToReach = isLocalDominant ? localTimeToReach[0] : opponentTimeToReach[0];
    std::stringstream timeSS;
    timeSS << std::fixed << std::setprecision(2) << timeToReach << "s";
    renderer.DrawString3D(timeSS.str(), dominantColor, ballPos, 1.0f, 1.0f);

    // Render possession information
    std::stringstream localSS;
    localSS << (gs.players[this->index].team == Team::BLUE ? "Blue" : "Orange") << " possession: "
        << std::fixed << std::setprecision(2) << localPossession * 100 << "%";
    renderer.DrawString2D(localSS.str(), gs.players[this->index].team == Team::BLUE ? rocketLeagueBlue : rocketLeagueOrange,
        rlbot::flat::Vector3{ 10, 10, 0 }, 2.0f, 2.0f);

    if (opponent) {
        std::stringstream opponentSS;
        opponentSS << (gs.players[this->index].team == Team::BLUE ? "Orange" : "Blue") << " possession: "
            << std::fixed << std::setprecision(2) << opponentPossession * 100 << "%";
        renderer.DrawString2D(opponentSS.str(), gs.players[this->index].team == Team::BLUE ? rocketLeagueOrange : rocketLeagueBlue,
            rlbot::flat::Vector3{ 10, 40, 0 }, 2.0f, 2.0f);
    }

    // Render overall possession summary
    std::stringstream summaryStream;
    summaryStream << "Dominant team: " << (isLocalDominant ?
        (gs.players[this->index].team == Team::BLUE ? "Blue" : "Orange") :
        (gs.players[this->index].team == Team::BLUE ? "Orange" : "Blue"));
    renderer.DrawString2D(summaryStream.str(), dominantColor, rlbot::flat::Vector3{ 10, 70, 0 }, 2.0f, 2.0f);
}

#include <algorithm>


float RLBotBot::TimeToGround(const RLGSC::GameState & gs) {
    constexpr float GRAVITY = -650.0f; // Gravity in Rocket League (uu/s^2)
    constexpr float GROUND_Z = 17.01f; // Approximate ground level for cars

    const auto& player = gs.players[this->index];
    float z = player.phys.pos.z;
    float vz = player.phys.vel.z;

    // If the car is already on the ground, return 0
    if (z <= GROUND_Z) {
        return 0.0f;
    }

    // Calculate time to ground using quadratic formula
    // z = z0 + v0*t + 0.5*a*t^2
    // 0 = (z0 - GROUND_Z) + v0*t + 0.5*a*t^2
    float a = 0.5f * GRAVITY;
    float b = vz;
    float c = z - GROUND_Z;

    float discriminant = b * b - 4 * a * c;

    // If discriminant is negative, use a linear approximation
    if (discriminant < 0) {
        // This shouldn't happen in normal gameplay, but let's approximate
        return (z - GROUND_Z) / -vz; // Simple linear approximation
    }

    float sqrtDiscriminant = std::sqrt(discriminant);
    float t1 = (-b + sqrtDiscriminant) / (2 * a);
    float t2 = (-b - sqrtDiscriminant) / (2 * a);

    // Return the positive time that's closest to zero
    if (t1 >= 0 && t2 >= 0) {
        return RS_MIN(t1, t2);
    }
    else if (t1 >= 0) {
        return t1;
    }
    else if (t2 >= 0) {
        return t2;
    }
    else {
        // This shouldn't happen, but just in case, return a small positive value
        return 0.001f;
    }
}


float calculateAirTime(float curDist, float curVel, bool hasBoost, bool hasFlip) {
    float t = 0;
    bool hasFlipped = false;

    while (curDist > 0) {
        if (curVel < MAX_TOTAL_SPEED && t == 0 && hasFlip) {
            // Flip force
            curVel += FLIP_FORCE;
            hasFlipped = true;
        }

        if (curVel < MAX_TOTAL_SPEED) {
            // Apply air acceleration
            float accel = AIR_ACCEL;
            if (hasBoost) {
                accel += BOOST_ACCEL_AIR;
            }
            curVel += accel * STEP_INTERVAL;
        }

        curVel = RS_MIN(curVel, MAX_TOTAL_SPEED);
        float distTraveled = curVel * STEP_INTERVAL;
        curDist -= distTraveled;
        t += STEP_INTERVAL;

        if (curDist <= 0) {
            // Adjust for overshooting
            t -= STEP_INTERVAL;
            t += curDist / curVel;
            break;
        }
    }

    return t;
}

float RLBotBot::TimeToClosestWallAir(const RLGSC::GameState& gs) {
    constexpr float STEP_INTERVAL = 1.0f / 120.0f; // Assuming 120 ticks per second

    // Get the player's position and velocity
    const auto& player = gs.players[this->index];
    float x = player.phys.pos.x;
    float y = player.phys.pos.y;
    float vx = player.phys.vel.x;
    float vy = player.phys.vel.y;

    // Calculate distances to walls
    float dist_side_wall = 4096.0f - std::abs(x);
    float dist_back_wall = 5120.0f - std::abs(y);

    // Calculate distance to corner
    float x1 = 4096.0f - 1152.0f, y1 = 5120.0f, x2 = 4096.0f, y2 = 5120.0f - 1152.0f;
    float A = std::abs(x) - x1;
    float B = std::abs(y) - y1;
    float C = x2 - x1;
    float D = y2 - y1;
    float dot = A * C + B * D;
    float len_sq = C * C + D * D;
    float param = (len_sq != 0) ? dot / len_sq : -1;
    float xx = (param < 0) ? x1 : (param > 1) ? x2 : x1 + param * C;
    float yy = (param < 0) ? y1 : (param > 1) ? y2 : y1 + param * D;
    float dx = std::abs(x) - xx;
    float dy = std::abs(y) - yy;
    float dist_corner = std::sqrt(dx * dx + dy * dy);

    // Calculate initial velocities towards walls
    float vel_side_wall = std::abs(vx);
    float vel_back_wall = std::abs(vy);
    float vel_corner = (dx * vx + dy * vy) / std::sqrt(dx * dx + dy * dy);

    // Determine if the car has boost and flip available
    bool hasBoost = true;
    bool hasFlip = player.carState.HasFlipOrJump();

    // Calculate air times to each wall
    float time_side_wall = calculateAirTime(dist_side_wall, vel_side_wall, hasBoost, hasFlip);
    float time_back_wall = calculateAirTime(dist_back_wall, vel_back_wall, hasBoost, hasFlip);
    float time_corner = calculateAirTime(dist_corner, vel_corner, hasBoost, hasFlip);

    // Return the minimum time to the closest wall
    return RS_MIN(RS_MIN(time_side_wall, time_back_wall), time_corner);
}

/*