#include #include "scheduler.hpp" #include "loader/component_loader.hpp" #include #include #include #include namespace scheduler { namespace { struct task { std::function handler{}; std::chrono::milliseconds interval{}; std::chrono::high_resolution_clock::time_point last_call{}; }; using task_list = std::vector; class task_pipeline { public: void add(task&& task) { new_callbacks_.access([&task](task_list& tasks) { tasks.emplace_back(std::move(task)); }); } void execute() { callbacks_.access([&](task_list& tasks) { this->merge_callbacks(); for (auto i = tasks.begin(); i != tasks.end();) { const auto now = std::chrono::high_resolution_clock::now(); const auto diff = now - i->last_call; if (diff < i->interval) { ++i; continue; } i->last_call = now; const auto res = i->handler(); if (res == cond_end) { i = tasks.erase(i); } else { ++i; } } }); } private: utilities::concurrency::container new_callbacks_; utilities::concurrency::container callbacks_; void merge_callbacks() { callbacks_.access([&](task_list& tasks) { new_callbacks_.access([&](task_list& new_tasks) { tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), std::move_iterator(new_tasks.end())); new_tasks = {}; }); }); } }; volatile bool kill = false; std::thread thread; task_pipeline pipelines[pipeline::count]; utilities::hook::detour r_end_frame_hook; utilities::hook::detour g_run_frame_hook; utilities::hook::detour main_frame_hook; void execute(const pipeline type) { assert(type >= 0 && type < pipeline::count); pipelines[type].execute(); } void r_end_frame_stub() { execute(pipeline::renderer); r_end_frame_hook.invoke(); } void server_frame_stub() { g_run_frame_hook.invoke(); execute(pipeline::server); } void main_frame_stub() { main_frame_hook.invoke(); execute(pipeline::main); } } void schedule(const std::function& callback, const pipeline type, const std::chrono::milliseconds delay) { assert(type >= 0 && type < pipeline::count); task task; task.handler = callback; task.interval = delay; task.last_call = std::chrono::high_resolution_clock::now(); pipelines[type].add(std::move(task)); } void loop(const std::function& callback, const pipeline type, const std::chrono::milliseconds delay) { schedule([callback]() { callback(); return cond_continue; }, type, delay); } void once(const std::function& callback, const pipeline type, const std::chrono::milliseconds delay) { schedule([callback]() { callback(); return cond_end; }, type, delay); } class component final : public component_interface { public: void pre_start() override { thread = utilities::thread::create_named_thread("Async Scheduler", []() { while (!kill) { execute(pipeline::async); std::this_thread::sleep_for(10ms); } }); } void post_unpack() override { r_end_frame_hook.create(0x14361E260_g, r_end_frame_stub); // R_EndFrame main_frame_hook.create(0x14288BAE0_g, main_frame_stub); // Com_Frame //g_run_frame_hook.create(0x142D08FC0_g, server_frame_stub); // G_RunFrame } void pre_destroy() override { kill = true; if (thread.joinable()) { thread.join(); } } }; } REGISTER_COMPONENT(scheduler::component)