void RLBotBot::RenderGlobalBallPred(const RLGSC::GameState& gs) {
    if (!renderBallPredictionsEnabled) return;
    rlbot::ScopedRenderer renderer("global_ballpred_renderer");

    BallPredEnv* ballPredEnv = BallPred::GetOrMake(predictionArena);
    if (!ballPredEnv) return;

    BallPred::Update(predictionArena);

    constexpr float MAX_PRED_TIME = 2.0f;  // 6 seconds prediction
    constexpr float TIME_STEP = 1.0f / 60.0f;  // 60 fps
    constexpr int NUM_POINTS = static_cast<int>(MAX_PRED_TIME / TIME_STEP) + 1;

    std::vector<rlbot::flat::Vector3> points(NUM_POINTS);

    for (int i = 0; i < NUM_POINTS; i++) {
        float t = i * TIME_STEP;
        PhysObj ballState = ballPredEnv->GetAtTime(t, gs.ball);
        points[i] = rlbot::flat::Vector3{
            static_cast<float>(ballState.pos.x),
            static_cast<float>(ballState.pos.y),
            static_cast<float>(ballState.pos.z)
        };
    }

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

    // Draw a green dot at the end of the prediction line
    if (!points.empty()) {
        renderer.DrawRect3D(
            rlbot::Color::green,
            points.back(),
            10,
            10,
            true,
            true
        );
    }
} why does this work but this thinks balls x is 0 class sBP1 : public RewardFunction {
private:
	static constexpr float MAX_PRED_TIME = 2.0f;  // Maximum prediction time in seconds
	RocketSim::Arena* predictionArena;

public:
	sBP1(RocketSim::Arena* predictionArena) : predictionArena(predictionArena) {
		// Initialization if needed
	}

	float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) override {
		if (!predictionArena) {
			return 0.0f;  // No reward if arena is not available
		}

		BallPredEnv* ballPredEnv = BallPred::GetOrMake(predictionArena);
		if (!ballPredEnv) return 0.0f;

		if (!ballPredEnv) {
			RG_LOG("no ballPredEnv");
		}
		
		// **Uncomment the update call**
		BallPred::Update(predictionArena);

		// Get the predicted ball position at MAX_PRED_TIME
		PhysObj predictedBall = ballPredEnv->GetAtTime(MAX_PRED_TIME, state.ball);

		// Calculate distance between the player and the predicted ball position
		float distance = (player.phys.pos - predictedBall.pos).Length();

		// Check if the player is within 90 units of the predicted ball position
		if (distance <= 180.0f) {
			return 10.0f;  // High reward for being close to the prediction point
		}

		// If not within 90 units, calculate velocity towards the predicted ball position

		// Calculate the direction vector from player to predicted ball
		Vec directionToBall = (predictedBall.pos - player.phys.pos).Normalized();

		// Calculate the dot product of player's velocity and the direction to the predicted ball
		float velocityTowardsBall = player.phys.vel.Dot(directionToBall);

		// Normalize the velocity by the car's maximum speed
		float normalizedVelocity = velocityTowardsBall / CommonValues::CAR_MAX_SPEED;

		RG_LOG(predictedBall.pos.x);
		// Ensure the reward is non-negative
		return RS_MAX(0.0f, normalizedVelocity);
	}
};