h1-mod/src/client/component/scheduler.cpp

227 lines
4.8 KiB
C++
Raw Normal View History

2022-02-03 14:05:24 -05:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "game/game.hpp"
#include <utils/hook.hpp>
#include <utils/concurrency.hpp>
#include <utils/string.hpp>
2022-02-17 00:11:35 -05:00
#include <utils/thread.hpp>
2022-02-03 14:05:24 -05:00
namespace scheduler
{
namespace
{
struct task
{
std::function<bool()> handler{};
std::chrono::milliseconds interval{};
std::chrono::high_resolution_clock::time_point last_call{};
};
using task_list = std::vector<task>;
class task_pipeline
{
public:
void add(task&& task)
{
new_callbacks_.access([&task](task_list& tasks)
2022-02-23 15:23:00 -05:00
{
tasks.emplace_back(std::move(task));
});
2022-02-03 14:05:24 -05:00
}
void execute()
{
callbacks_.access([&](task_list& tasks)
{
this->merge_callbacks();
for (auto i = tasks.begin(); i != tasks.end();)
2022-02-03 14:05:24 -05:00
{
const auto now = std::chrono::high_resolution_clock::now();
const auto diff = now - i->last_call;
2022-02-03 14:05:24 -05:00
if (diff < i->interval)
2022-02-03 14:05:24 -05:00
{
++i;
continue;
2022-02-03 14:05:24 -05:00
}
i->last_call = now;
const auto res = i->handler();
if (res == cond_end)
{
i = tasks.erase(i);
}
else
{
++i;
}
}
});
2022-02-03 14:05:24 -05:00
}
private:
utils::concurrency::container<task_list> new_callbacks_;
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
void merge_callbacks()
{
callbacks_.access([&](task_list& tasks)
2022-02-23 15:23:00 -05:00
{
new_callbacks_.access([&](task_list& new_tasks)
2022-02-03 14:05:24 -05:00
{
2022-05-17 10:56:26 -04:00
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()),
std::move_iterator<task_list::iterator>(new_tasks.end()));
2022-02-23 15:23:00 -05:00
new_tasks = {};
2022-02-03 14:05:24 -05:00
});
2022-02-23 15:23:00 -05:00
});
2022-02-03 14:05:24 -05:00
}
};
volatile bool kill = false;
std::thread thread;
task_pipeline pipelines[pipeline::count];
utils::hook::detour r_end_frame_hook;
utils::hook::detour g_run_frame_hook;
utils::hook::detour main_frame_hook;
2022-05-19 18:06:09 -04:00
utils::hook::detour hks_frame_hook;
2022-02-03 14:05:24 -05:00
void execute(const pipeline type)
{
assert(type >= 0 && type < pipeline::count);
pipelines[type].execute();
}
void r_end_frame_stub()
{
execute(pipeline::renderer);
}
void server_frame_stub()
{
g_run_frame_hook.invoke<void>();
execute(pipeline::server);
}
2022-05-18 16:00:02 -04:00
void* main_frame_stub()
2022-02-03 14:05:24 -05:00
{
2022-05-18 16:00:02 -04:00
const auto _0 = gsl::finally([]()
{
execute(pipeline::main);
});
return main_frame_hook.invoke<void*>();
2022-02-03 14:05:24 -05:00
}
2022-04-11 05:05:21 -04:00
void hks_frame_stub()
{
const auto state = *game::hks::lua_state;
if (state)
{
execute(pipeline::lui);
}
2022-05-25 17:56:10 -04:00
hks_frame_hook.invoke<bool>();
2022-04-11 05:05:21 -04:00
}
2022-02-03 14:05:24 -05:00
}
void schedule(const std::function<bool()>& callback, const pipeline type,
2022-05-17 10:56:26 -04:00
const std::chrono::milliseconds delay)
2022-02-03 14:05:24 -05:00
{
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<void()>& callback, const pipeline type,
2022-05-17 10:56:26 -04:00
const std::chrono::milliseconds delay)
2022-02-03 14:05:24 -05:00
{
schedule([callback]()
2022-02-23 15:23:00 -05:00
{
callback();
return cond_continue;
}, type, delay);
2022-02-03 14:05:24 -05:00
}
void once(const std::function<void()>& callback, const pipeline type,
2022-05-17 10:56:26 -04:00
const std::chrono::milliseconds delay)
2022-02-03 14:05:24 -05:00
{
schedule([callback]()
2022-02-23 15:23:00 -05:00
{
callback();
return cond_end;
}, type, delay);
2022-02-03 14:05:24 -05:00
}
2022-02-17 00:11:35 -05:00
void on_game_initialized(const std::function<void()>& callback, const pipeline type,
2022-05-17 10:56:26 -04:00
const std::chrono::milliseconds delay)
2022-02-17 00:11:35 -05:00
{
schedule([=]()
2022-02-23 15:23:00 -05:00
{
2022-02-28 15:04:44 -05:00
const auto dw_init = game::environment::is_sp() ? true : game::Live_SyncOnlineDataFlags(0) == 0;
2022-02-23 15:23:00 -05:00
if (dw_init && game::Sys_IsDatabaseReady2())
2022-02-17 00:11:35 -05:00
{
2022-02-23 15:23:00 -05:00
once(callback, type, delay);
return cond_end;
}
2022-02-17 00:11:35 -05:00
2022-02-23 15:23:00 -05:00
return cond_continue;
}, pipeline::main);
2022-02-17 00:11:35 -05:00
}
2022-02-03 14:05:24 -05:00
class component final : public component_interface
{
public:
2022-02-17 00:11:35 -05:00
void post_start() override
{
thread = utils::thread::create_named_thread("Async Scheduler", []()
2022-02-23 15:23:00 -05:00
{
while (!kill)
2022-02-17 00:11:35 -05:00
{
2022-02-23 15:23:00 -05:00
execute(pipeline::async);
std::this_thread::sleep_for(10ms);
}
});
2022-02-17 00:11:35 -05:00
}
2022-02-03 14:05:24 -05:00
void post_unpack() override
{
2022-05-25 17:56:10 -04:00
utils::hook::jump(SELECT_VALUE(0x581FB0_b, 0x6A6300_b), utils::hook::assemble([](utils::hook::assembler& a)
2022-05-17 10:56:26 -04:00
{
a.pushad64();
a.call_aligned(r_end_frame_stub);
a.popad64();
a.sub(rsp, 0x28);
2022-05-25 17:56:10 -04:00
a.call(SELECT_VALUE(0x581840_b, 0x6A5C20_b));
a.mov(rax, SELECT_VALUE(0x1182A680_b, 0xEAB4308_b));
2022-05-17 10:56:26 -04:00
a.mov(rax, qword_ptr(rax));
2022-05-25 17:56:10 -04:00
a.jmp(SELECT_VALUE(0x581FC0_b, 0x6A6310_b));
2022-05-17 10:56:26 -04:00
}), true);
2022-05-25 17:56:10 -04:00
g_run_frame_hook.create(SELECT_VALUE(0x2992E0_b, 0x417940_b), scheduler::server_frame_stub);
main_frame_hook.create(SELECT_VALUE(0x1B1DF0_b, 0x3438B0_b), scheduler::main_frame_stub);
hks_frame_hook.create(SELECT_VALUE(0x1028D0_b, 0x2792E0_b), scheduler::hks_frame_stub);
2022-02-17 00:11:35 -05:00
}
void pre_destroy() override
{
kill = true;
if (thread.joinable())
{
thread.join();
}
2022-02-03 14:05:24 -05:00
}
};
}
2022-05-17 11:08:53 -04:00
REGISTER_COMPONENT(scheduler::component)