Program Listing for File Engine.hpp
↰ Return to documentation for file (engine/include/Cacao/Engine.hpp
)
#pragma once
#include <future>
#include <mutex>
#include <string>
#include <chrono>
#include <filesystem>
#include <thread>
#include <queue>
#include <functional>
#include "Exceptions.hpp"
#include "DllHelper.hpp"
#include "Identity.hpp"
using namespace std::chrono_literals;
namespace Cacao {
class CACAO_API Engine {
public:
static Engine& Get();
Engine(const Engine&) = delete;
Engine(Engine&&) = delete;
Engine& operator=(const Engine&) = delete;
Engine& operator=(Engine&&) = delete;
//======================= CONFIGURATION =======================
struct CACAO_API Config {
std::chrono::milliseconds fixedTickRate = 20ms;
int maxFrameLag;
bool alwaysRerenderUI = false;
} config;
struct CACAO_API InitConfig {
bool standalone = false;
std::string initialRequestedBackend;
std::string preferredWindowProvider;
bool suppressConsoleLogging = false;
bool suppressFileLogging = false;
ClientIdentity clientID;
};
const InitConfig& GetInitConfig() const {
return icfg;
}
//===================== UTILITY FUNCTIONS =====================
const std::filesystem::path GetDataDirectory();
template<typename F, typename... Args, typename R = std::invoke_result_t<F&&, Args&&...>>
requires std::invocable<F&&, Args&&...>
std::shared_future<R> RunTaskOnMainThread(F func, Args... args) {
Check<BadStateException>(state == State::Running, "Engine must be in running state to submit main thread task!");
//Create a task and get a result future
std::shared_ptr<std::packaged_task<R()>> task;
if constexpr(sizeof...(args) == 0) {
task = std::make_shared<std::packaged_task<R()>>(std::move(func));
} else {
//Wrap the function so it doesn't need any arguments
auto wrapper = std::bind(std::forward<F>(func), std::forward<Args...>(args...));
task = std::make_shared<std::packaged_task<R()>>(std::move(wrapper));
}
std::shared_future<R> result = task->get_future().share();
//Is this the main thread?
if(std::this_thread::get_id() == mainThread) {
(*task)();
return result;
}
//Add task to queue
{
std::lock_guard lk(mttQueueMtx);
mainThreadTasksQueue.emplace([task]() { (*task)(); });
}
//Return future
return result;
}
//========================= LIFECYCLE =========================
enum class State {
Dead,
Alive,
Ready,
Running
};
void CoreInit(const InitConfig& initCfg);
void GfxInit();
void Run();
void Quit();
void GfxShutdown();
void CoreShutdown();
State GetState() {
std::lock_guard lk(stateMtx);
return state;
}
private:
InitConfig icfg;
State state;
std::mutex stateMtx;
std::queue<std::function<void()>> mainThreadTasksQueue;
std::mutex mttQueueMtx;
std::thread::id mainThread;
Engine();
~Engine();
};
}