iw4x-client/src/Components/Modules/Scheduler.cpp

194 lines
4.1 KiB
C++
Raw Normal View History

2022-02-27 07:53:44 -05:00
#include <STDInclude.hpp>
constexpr bool COND_CONTINUE = false;
constexpr bool COND_END = true;
namespace Components
{
std::thread Scheduler::Thread;
volatile bool Scheduler::Kill = false;
Scheduler::TaskPipeline Scheduler::Pipelines[Pipeline::COUNT];
2017-07-03 09:07:47 -04:00
void Scheduler::TaskPipeline::add(Task&& task)
{
newCallbacks_.access([&task](taskList& tasks)
{
tasks.emplace_back(std::move(task));
});
}
void Scheduler::TaskPipeline::execute()
{
callbacks_.access([&](taskList& tasks)
{
this->mergeCallbacks();
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
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()
{
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 = {};
});
});
}
void Scheduler::Execute(Pipeline type)
2017-05-31 10:09:41 -04:00
{
AssertCount(type, Pipeline::COUNT);
Pipelines[type].execute();
2017-05-31 10:09:41 -04:00
}
void Scheduler::REndFrame_Hk()
{
Utils::Hook::Call<void()>(0x50AB20)();
Execute(Pipeline::RENDERER);
}
void Scheduler::ServerFrame_Hk()
2017-05-31 10:09:41 -04:00
{
Utils::Hook::Call<void()>(0x471C50)();
Execute(Pipeline::SERVER);
2017-05-31 10:09:41 -04:00
}
void Scheduler::ClientFrame_Hk(const int localClientNum)
{
Utils::Hook::Call<void(int)>(0x5A8E80)(localClientNum);
Execute(Pipeline::CLIENT);
}
void Scheduler::MainFrame_Hk()
{
Utils::Hook::Call<void()>(0x47DCA0)();
Execute(Pipeline::MAIN);
}
void Scheduler::SysSetBlockSystemHotkeys_Hk(int block)
{
Execute(Pipeline::QUIT);
Utils::Hook::Call<void(int)>(0x46B370)(block);
}
void Scheduler::Schedule(const std::function<bool()>& callback, const Pipeline type,
const std::chrono::milliseconds delay)
{
AssertCount(type, Pipeline::COUNT);
Task task;
task.handler = callback;
task.interval = delay;
task.lastCall = std::chrono::high_resolution_clock::now();
Pipelines[type].add(std::move(task));
}
void Scheduler::Loop(const std::function<void()>& callback, const Pipeline type,
const std::chrono::milliseconds delay)
{
Schedule([callback]
{
callback();
return COND_CONTINUE;
}, type, delay);
}
void Scheduler::Once(const std::function<void()>& callback, const Pipeline type,
const std::chrono::milliseconds delay)
2017-05-31 10:09:41 -04:00
{
Schedule([callback]
{
callback();
return COND_END;
}, type, delay);
2017-05-31 10:09:41 -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
{
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
}
void Scheduler::OnGameShutdown(const std::function<void()>& callback)
2017-07-03 09:07:47 -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
Scheduler::Scheduler()
{
Thread = Utils::Thread::createNamedThread("Async Scheduler", []
2017-07-03 09:07:47 -04:00
{
while (!Kill)
2017-07-03 09:07:47 -04:00
{
Execute(Pipeline::ASYNC);
std::this_thread::sleep_for(10ms);
}
});
2017-07-03 09:07:47 -04:00
Utils::Hook(0x4DBE9A, REndFrame_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x518D5C, REndFrame_Hk, HOOK_CALL).install()->quick();
Utils::Hook(0x5ACBA3, REndFrame_Hk, HOOK_CALL).install()->quick();
// 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
// CL_CheckTimeout
Utils::Hook(0x4B0F81, ClientFrame_Hk, HOOK_CALL).install()->quick();
2017-05-31 10:09:41 -04:00
// Com_Frame_Try_Block_Function
Utils::Hook(0x4B724F, MainFrame_Hk, HOOK_CALL).install()->quick();
2017-07-03 09:07:47 -04:00
// Sys_Quit
Utils::Hook(0x4D697A, SysSetBlockSystemHotkeys_Hk, HOOK_CALL).install()->quick();
}
2017-07-03 09:07:47 -04:00
void Scheduler::preDestroy()
{
Kill = true;
if (Thread.joinable())
2017-07-03 09:07:47 -04:00
{
Thread.join();
2017-07-03 09:07:47 -04:00
}
}
}