#include "STDInclude.hpp" namespace Components { bool Scheduler::AsyncTerminate; std::thread Scheduler::AsyncThread; bool Scheduler::ReadyPassed = false; Utils::Signal Scheduler::ReadySignal; Utils::Signal Scheduler::ShutdownSignal; Utils::Signal Scheduler::FrameSignal; Utils::Signal Scheduler::FrameOnceSignal; std::vector Scheduler::DelayedSlots; Utils::Signal Scheduler::AsyncFrameSignal; Utils::Signal Scheduler::AsyncFrameOnceSignal; void Scheduler::Once(Utils::Slot callback, bool clientOnly) { if (clientOnly && (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())) return; Scheduler::FrameOnceSignal.connect(callback); } void Scheduler::OnShutdown(Utils::Slot callback) { Scheduler::ShutdownSignal.connect(callback); } void Scheduler::OnFrame(Utils::Slot callback, bool clientOnly) { if (clientOnly && (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())) return; Scheduler::FrameSignal.connect(callback); } void Scheduler::OnReady(Utils::Slot callback, bool clientOnly) { if (clientOnly && (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())) return; if (Scheduler::ReadyPassed) Scheduler::Once(callback); else Scheduler::ReadySignal.connect(callback); } void Scheduler::ReadyHandler() { if (!FastFiles::Ready()) { Scheduler::Once(Scheduler::ReadyHandler); } else { Scheduler::ReadyPassed = true; Scheduler::ReadySignal(); Scheduler::ReadySignal.clear(); } } void Scheduler::FrameHandler() { Scheduler::DelaySignal(); Scheduler::FrameSignal(); Utils::Signal copy(Scheduler::FrameOnceSignal); Scheduler::FrameOnceSignal.clear(); copy(); } void Scheduler::OnDelay(Utils::Slot callback, std::chrono::nanoseconds delay, bool clientOnly) { if (clientOnly && (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())) return; Scheduler::DelayedSlot slot; slot.callback = callback; slot.delay = delay; Scheduler::DelayedSlots.push_back(slot); } void Scheduler::DelaySignal() { Utils::Signal signal; for (auto i = Scheduler::DelayedSlots.begin(); i != Scheduler::DelayedSlots.end();) { if (i->interval.elapsed(i->delay)) { signal.connect(i->callback); i = Scheduler::DelayedSlots.erase(i); continue; } ++i; } signal(); } void Scheduler::ShutdownStub(int num) { Scheduler::ShutdownSignal(); Utils::Hook::Call(0x46B370)(num); } void Scheduler::OnFrameAsync(Utils::Slot callback) { Scheduler::AsyncFrameSignal.connect(callback); } void Scheduler::OnceAsync(Utils::Slot callback) { Scheduler::AsyncFrameOnceSignal.connect(callback); } Scheduler::Scheduler() { Scheduler::ReadyPassed = false; Scheduler::Once(Scheduler::ReadyHandler); Utils::Hook(0x4D697A, Scheduler::ShutdownStub, HOOK_CALL).install()->quick(); if (!Loader::IsPerformingUnitTests()) { Scheduler::AsyncTerminate = false; Scheduler::AsyncThread = std::thread([]() { while (!Scheduler::AsyncTerminate) { Scheduler::AsyncFrameSignal(); Utils::Signal copy(Scheduler::AsyncFrameOnceSignal); Scheduler::AsyncFrameOnceSignal.clear(); copy(); std::this_thread::sleep_for(16ms); } }); } } Scheduler::~Scheduler() { Scheduler::ReadySignal.clear(); Scheduler::ShutdownSignal.clear(); Scheduler::FrameSignal.clear(); Scheduler::FrameOnceSignal.clear(); Scheduler::DelayedSlots.clear(); Scheduler::AsyncFrameSignal.clear(); Scheduler::AsyncFrameOnceSignal.clear(); Scheduler::ReadyPassed = false; } void Scheduler::preDestroy() { Scheduler::AsyncTerminate = true; if (Scheduler::AsyncThread.joinable()) { Scheduler::AsyncThread.join(); } } }