2022-02-27 07:53:44 -05:00
|
|
|
#include <STDInclude.hpp>
|
2017-05-31 09:45:12 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
constexpr bool COND_CONTINUE = false;
|
|
|
|
constexpr bool COND_END = true;
|
|
|
|
|
2017-05-31 09:45:12 -04:00
|
|
|
namespace Components
|
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
std::thread Scheduler::Thread;
|
|
|
|
volatile bool Scheduler::Kill = false;
|
|
|
|
Scheduler::TaskPipeline Scheduler::Pipelines[Pipeline::COUNT];
|
2017-07-03 09:07:47 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::TaskPipeline::add(Task&& task)
|
|
|
|
{
|
|
|
|
newCallbacks_.access([&task](taskList& tasks)
|
|
|
|
{
|
|
|
|
tasks.emplace_back(std::move(task));
|
|
|
|
});
|
|
|
|
}
|
2017-05-31 09:45:12 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::TaskPipeline::execute()
|
|
|
|
{
|
|
|
|
callbacks_.access([&](taskList& tasks)
|
|
|
|
{
|
|
|
|
this->mergeCallbacks();
|
2017-05-31 09:45:12 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
for (auto i = tasks.begin(); i != tasks.end();)
|
|
|
|
{
|
|
|
|
const auto now = std::chrono::high_resolution_clock::now();
|
|
|
|
const auto diff = now - i->lastCall;
|
2017-07-03 09:07:47 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
if (diff < i->interval)
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
i->lastCall = now;
|
|
|
|
|
|
|
|
const auto res = i->handler();
|
|
|
|
if (res == COND_END)
|
|
|
|
{
|
|
|
|
i = tasks.erase(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scheduler::TaskPipeline::mergeCallbacks()
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
callbacks_.access([&](taskList& tasks)
|
|
|
|
{
|
|
|
|
newCallbacks_.access([&](taskList& new_tasks)
|
|
|
|
{
|
|
|
|
tasks.insert(tasks.end(), std::move_iterator<taskList::iterator>(new_tasks.begin()), std::move_iterator<taskList::iterator>(new_tasks.end()));
|
|
|
|
new_tasks = {};
|
|
|
|
});
|
|
|
|
});
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::Execute(Pipeline type)
|
2017-05-31 10:09:41 -04:00
|
|
|
{
|
2022-06-04 08:59:14 -04:00
|
|
|
assert(type < Pipeline::COUNT);
|
2022-05-05 10:03:14 -04:00
|
|
|
Pipelines[type].execute();
|
2017-05-31 10:09:41 -04:00
|
|
|
}
|
|
|
|
|
2022-07-02 06:17:08 -04:00
|
|
|
void Scheduler::ScrPlace_EndFrame_Hk()
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-07-02 06:17:08 -04:00
|
|
|
Utils::Hook::Call<void()>(0x4AA720)();
|
2022-05-06 19:15:58 -04:00
|
|
|
Execute(Pipeline::RENDERER);
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::ServerFrame_Hk()
|
2017-05-31 10:09:41 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Utils::Hook::Call<void()>(0x471C50)();
|
2022-05-06 19:15:58 -04:00
|
|
|
Execute(Pipeline::SERVER);
|
2017-05-31 10:09:41 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::ClientFrame_Hk(const int localClientNum)
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Utils::Hook::Call<void(int)>(0x5A8E80)(localClientNum);
|
|
|
|
Execute(Pipeline::CLIENT);
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::MainFrame_Hk()
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Utils::Hook::Call<void()>(0x47DCA0)();
|
2022-05-06 19:15:58 -04:00
|
|
|
Execute(Pipeline::MAIN);
|
2022-05-05 10:03:14 -04:00
|
|
|
}
|
2017-05-31 09:45:12 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::SysSetBlockSystemHotkeys_Hk(int block)
|
|
|
|
{
|
|
|
|
Execute(Pipeline::QUIT);
|
|
|
|
Utils::Hook::Call<void(int)>(0x46B370)(block);
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::Schedule(const std::function<bool()>& callback, const Pipeline type,
|
|
|
|
const std::chrono::milliseconds delay)
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-06-04 08:59:14 -04:00
|
|
|
assert(type < Pipeline::COUNT);
|
2017-06-01 04:25:13 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
Task task;
|
|
|
|
task.handler = callback;
|
|
|
|
task.interval = delay;
|
|
|
|
task.lastCall = std::chrono::high_resolution_clock::now();
|
2017-05-31 09:45:12 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
Pipelines[type].add(std::move(task));
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::Loop(const std::function<void()>& callback, const Pipeline type,
|
|
|
|
const std::chrono::milliseconds delay)
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Schedule([callback]
|
2017-05-31 09:45:12 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
callback();
|
|
|
|
return COND_CONTINUE;
|
|
|
|
}, type, delay);
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::Once(const std::function<void()>& callback, const Pipeline type,
|
|
|
|
const std::chrono::milliseconds delay)
|
2017-05-31 10:09:41 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Schedule([callback]
|
|
|
|
{
|
|
|
|
callback();
|
|
|
|
return COND_END;
|
|
|
|
}, type, delay);
|
2017-05-31 10:09:41 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::OnGameInitialized(const std::function<void()>& callback, const Pipeline type,
|
|
|
|
const std::chrono::milliseconds delay)
|
2017-07-03 09:07:47 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Schedule([=]
|
|
|
|
{
|
|
|
|
if (Game::Sys_IsDatabaseReady2())
|
|
|
|
{
|
|
|
|
Once(callback, type, delay);
|
|
|
|
return COND_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
return COND_CONTINUE;
|
|
|
|
}, Pipeline::MAIN); // Once Com_Frame_Try_Block_Function is called we know the game is 'ready'
|
2017-07-03 09:07:47 -04:00
|
|
|
}
|
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
void Scheduler::OnGameShutdown(const std::function<void()>& callback)
|
2017-07-03 09:07:47 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Schedule([callback]
|
|
|
|
{
|
|
|
|
callback();
|
|
|
|
return COND_END;
|
|
|
|
}, Pipeline::QUIT, 0ms);
|
2017-07-03 09:07:47 -04:00
|
|
|
}
|
2017-05-31 10:09:41 -04:00
|
|
|
|
2017-05-31 09:45:12 -04:00
|
|
|
Scheduler::Scheduler()
|
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Thread = Utils::Thread::createNamedThread("Async Scheduler", []
|
2017-07-03 09:07:47 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
while (!Kill)
|
2017-07-03 09:07:47 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Execute(Pipeline::ASYNC);
|
|
|
|
std::this_thread::sleep_for(10ms);
|
|
|
|
}
|
|
|
|
});
|
2017-07-03 09:07:47 -04:00
|
|
|
|
2022-07-02 06:17:08 -04:00
|
|
|
Utils::Hook(0x5ACB9E, ScrPlace_EndFrame_Hk, HOOK_CALL).install()->quick();
|
2017-05-31 09:45:12 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
// Hook G_Glass_Update so we may fix TLS issues
|
|
|
|
Utils::Hook(0x416049, ServerFrame_Hk, HOOK_CALL).install()->quick();
|
2017-05-31 10:09:41 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
// CL_CheckTimeout
|
|
|
|
Utils::Hook(0x4B0F81, ClientFrame_Hk, HOOK_CALL).install()->quick();
|
2017-05-31 10:09:41 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
// Com_Frame_Try_Block_Function
|
|
|
|
Utils::Hook(0x4B724F, MainFrame_Hk, HOOK_CALL).install()->quick();
|
2017-07-03 09:07:47 -04:00
|
|
|
|
2022-05-05 10:03:14 -04:00
|
|
|
// Sys_Quit
|
|
|
|
Utils::Hook(0x4D697A, SysSetBlockSystemHotkeys_Hk, HOOK_CALL).install()->quick();
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|
2017-07-03 09:07:47 -04:00
|
|
|
|
|
|
|
void Scheduler::preDestroy()
|
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Kill = true;
|
|
|
|
if (Thread.joinable())
|
2017-07-03 09:07:47 -04:00
|
|
|
{
|
2022-05-05 10:03:14 -04:00
|
|
|
Thread.join();
|
2017-07-03 09:07:47 -04:00
|
|
|
}
|
|
|
|
}
|
2017-05-31 09:45:12 -04:00
|
|
|
}
|