int main(int argc, char* argv[]) {
	// Initialize RocketSim with collision meshes
	RocketSim::Init("./collision_meshes");

	// Make configuration for the learner
	LearnerConfig cfg = {};
	cfg.renderMode = false;

	for (int i = 1; i < argc; ++i) {
		if (std::strcmp(argv[i], "--render") == 0) {
			cfg.renderMode = true;
			cfg.renderTimeScale = 1.0f;
			cfg.deterministic = true;
		}
	}

	// Play around with these to see what the optimal is for your machine, more isn't always better
	cfg.numThreads = 16;
	cfg.numGamesPerThread = 20;

	// We want a large itr/batch size
	// You'll want to increase this as your bot improves, up to an extent
	int tsPerItr = 100 * 1000;
	cfg.timestepsPerIteration = tsPerItr;
	cfg.ppo.batchSize = tsPerItr;
	cfg.ppo.miniBatchSize = 25 * 1000; // Lower this if too much VRAM is being allocated
	cfg.expBufferSize = tsPerItr * 2;
	
	// This is just set to 1 to match rlgym-ppo example
	// I've found the best value is somewhere between 2 and 4
	// Increasing this will lower SPS, but increase step efficiency
	cfg.ppo.epochs = 3; 

	// Reasonable starting entropy
	cfg.ppo.entCoef = 0.01f;

	cfg.skillTrackerConfig.enabled = true;
	cfg.timestepsPerSave = 2'000'000;
	cfg.checkpointsToKeep = 30;
	cfg.skillTrackerConfig.numEnvs = 16;
	cfg.skillTrackerConfig.numThreads = 16;
	cfg.skillTrackerConfig.perModeRatings = true;

	// Good learning rate to start, may start to be too high around 100m steps
	cfg.ppo.policyLR = 1e-4;
	cfg.ppo.criticLR = 1e-4;


	cfg.metricsRunName = "FINAL2";
	cfg.metricsProjectName = "VILLAIN ARC";
	cfg.metricsGroupName = "GOOD";

	// Default model size
	cfg.ppo.policyLayerSizes = { 512, 512, 512, 512, 512 };
	cfg.ppo.criticLayerSizes = { 512, 512, 512, 512, 512 };
	
	cfg.sendMetrics = true; // Send metrics
	
	// Make the learner with the environment creation function and the config we just made
	Learner learner = Learner(EnvCreateFunc, cfg);

	// Set up our callbacks
	learner.stepCallback = OnStep;
	learner.iterationCallback = OnIteration;

	// Add a custom step callback to update the global ball prediction
	auto originalStepCallback = learner.stepCallback;
	learner.stepCallback = [originalStepCallback](GameInst* gameInst, const RLGSC::Gym::StepResult& stepResult, Report& gameMetrics) {
		// Call the original step callback
		if (originalStepCallback) {
			originalStepCallback(gameInst, stepResult, gameMetrics);
		}

		// Update the global ball prediction
		const RocketSim::Arena* arena = gameInst->gym->arena;
		RLGSC::UpdateGlobalBallPrediction(arena);
		};

	// Start learning!
	learner.Learn();

	// Cleanup the global ball prediction when done
	RLGSC::CleanupGlobalBallPred();

	return 0;
} #pragma once


#include "C:\Epsilon\RLGymPPO_CPP-main\RLGymPPO_CPP\RLGymSim_CPP\RocketSim\src\Sim\Arena\Arena.h"
#include "C:\Epsilon\RLGymPPO_CPP-main\RLGymPPO_CPP\RLGymSim_CPP\src\RLGymSim_CPP\Utils\Gamestates\PhysObj.h"
#include "C:\Epsilon\RLGymPPO_CPP-main\RLGymPPO_CPP\RLGymSim_CPP\RocketSim\src\Sim\BallPredTracker\BallPredTracker.h"
#include <mutex>

namespace RLGSC {

    class GlobalBallPred {
    private:
        static GlobalBallPred* instance;
        RocketSim::BallPredTracker* ballPredTracker;
        const RocketSim::Arena* arena;
        std::mutex mutex;

        GlobalBallPred(const RocketSim::Arena* arena);

    public:
        static GlobalBallPred* GetInstance(const RocketSim::Arena* arena);
        RLGSC::PhysObj GetAtTime(float time, const RLGSC::PhysObj& curBall);
        void UpdatePrediction();
        static void Cleanup();

        GlobalBallPred(const GlobalBallPred&) = delete;
        GlobalBallPred& operator=(const GlobalBallPred&) = delete;

        ~GlobalBallPred();
    };

    inline void UpdateGlobalBallPrediction(const RocketSim::Arena* arena) {
        GlobalBallPred::GetInstance(arena)->UpdatePrediction();
    }

    inline RLGSC::PhysObj GetGlobalBallPredAtTime(const RocketSim::Arena* arena, float time, const RLGSC::PhysObj& curBall) {
        return GlobalBallPred::GetInstance(arena)->GetAtTime(time, curBall);
    }

    inline void CleanupGlobalBallPred() {
        GlobalBallPred::Cleanup();
    }

}  // namespace RLGSC #include "GlobalBallPred.h"

namespace RLGSC {

    GlobalBallPred* GlobalBallPred::instance = nullptr;

    GlobalBallPred::GlobalBallPred(const RocketSim::Arena* arena) : arena(arena), ballPredTracker(nullptr) {
        ballPredTracker = new RocketSim::BallPredTracker(const_cast<RocketSim::Arena*>(arena), 6 * 120);
    }

    GlobalBallPred* GlobalBallPred::GetInstance(const RocketSim::Arena* arena) {
        static std::mutex initMutex;
        std::lock_guard<std::mutex> lock(initMutex);

        if (instance == nullptr) {
            instance = new GlobalBallPred(arena);
        }
        return instance;
    }

    RLGSC::PhysObj GlobalBallPred::GetAtTime(float time, const RLGSC::PhysObj& curBall) {
        std::lock_guard<std::mutex> lock(mutex);

        if (ballPredTracker->predData.empty()) {
            return curBall;
        }

        return RLGSC::PhysObj(ballPredTracker->GetBallStateForTime(time));
    }

    void GlobalBallPred::UpdatePrediction() {
        std::lock_guard<std::mutex> lock(mutex);
        ballPredTracker->UpdatePredFromArena(const_cast<RocketSim::Arena*>(arena));
    }

    void GlobalBallPred::Cleanup() {
        delete instance;
        instance = nullptr;
    }

    GlobalBallPred::~GlobalBallPred() {
        delete ballPredTracker;
    }

}  // namespace RLGSC how the ballpred is made #pragma once
#include "../Arena/Arena.h"

RS_NS_START

// An external tool struct that predicts the ball of a given arena
struct BallPredTracker {
	Arena* ballPredArena;
	std::vector<BallState> predData;
	size_t numPredTicks;

	int lastUpdateTickCount;

	// arena: The arena you want to predict the ball for (BallPredTracker will make a copy of it without the cars)
	// You do not need to make another arena for BallPredTracker, it does that itself
	BallPredTracker(Arena* arena, size_t numPredTicks);
	~BallPredTracker();

	// No copying
	BallPredTracker(const BallPredTracker& other) = delete;
	BallPredTracker& operator=(const BallPredTracker& other) = delete;

	// Update the prediction data from the arena the ball is in, does not need to be called every tick
	// The arena is needed for the current ball state, as well as the tick count to determine time since last update
	void UpdatePredFromArena(Arena* arena);

	// An alternate version of UpdatePred which doesn't require the arena, 
	//	but instead you manually provide the current ball state and the ticks since this tracker was last updated
	void UpdatePredManual(const BallState& curBallState, int ticksSinceLastUpdate);

	// Forcefully re-predicts all ticks
	void ForceUpdateAllPred(const BallState& initialBallState);

	// Get the predicted ball state at a given future time delta
	BallState GetBallStateForTime(float predTime) const;
};

RS_NS_END errors Severity	Code	Description	Project	File	Line	Suppression State	Details
Error	LNK2019	unresolved external symbol "public: static class RLGSC::GlobalBallPred * __cdecl RLGSC::GlobalBallPred::GetInstance(class RocketSim::Arena const *)" (?GetInstance@GlobalBallPred@RLGSC@@SAPEAV12@PEBVArena@RocketSim@@@Z) referenced in function "void __cdecl std::invoke<class `int __cdecl main(int,char * * const)'::`2'::<lambda_1> &,class RLGPC::GameInst *,struct RLGSC::Gym::StepResult const &,struct RLGPC::Report &>(class `int __cdecl main(int,char * * const)'::`2'::<lambda_1> &,class RLGPC::GameInst * &&,struct RLGSC::Gym::StepResult const &,struct RLGPC::Report &)" (??$invoke@AEAV<lambda_1>@?1??main@@YAHHQEAPEAD@Z@PEAVGameInst@RLGPC@@AEBUStepResult@Gym@RLGSC@@AEAUReport@4@@std@@YAXAEAV<lambda_1>@?1??main@@YAHHQEAPEAD@Z@$$QEAPEAVGameInst@RLGPC@@AEBUStepResult@Gym@RLGSC@@AEAUReport@4@@Z)	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\RLGymPPO_CPP-main	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\examplemain.cpp.obj	1		Severity	Code	Description	Project	File	Line	Suppression State	Details
Error	LNK2019	unresolved external symbol "public: void __cdecl RLGSC::GlobalBallPred::UpdatePrediction(void)" (?UpdatePrediction@GlobalBallPred@RLGSC@@QEAAXXZ) referenced in function "void __cdecl std::invoke<class `int __cdecl main(int,char * * const)'::`2'::<lambda_1> &,class RLGPC::GameInst *,struct RLGSC::Gym::StepResult const &,struct RLGPC::Report &>(class `int __cdecl main(int,char * * const)'::`2'::<lambda_1> &,class RLGPC::GameInst * &&,struct RLGSC::Gym::StepResult const &,struct RLGPC::Report &)" (??$invoke@AEAV<lambda_1>@?1??main@@YAHHQEAPEAD@Z@PEAVGameInst@RLGPC@@AEBUStepResult@Gym@RLGSC@@AEAUReport@4@@std@@YAXAEAV<lambda_1>@?1??main@@YAHHQEAPEAD@Z@$$QEAPEAVGameInst@RLGPC@@AEBUStepResult@Gym@RLGSC@@AEAUReport@4@@Z)	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\RLGymPPO_CPP-main	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\examplemain.cpp.obj	1		Severity	Code	Description	Project	File	Line	Suppression State	Details
Error	LNK2019	unresolved external symbol "public: static void __cdecl RLGSC::GlobalBallPred::Cleanup(void)" (?Cleanup@GlobalBallPred@RLGSC@@SAXXZ) referenced in function "void __cdecl RLGSC::CleanupGlobalBallPred(void)" (?CleanupGlobalBallPred@RLGSC@@YAXXZ)	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\RLGymPPO_CPP-main	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\examplemain.cpp.obj	1		
Severity	Code	Description	Project	File	Line	Suppression State	Details
Error	LNK2019	unresolved external symbol "public: __cdecl RLGSC::DefaultOBS::DefaultOBS(struct RocketSim::Vec,float,float)" (??0DefaultOBS@RLGSC@@QEAA@UVec@RocketSim@@MM@Z) referenced in function "struct RLGPC::EnvCreateResult __cdecl EnvCreateFunc(void)" (?EnvCreateFunc@@YA?AUEnvCreateResult@RLGPC@@XZ)	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\RLGymPPO_CPP-main	C:\Epsilon\RLGymPPO_CPP-main\out\build\x64.build\examplemain.cpp.obj	1