look at these cpp rewards namespace RLGSC {
	// https://github.com/AechPro/rocket-league-gym-sim/blob/main/rlgym_sim/utils/reward_functions/common_rewards/misc_rewards.py
	class EventReward : public RewardFunction {
	public:
		struct ValSet {
			constexpr static int VAL_AMOUNT = 11;
			float vals[VAL_AMOUNT] = {};

			float& operator[](int index) { return vals[index]; }
		};
		ValSet weights;

		std::unordered_map<int, ValSet> lastRegisteredValues;

		struct WeightScales {
			float
				goal = 0,
				teamGoal = 0,
				concede = 0,
				assist = 0,

				touch = 0,
				shot = 0,
				shotPass = 0,
				save = 0,
				demo = 0,
				demoed = 0,
				boostPickup = 0;

			float& operator[](size_t index) { 
				// Make sure members line up
				static_assert(
					offsetof(WeightScales, boostPickup) - offsetof(WeightScales, goal) == 
					sizeof(float) * (ValSet::VAL_AMOUNT - 1)
					);
				return (&goal)[index]; 
			}
		};

		EventReward(WeightScales scales);

		static ValSet ExtractValues(const PlayerData& player, const GameState& state);

		virtual void Reset(const GameState& state);
		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction);
	};

	// https://github.com/AechPro/rocket-league-gym-sim/blob/main/rlgym_sim/utils/reward_functions/common_rewards/misc_rewards.py
	class VelocityReward : public RewardFunction {
	public:
		bool isNegative;
		VelocityReward(bool isNegative = false) : isNegative(isNegative) {}
		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) {
			return player.phys.vel.Length() / CommonValues::CAR_MAX_SPEED * (1 - 2 * isNegative);
		}
	};

	// https://github.com/AechPro/rocket-league-gym-sim/blob/main/rlgym_sim/utils/reward_functions/common_rewards/misc_rewards.py
	class SaveBoostReward : public RewardFunction {
	public:
		float exponent;
		SaveBoostReward(float exponent = 0.5f) : exponent(exponent) {}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) {
			return RS_CLAMP(powf(player.boostFraction, exponent), 0, 1);
		}
	};

	class BoostSquareDiff : public RewardFunction {
	public:
		BoostSquareDiff() {}

		virtual void Reset(const GameState& initial_state) override {
			previous_boost_amounts.clear();
			for (const auto& player : initial_state.players) {
				previous_boost_amounts[player.carId] = player.boostFraction;
			}
		}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& previous_action) override {
			float current_boost = player.boostFraction;
			float reward = 0.0f;

			auto it = previous_boost_amounts.find(player.carId);
			if (it != previous_boost_amounts.end()) {
				float prev_boost = it->second;
				reward = std::max(0.0f, std::sqrt(std::sqrt(current_boost) - std::sqrt(prev_boost)));
			}

			previous_boost_amounts[player.carId] = current_boost;

			return reward;
		}

	private:
		std::unordered_map<uint32_t, float> previous_boost_amounts;
	};

	
	


	class PlayerNetA : public RewardFunction {
	public:
		PlayerNetA(float align_w = 1.0f) : align_w(align_w) {}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) override {
			Vec ball_pos = state.ball.pos;
			Vec pos = player.phys.pos;

			// Align player->ball and player->net vectors
			float alignment = 0.5f * (CosineSimilarity(ball_pos - pos, CommonValues::ORANGE_GOAL_BACK - pos) -
				CosineSimilarity(ball_pos - pos, CommonValues::BLUE_GOAL_BACK - pos));

			if (player.team == Team::ORANGE) {
				alignment *= -1;
			}

			return align_w * alignment;
		}

	private:
		float align_w;

		float CosineSimilarity(const Vec& a, const Vec& b) {
			return a.Dot(b) / (a.Length() * b.Length());
		}
	};


	class StateQReward : public RLGSC::RewardFunction {
	private:
		float goal_dist_w;
		Vec orange_goal;
		Vec blue_goal;

	public:
		StateQReward(float goal_dist_weight = 10.0f)
			: goal_dist_w(goal_dist_weight) {
			// Initialize goal positions
			orange_goal = (RLGSC::CommonValues::ORANGE_GOAL_BACK + RLGSC::CommonValues::ORANGE_GOAL_CENTER) / 2;
			blue_goal = (RLGSC::CommonValues::BLUE_GOAL_BACK + RLGSC::CommonValues::BLUE_GOAL_CENTER) / 2;
		}

		float GetReward(const RLGSC::PlayerData& player, const RLGSC::GameState& state, const RLGSC::Action& prevAction) override {
			Vec ball_pos = state.ball.pos;

			float orange_dist = (orange_goal - ball_pos).Length();
			float blue_dist = (blue_goal - ball_pos).Length();

			float state_quality = 0.5f * goal_dist_w * (
				std::exp(-orange_dist / RLGSC::CommonValues::CAR_MAX_SPEED) -
				std::exp(-blue_dist / RLGSC::CommonValues::CAR_MAX_SPEED)
				);

			// Flip the reward for orange team
			return (player.team == Team::BLUE) ? state_quality : -state_quality;
		}
	};


    

	class BallTowardsGoalReward : public RewardFunction {
	public:
		bool ownGoal = false;
		float angleThreshold = 0.6f;

		BallTowardsGoalReward(bool ownGoal = false) : ownGoal(ownGoal) {}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) {
			bool targetOrangeGoal = player.team == Team::BLUE;
			if (ownGoal)
				targetOrangeGoal = !targetOrangeGoal;

			// Define goal dimensions
			float GOAL_WIDTH = 892.755f;
			float GOAL_HEIGHT = 642.775f;
			float goalY = RLConst::SOCCAR_GOAL_SCORE_BASE_THRESHOLD_Y * (player.team == Team::BLUE ? 1 : -1);
			goalY *= 1.05f;

			float distToScoring = abs(state.ball.pos.y - goalY);
			float timeToScoring = distToScoring / (abs(state.ball.vel.y) + 1e-6);

			Vec gravityDrop = Vec(0, 0, RLConst::GRAVITY_Z) * powf(timeToScoring, 2) * 0.5f;
			Vec extrapBallPos = state.ball.pos + state.ball.vel * timeToScoring + gravityDrop;
			extrapBallPos.z = RS_MAX(extrapBallPos.z, CommonValues::BALL_RADIUS);
			//RG_LOG(extrapBallPos);

			Vec targetPos = {
			  RS_CLAMP(extrapBallPos.x, -GOAL_WIDTH, GOAL_WIDTH),
			  goalY,
			  RS_CLAMP(extrapBallPos.z, 0, GOAL_HEIGHT)
			};

			

			// Calculate direction vectors
			Vec ballDirToGoal = (targetPos - state.ball.pos).Normalized();
			Vec ballHeadingDir = state.ball.vel.Normalized(); // Using velocity for ball's heading direction

			// Calculate dot product
			float unAlign = ballDirToGoal.Dist(ballHeadingDir);
			//RG_LOG(unAlign);
			//RG_LOG(extrapBallPos);

			float reward = 0.0f;
			
			reward = 1 - (unAlign / angleThreshold);
			

			return RS_MAX(reward, 0) * state.ball.vel.Length() / 3000;
		}
	};

	

	// reward the player for moving fast at the ball
	class SpeedTowardBallReward : public RewardFunction {
	public:
		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) {
			return RS_MAX(0, player.phys.vel.Dot((state.ball.pos - player.phys.pos).Normalized()) / CommonValues::CAR_MAX_SPEED);
		};
	};

	// https://github.com/AechPro/rocket-league-gym-sim/blob/main/rlgym_sim/utils/reward_functions/common_rewards/player_ball_rewards.py
	class FaceBallReward : public RewardFunction {
	public:
		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) {
			Vec dirToBall = (state.ball.pos - player.phys.pos).Normalized();
			return player.carState.rotMat.forward.Dot(dirToBall);
		}
	};

	// https://github.com/AechPro/rocket-league-gym-sim/blob/main/rlgym_sim/utils/reward_functions/common_rewards/player_ball_rewards.py
	class TouchBallReward : public RewardFunction {
	public:
		float aerialWeight;
		TouchBallReward(float aerialWeight = 0) : aerialWeight(aerialWeight) {}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) {
			using namespace CommonValues;

			if (player.ballTouchedStep) {
				return powf((state.ball.pos.z + BALL_RADIUS) / (BALL_RADIUS * 2), aerialWeight);
			} else {
				return 0;
			}
		}
	};

	class StrongTouchReward : public RewardFunction {
	public:
		Vec last_vel;

		StrongTouchReward() : last_vel(Vec(0, 0, 0)) {}

		virtual void Reset(const GameState& initialState) override {
			last_vel = Vec(0, 0, 0);
		}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) override {
			float reward = 0.0f;
			if (player.ballTouchedStep) {
				float vel_difference = std::abs((last_vel - state.ball.vel).Length());
				reward = vel_difference / 4600.0f;
			}

			last_vel = state.ball.vel;

			return reward;
		}

	};

	class JumpTouchReward : public RewardFunction {
	public:
		JumpTouchReward(float min_height = 200.0f, float exp = 1.0f)
			: min_height(min_height), exp(exp), div(std::pow(CommonValues::CEILING_Z / 2 - CommonValues::BALL_RADIUS, exp)) {}

		virtual void Reset(const GameState& initialState) override {
			ticks_until_next_reward = 0;
		}

		virtual float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) override {
			if (player.ballTouchedStep && player.carState.isOnGround && state.ball.pos[2] >= min_height && ticks_until_next_reward <= 0) {
				ticks_until_next_reward = 149;
				float reward = std::pow(std::min(state.ball.pos[2], CommonValues::CEILING_Z / 2) - CommonValues::BALL_RADIUS, exp) / div;
				if (reward > 0.05)
					return reward;
			}
			ticks_until_next_reward -= 1;
			return 0.0f;
		}

	private:
		float min_height;
		float exp;
		float div;
		int ticks_until_next_reward = 0;
	};

	class THeight : public RewardFunction {
	private:
		float weight;

	public:
		THeight(float weight = 1.0f) : weight(weight) {}

		float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) override {
			if (player.ballTouchedStep && !player.carState.isOnGround) {
				float touchHeight = state.ball.pos.z / CommonValues::CEILING_Z;
				//RG_LOG(touchHeight);
				return weight * touchHeight;
			}
			return 0.0f;
		}
	};

	class TAccel : public RewardFunction {
	private:
		float weight;
		Vec lastBallVelocity;

	public:
		TAccel(float weight = 1.0f) : weight(weight), lastBallVelocity(Vec()) {}

		void Reset(const GameState& initialState) override {
			lastBallVelocity = initialState.ball.vel;
		}

		float GetReward(const PlayerData& player, const GameState& state, const Action& prevAction) override {
			Vec curr_vel = state.ball.vel;
			float reward = 0.0f;

			if (player.ballTouchedStep) {
				// Exactly matching the Python logic:
				// norm(curr_vel - last_vel) / CAR_MAX_SPEED
				reward = (curr_vel - lastBallVelocity).Length() / CommonValues::CAR_MAX_SPEED;
			}
			//RG_LOG(reward);
			lastBallVelocity = curr_vel;  // Update for next step
			return weight * reward;
		}
	}; i want you to convert this python reward function into cpp like the other cpp reward in one big reward class NectoRewardFunction(RewardFunction):
    BLUE_GOAL = (np.array(BLUE_GOAL_BACK) + np.array(BLUE_GOAL_CENTER)) / 2
    ORANGE_GOAL = (np.array(ORANGE_GOAL_BACK) + np.array(ORANGE_GOAL_CENTER)) / 2

    def __init__(
            self,
            team_spirit=0.6,  # 0.3 -> 0.5
            goal_w=10,
            goal_dist_w=10,
            goal_speed_bonus_w=2.5,
            goal_dist_bonus_w=2.5,
            demo_w=5,
            dist_w=0.5,  # 0.75 -> 0.5
            align_w=0.5,
            boost_gain_w=1,
            boost_lose_w=0.7,  # 0.5 -> 0.7
            touch_grass_w=0.005,
            touch_height_w=1.2,  # 1 -> ~1.1 (changed normalization factor) -> 1.2
            touch_accel_w=0.25,
            opponent_punish_w=1
    ):
        self.team_spirit = team_spirit
        self.current_state = None
        self.last_state = None
        self.n = 0
        self.goal_w = goal_w
        self.goal_dist_w = goal_dist_w
        self.goal_speed_bonus_w = goal_speed_bonus_w
        self.goal_dist_bonus_w = goal_dist_bonus_w
        self.demo_w = demo_w
        self.dist_w = dist_w
        self.align_w = align_w
        self.boost_gain_w = boost_gain_w
        self.boost_lose_w = boost_lose_w
        self.touch_grass_w = touch_grass_w
        self.touch_height_w = touch_height_w
        self.touch_accel_w = touch_accel_w
        self.opponent_punish_w = opponent_punish_w
        self.state_quality = None
        self.player_qualities = None
        self.rewards = None

    def _state_qualities(self, state: GameState):
        ball_pos = state.ball.position

        state_quality = 0.5 * self.goal_dist_w * (exp(-norm(self.ORANGE_GOAL - ball_pos) / CAR_MAX_SPEED)
                                                  - exp(-norm(self.BLUE_GOAL - ball_pos) / CAR_MAX_SPEED))
        player_qualities = np.zeros(len(state.players))
        for i, player in enumerate(state.players):
            pos = player.car_data.position

            # Align player->ball and player->net vectors
            alignment = 0.5 * (cosine_similarity(ball_pos - pos, ORANGE_GOAL_BACK - pos)
                               - cosine_similarity(ball_pos - pos, BLUE_GOAL_BACK - pos))
            if player.team_num == ORANGE_TEAM:
                alignment *= -1
            liu_dist = exp(-norm(ball_pos - pos) / 1410)  # Max driving speed
            player_qualities[i] = (self.dist_w * liu_dist + self.align_w * alignment)

            # TODO use only dist of closest player for entire team?

        # Half state quality because it is applied to both teams, thus doubling it in the reward distributing
        return state_quality / 2, player_qualities

    def _calculate_rewards(self, state: GameState):
        # Calculate rewards, positive for blue, negative for orange
        state_quality, player_qualities = self._state_qualities(state)
        player_rewards = np.zeros_like(player_qualities)

        for i, player in enumerate(state.players):
            last = self.last_state.players[i]

            if player.ball_touched:
                curr_vel = self.current_state.ball.linear_velocity
                last_vel = self.last_state.ball.linear_velocity

                # On ground it gets about 0.04 just for touching, as well as some extra for the speed it produces
                # Ball is pretty close to z=150 when on top of car, so 1 second of dribbling is 1 reward
                # Close to 20 in the limit with ball on top, but opponents should learn to challenge way before that
                player_rewards[i] += self.touch_height_w * state.ball.position[2] / CEILING_Z

                # Changing speed of ball from standing still to supersonic (~83kph) is 1 reward
                player_rewards[i] += self.touch_accel_w * norm(curr_vel - last_vel) / CAR_MAX_SPEED

            # Encourage collecting and saving boost, sqrt to weight boost more the less it has
            boost_diff = np.sqrt(player.boost_amount) - np.sqrt(last.boost_amount)
            if boost_diff >= 0:
                player_rewards[i] += self.boost_gain_w * boost_diff
            else:
                player_rewards[i] += self.boost_lose_w * boost_diff

            # Encourage being in the air (slightly)
            player_rewards[i] -= player.on_ground * self.touch_grass_w

            if player.is_demoed and not last.is_demoed:
                player_rewards[i] -= self.demo_w / 2
            if player.match_demolishes > last.match_demolishes:
                player_rewards[i] += self.demo_w / 2

        mid = len(player_rewards) // 2

        player_rewards += player_qualities - self.player_qualities
        player_rewards[:mid] += state_quality - self.state_quality
        player_rewards[mid:] -= state_quality - self.state_quality

        self.player_qualities = player_qualities
        self.state_quality = state_quality

        # Handle goals with no scorer for critic consistency,
        # random state could send ball straight into goal
        d_blue = state.blue_score - self.last_state.blue_score
        d_orange = state.orange_score - self.last_state.orange_score
        if d_blue > 0:
            goal_speed = norm(self.last_state.ball.linear_velocity)
            distances = norm(
                np.stack([p.car_data.position for p in state.players[mid:]])
                - self.last_state.ball.position,
                axis=-1
            )
            player_rewards[mid:] = -self.goal_dist_bonus_w * (1 - exp(-distances / CAR_MAX_SPEED))
            player_rewards[:mid] = (self.goal_w * d_blue
                                    + self.goal_dist_bonus_w * goal_speed / BALL_MAX_SPEED)
        if d_orange > 0:
            goal_speed = norm(self.last_state.ball.linear_velocity)
            distances = norm(
                np.stack([p.car_data.position for p in state.players[:mid]])
                - self.last_state.ball.position,
                axis=-1
            )
            player_rewards[:mid] = -self.goal_dist_bonus_w * (1 - exp(-distances / CAR_MAX_SPEED))
            player_rewards[mid:] = (self.goal_w * d_orange
                                    + self.goal_dist_bonus_w * goal_speed / BALL_MAX_SPEED)

        blue = player_rewards[:mid]
        orange = player_rewards[mid:]
        bm = np.nan_to_num(blue.mean())
        om = np.nan_to_num(orange.mean())

        player_rewards[:mid] = ((1 - self.team_spirit) * blue + self.team_spirit * bm
                                - self.opponent_punish_w * om)
        player_rewards[mid:] = ((1 - self.team_spirit) * orange + self.team_spirit * om
                                - self.opponent_punish_w * bm)

        self.last_state = state
        self.rewards = player_rewards

    def reset(self, initial_state: GameState):
        self.n = 0
        self.last_state = None
        self.rewards = None
        self.current_state = initial_state
        self.state_quality, self.player_qualities = self._state_qualities(initial_state)

    def get_reward(self, player: PlayerData, state: GameState, previous_action: np.ndarray) -> float:
        if state != self.current_state:
            self.last_state = self.current_state
            self.current_state = state
            self._calculate_rewards(state)
            self.n = 0
        rew = self.rewards[self.n]
        self.n += 1
        return float(rew)  # / 3.2  # Divide to get std of expected reward to ~1 at start, helps value net a little