Update nemirtingas overlay to latest.

This commit is contained in:
Mr_Goldberg 2022-08-21 03:43:24 -04:00
parent 97a1ff5186
commit de6805dd8b
No known key found for this signature in database
GPG key ID: 8597D87419DEF278
3 changed files with 362 additions and 439 deletions

View file

@ -26,33 +26,38 @@
#include "System/System.h" #include "System/System.h"
#include "System/Library.h" #include "System/Library.h"
#include "System/ScopedLock.hpp" #include "System/ScopedLock.hpp"
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) \ #if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) \
|| defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
#define RENDERERDETECTOR_OS_WINDOWS #define RENDERERDETECTOR_OS_WINDOWS
#include "windows/DX12_Hook.h"
#include "windows/DX11_Hook.h"
#include "windows/DX10_Hook.h"
#include "windows/DX9_Hook.h"
#include "windows/OpenGL_Hook.h"
#include "windows/Vulkan_Hook.h"
#include "windows/DirectX_VTables.h"
#include <random>
#ifdef GetModuleHandle
#undef GetModuleHandle
#endif
#elif defined(__linux__) || defined(linux) #elif defined(__linux__) || defined(linux)
#define RENDERERDETECTOR_OS_LINUX #define RENDERERDETECTOR_OS_LINUX
#include "linux/OpenGLX_Hook.h"
#elif defined(__APPLE__) #elif defined(__APPLE__)
#define RENDERERDETECTOR_OS_APPLE #define RENDERERDETECTOR_OS_APPLE
#endif
#ifdef RENDERERDETECTOR_OS_WINDOWS #include "macosx/OpenGL_Hook.h"
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#include "windows/DX12_Hook.h"
#include "windows/DX11_Hook.h"
#include "windows/DX10_Hook.h"
#include "windows/DX9_Hook.h"
#include "windows/OpenGL_Hook.h"
#include "windows/Vulkan_Hook.h"
#include "windows/DirectX_VTables.h"
#include <random>
#ifdef GetModuleHandle
#undef GetModuleHandle
#endif #endif
class Renderer_Detector class Renderer_Detector
@ -68,63 +73,29 @@ public:
return instance; return instance;
} }
static void deleteInst() #if defined(RENDERERDETECTOR_OS_WINDOWS)
{ #define RENDERER_HOOKS { OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl },\
if (instance != nullptr) { Vulkan_Hook::DLL_NAME, &Renderer_Detector::hook_vulkan },\
{ { DX12_Hook::DLL_NAME, &Renderer_Detector::hook_dx12 },\
delete instance; { DX11_Hook::DLL_NAME, &Renderer_Detector::hook_dx11 },\
instance = nullptr; { DX10_Hook::DLL_NAME, &Renderer_Detector::hook_dx10 },\
} { DX9_Hook::DLL_NAME, &Renderer_Detector::hook_dx9 },
}
~Renderer_Detector() ~Renderer_Detector()
{ {
stop_detection();
delete dx9_hook; delete dx9_hook;
delete dx10_hook; delete dx10_hook;
delete dx11_hook; delete dx11_hook;
delete dx12_hook; delete dx12_hook;
delete opengl_hook; delete opengl_hook;
delete vulkan_hook; delete vulkan_hook;
instance = nullptr;
} }
private: private:
Renderer_Detector():
dxgi_hooked(false),
dxgi1_2_hooked(false),
dx12_hooked(false),
dx11_hooked(false),
dx10_hooked(false),
dx9_hooked(false),
opengl_hooked(false),
vulkan_hooked(false),
renderer_hook(nullptr),
dx9_hook(nullptr),
dx10_hook(nullptr),
dx11_hook(nullptr),
dx12_hook(nullptr),
opengl_hook(nullptr),
vulkan_hook(nullptr),
detection_done(false),
force_done(false)
{
std::wstring tmp(4096, L'\0');
tmp.resize(GetSystemDirectoryW(&tmp[0], tmp.size()));
_SystemDir = System::Encoding::WCharToUtf8(tmp);
System::String::ToLower(_SystemDir);
wchar_t random_str[] = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dis(0, 61);
_WindowClassName.resize(64);
for (int i = 0; i < 64; ++i)
_WindowClassName[i] = random_str[dis(gen)];
}
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
decltype(&IDXGISwapChain::Present) IDXGISwapChainPresent; decltype(&IDXGISwapChain::Present) IDXGISwapChainPresent;
decltype(&IDXGISwapChain1::Present1) IDXGISwapChainPresent1; decltype(&IDXGISwapChain1::Present1) IDXGISwapChainPresent1;
@ -143,8 +114,6 @@ private:
bool opengl_hooked; bool opengl_hooked;
bool vulkan_hooked; bool vulkan_hooked;
Base_Hook detection_hooks;
ingame_overlay::Renderer_Hook* renderer_hook;
DX12_Hook* dx12_hook; DX12_Hook* dx12_hook;
DX11_Hook* dx11_hook; DX11_Hook* dx11_hook;
DX10_Hook* dx10_hook; DX10_Hook* dx10_hook;
@ -152,15 +121,47 @@ private:
OpenGL_Hook* opengl_hook; OpenGL_Hook* opengl_hook;
Vulkan_Hook* vulkan_hook; Vulkan_Hook* vulkan_hook;
bool detection_done, force_done;
std::condition_variable stop_detection_cv;
std::mutex stop_detection_mutex;
HWND dummyWindow = nullptr; HWND dummyWindow = nullptr;
std::wstring _WindowClassName; std::wstring _WindowClassName;
std::string _SystemDir; std::string _SystemDir;
ATOM atom = 0; ATOM atom = 0;
Renderer_Detector() :
dxgi_hooked(false),
dxgi1_2_hooked(false),
dx12_hooked(false),
dx11_hooked(false),
dx10_hooked(false),
dx9_hooked(false),
opengl_hooked(false),
vulkan_hooked(false),
renderer_hook(nullptr),
dx9_hook(nullptr),
dx10_hook(nullptr),
dx11_hook(nullptr),
dx12_hook(nullptr),
opengl_hook(nullptr),
vulkan_hook(nullptr),
detection_done(false),
detection_count(0),
detection_cancelled(false)
{
std::wstring tmp(4096, L'\0');
tmp.resize(GetSystemDirectoryW(&tmp[0], tmp.size()));
_SystemDir = System::Encoding::WCharToUtf8(tmp);
System::String::ToLower(_SystemDir);
wchar_t random_str[] = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dis(0, 61);
_WindowClassName.resize(64);
for (int i = 0; i < 64; ++i)
_WindowClassName[i] = random_str[dis(gen)];
}
std::string FindPreferedModulePath(std::string const& name) std::string FindPreferedModulePath(std::string const& name)
{ {
std::string res; std::string res;
@ -982,7 +983,8 @@ private:
phyDevices.resize(count); phyDevices.resize(count);
vkEnumeratePhysicalDevices(instance, &count, phyDevices.data()); vkEnumeratePhysicalDevices(instance, &count, phyDevices.data());
[&]() { [&]()
{// Lambda for nested for break.
VkPhysicalDeviceProperties props{}; VkPhysicalDeviceProperties props{};
std::vector<VkExtensionProperties> ext_props; std::vector<VkExtensionProperties> ext_props;
@ -1005,7 +1007,7 @@ private:
const char* str = "VK_KHR_swapchain"; const char* str = "VK_KHR_swapchain";
create_info.ppEnabledExtensionNames = &str; create_info.ppEnabledExtensionNames = &str;
vkCreateDevice(device, &create_info, nullptr, &pDevice); vkCreateDevice(device, &create_info, nullptr, &pDevice);
if(pDevice != nullptr) if (pDevice != nullptr)
return; return;
} }
} }
@ -1041,65 +1043,13 @@ private:
} }
} }
public: bool EnterDetection()
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
{ {
std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock); return CreateHWND() != nullptr;
if (!detection_lock.try_lock_for(timeout))
return nullptr;
{
std::lock_guard<std::mutex> lk(renderer_mutex);
if (detection_done)
{
if (renderer_hook != nullptr || force_done)
return renderer_hook;
detection_done = false;
} }
if (CreateHWND() == nullptr) void ExitDetection()
{ {
return nullptr;
}
}
SPDLOG_TRACE("Started renderer detection.");
std::pair<std::string, void(Renderer_Detector::*)(std::string const&)> libraries[]{
{OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl},
{Vulkan_Hook::DLL_NAME, &Renderer_Detector::hook_vulkan},
{ DX12_Hook::DLL_NAME, &Renderer_Detector::hook_dx12 },
{ DX11_Hook::DLL_NAME, &Renderer_Detector::hook_dx11 },
{ DX10_Hook::DLL_NAME, &Renderer_Detector::hook_dx10 },
{ DX9_Hook::DLL_NAME, &Renderer_Detector::hook_dx9 },
};
std::string name;
auto start_time = std::chrono::steady_clock::now();
do
{
std::unique_lock<std::mutex> lck(stop_detection_mutex);
if (detection_done)
break;
for (auto const& library : libraries)
{
void* lib_handle = System::Library::GetLibraryHandle(library.first.c_str());
if (lib_handle != nullptr)
{
std::lock_guard<std::mutex> lk(renderer_mutex);
name = FindPreferedModulePath(library.first);
(this->*library.second)(name);
}
}
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (!detection_done && (timeout.count() == -1 || (std::chrono::steady_clock::now() - start_time) <= timeout));
{
std::lock_guard<std::mutex> lk(renderer_mutex);
DestroyHWND(); DestroyHWND();
detection_done = true; detection_done = true;
@ -1122,74 +1072,42 @@ public:
delete vulkan_hook; vulkan_hook = nullptr; delete vulkan_hook; vulkan_hook = nullptr;
} }
SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
return renderer_hook;
}
void stop_detection()
{
{
System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_done = true;
force_done = true;
}
stop_detection_cv.notify_all();
}
};
Renderer_Detector* Renderer_Detector::instance = nullptr;
#elif defined(RENDERERDETECTOR_OS_LINUX) #elif defined(RENDERERDETECTOR_OS_LINUX)
#define GLAD_GL_IMPLEMENTATION #define RENDERER_HOOKS { OpenGLX_Hook::DLL_NAME, &Renderer_Detector::hook_openglx },
#include <glad/gl.h>
#include "linux/OpenGLX_Hook.h"
class Renderer_Detector
{
static Renderer_Detector* instance;
public:
static Renderer_Detector* Inst()
{
if (instance == nullptr)
{
instance = new Renderer_Detector;
}
return instance;
}
~Renderer_Detector() ~Renderer_Detector()
{ {
stop_detection();
delete openglx_hook; delete openglx_hook;
//delete vulkan_hook; //delete vulkan_hook;
instance = nullptr;
} }
private: private:
Renderer_Detector() :
openglx_hooked(false),
renderer_hook(nullptr),
openglx_hook(nullptr),
//vulkan_hook(nullptr),
detection_done(false)
{}
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
Base_Hook detection_hooks;
decltype(::glXSwapBuffers)* glXSwapBuffers; decltype(::glXSwapBuffers)* glXSwapBuffers;
bool openglx_hooked; bool openglx_hooked;
//bool vulkan_hooked; //bool vulkan_hooked;
ingame_overlay::Renderer_Hook* renderer_hook;
OpenGLX_Hook* openglx_hook; OpenGLX_Hook* openglx_hook;
//Vulkan_Hook* vulkan_hook;
bool detection_done; Renderer_Detector() :
std::condition_variable stop_detection_cv; openglx_hooked(false),
std::mutex stop_detection_mutex; renderer_hook(nullptr),
openglx_hook(nullptr),
//vulkan_hook(nullptr),
detection_done(false),
detection_count(0),
detection_cancelled(false)
{}
std::string FindPreferedModulePath(std::string const& name)
{
return name;
}
static void MyglXSwapBuffers(Display* dpy, GLXDrawable drawable) static void MyglXSwapBuffers(Display* dpy, GLXDrawable drawable)
{ {
@ -1248,128 +1166,57 @@ private:
} }
} }
public: bool EnterDetection()
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
{ {
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)> libraries[]{ return true;
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)>{OpenGLX_Hook::DLL_NAME, &Renderer_Detector::hook_openglx},
};
std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock);
if (!detection_lock.try_lock_for(timeout))
return nullptr;
{
std::lock_guard<std::mutex> lk(renderer_mutex);
if (detection_done)
{
if (renderer_hook != nullptr || force_done)
return renderer_hook;
detection_done = false;
}
} }
SPDLOG_TRACE("Started renderer detection."); void ExitDetection()
auto start_time = std::chrono::steady_clock::now();
do
{ {
std::unique_lock<std::mutex> lck(stop_detection_mutex);
if (detection_done)
break;
for (auto const& library : libraries)
{
void* lib_handle = System::Library::GetLibraryHandle(library.first);
if (lib_handle != nullptr)
{
std::lock_guard<std::mutex> lk(renderer_mutex);
std::string lib_path = System::Library::GetLibraryPath(lib_handle);
(this->*library.second)(lib_path);
}
}
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (!detection_done && (timeout.count() == -1 || (std::chrono::steady_clock::now() - start_time) <= timeout));
{
std::lock_guard<std::mutex> lk(renderer_mutex);
detection_done = true; detection_done = true;
detection_hooks.UnhookAll(); detection_hooks.UnhookAll();
openglx_hooked = false; openglx_hooked = false;
//vulkan_hooked = false;
delete openglx_hook; openglx_hook = nullptr; delete openglx_hook; openglx_hook = nullptr;
//delete vulkan_hook; vulkan_hook = nullptr; //delete vulkan_hook; vulkan_hook = nullptr;
} }
SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
return renderer_hook;
}
void stop_detection()
{
{
System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_done = true;
force_done = true;
}
stop_detection_cv.notify_all();
}
};
Renderer_Detector* Renderer_Detector::instance = nullptr;
#elif defined(RENDERERDETECTOR_OS_APPLE) #elif defined(RENDERERDETECTOR_OS_APPLE)
#include "macosx/OpenGL_Hook.h" #define RENDERER_HOOKS { OpenGL_Hook::DLL_NAME, & Renderer_Detector::hook_opengl },
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
class Renderer_Detector
{
static Renderer_Detector* instance;
public:
static Renderer_Detector* Inst()
{
if (instance == nullptr)
{
instance = new Renderer_Detector;
}
return instance;
}
~Renderer_Detector() ~Renderer_Detector()
{ {
stop_detection();
delete opengl_hook; delete opengl_hook;
instance = nullptr;
} }
private: private:
Renderer_Detector():
opengl_hooked(false),
renderer_hook(nullptr),
opengl_hook(nullptr),
detection_done(false)
{}
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
Base_Hook detection_hooks;
decltype(::CGLFlushDrawable)* CGLFlushDrawable; decltype(::CGLFlushDrawable)* CGLFlushDrawable;
bool opengl_hooked; bool opengl_hooked;
//bool metal_hooked;
ingame_overlay::Renderer_Hook* renderer_hook;
OpenGL_Hook* opengl_hook; OpenGL_Hook* opengl_hook;
//Metal_Hook* metal_hook;
bool detection_done; Renderer_Detector() :
std::condition_variable stop_detection_cv; opengl_hooked(false),
std::mutex stop_detection_mutex; renderer_hook(nullptr),
opengl_hook(nullptr),
detection_done(false),
detection_count(0),
detection_cancelled(false)
{}
std::string FindPreferedModulePath(std::string const& name)
{
return name;
}
static int64_t MyCGLFlushDrawable(CGLDrawable_t* glDrawable) static int64_t MyCGLFlushDrawable(CGLDrawable_t* glDrawable)
{ {
@ -1428,89 +1275,164 @@ private:
} }
} }
public: bool EnterDetection()
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
{ {
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)> libraries[]{ return true;
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)>{OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl} }
};
void ExitDetection()
{
detection_done = true;
detection_hooks.UnhookAll();
opengl_hooked = false;
//metal_hooked = false;
delete opengl_hook; opengl_hook = nullptr;
//delete metal_hook; metal_hook = nullptr;
}
#endif
private:
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
Base_Hook detection_hooks;
ingame_overlay::Renderer_Hook* renderer_hook;
bool detection_done;
uint32_t detection_count;
bool detection_cancelled;
std::condition_variable stop_detection_cv;
std::mutex stop_detection_mutex;
public:
std::future<ingame_overlay::Renderer_Hook*> detect_renderer(std::chrono::milliseconds timeout)
{
std::lock_guard<std::mutex> lk(stop_detection_mutex);
if (detection_count == 0)
{// If we have no detections in progress, restart detection.
detection_cancelled = false;
}
++detection_count;
return std::async(std::launch::async, [this, timeout]() -> ingame_overlay::Renderer_Hook*
{
std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock); std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock);
constexpr std::chrono::milliseconds infinite_timeout{ -1 };
if (!detection_lock.try_lock_for(timeout)) if (!detection_lock.try_lock_for(timeout))
return nullptr; return nullptr;
bool cancel = false;
{
System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
if (!detection_cancelled)
{ {
std::lock_guard<std::mutex> lk(renderer_mutex);
if (detection_done) if (detection_done)
{ {
if (renderer_hook != nullptr || force_done) if (renderer_hook == nullptr)
return renderer_hook; {// Renderer detection was run but we didn't find it, restart the detection
detection_done = false; detection_done = false;
} }
else
{// Renderer already detected, cancel detection and return the renderer.
cancel = true;
}
}
if (!EnterDetection())
cancel = true;
}
else
{// Detection was cancelled, cancel this detection
cancel = true;
}
}
if (cancel)
{
--detection_count;
stop_detection_cv.notify_all();
return renderer_hook;
} }
SPDLOG_TRACE("Started renderer detection."); SPDLOG_TRACE("Started renderer detection.");
std::pair<std::string, void(Renderer_Detector::*)(std::string const&)> libraries[]{
RENDERER_HOOKS
};
std::string name;
auto start_time = std::chrono::steady_clock::now(); auto start_time = std::chrono::steady_clock::now();
do do
{ {
std::unique_lock<std::mutex> lck(stop_detection_mutex); std::unique_lock<std::mutex> lck(stop_detection_mutex);
if (detection_done) if (detection_cancelled || detection_done)
break; break;
for (auto const& library : libraries) for (auto const& library : libraries)
{ {
void* lib_handle = System::Library::GetLibraryHandle(library.first); std::string lib_path = FindPreferedModulePath(library.first);
if (!lib_path.empty())
{
void* lib_handle = System::Library::GetLibraryHandle(lib_path.c_str());
if (lib_handle != nullptr) if (lib_handle != nullptr)
{ {
std::lock_guard<std::mutex> lk(renderer_mutex); std::lock_guard<std::mutex> lk(renderer_mutex);
std::string lib_path = System::Library::GetLibraryPath(lib_handle); (this->*library.second)(System::Library::GetLibraryPath(lib_handle));
(this->*library.second)(lib_path); }
} }
} }
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 }); stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (!detection_done && (timeout.count() == -1 || (std::chrono::steady_clock::now() - start_time) <= timeout)); } while (timeout == infinite_timeout || (std::chrono::steady_clock::now() - start_time) <= timeout);
{ {
std::lock_guard<std::mutex> lk(renderer_mutex); System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_done = true; ExitDetection();
detection_hooks.UnhookAll();
opengl_hooked = false; --detection_count;
delete opengl_hook; opengl_hook = nullptr;
//delete vulkan_hook; vulkan_hook = nullptr;
} }
stop_detection_cv.notify_all();
SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook); SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
return renderer_hook; return renderer_hook;
});
} }
void stop_detection() void stop_detection()
{ {
{
std::lock_guard<std::mutex> lk(stop_detection_mutex);
if (detection_count == 0)
return;
}
{ {
System::scoped_lock lk(renderer_mutex, stop_detection_mutex); System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_done = true; detection_cancelled = true;
force_done = true;
} }
stop_detection_cv.notify_all(); stop_detection_cv.notify_all();
{
std::unique_lock<std::mutex> lk(stop_detection_mutex);
stop_detection_cv.wait(lk, [&]() { return detection_count == 0; });
}
} }
}; };
Renderer_Detector* Renderer_Detector::instance = nullptr; Renderer_Detector* Renderer_Detector::instance = nullptr;
#endif
namespace ingame_overlay { namespace ingame_overlay {
std::future<ingame_overlay::Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout) std::future<ingame_overlay::Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout)
{ {
return std::async(std::launch::async, &Renderer_Detector::detect_renderer, Renderer_Detector::Inst(), timeout); return Renderer_Detector::Inst()->detect_renderer(timeout);
} }
void StopRendererDetection() void StopRendererDetection()
@ -1518,9 +1440,9 @@ void StopRendererDetection()
Renderer_Detector::Inst()->stop_detection(); Renderer_Detector::Inst()->stop_detection();
} }
void FreeRendererDetection() void FreeDetector()
{ {
Renderer_Detector::deleteInst(); delete Renderer_Detector::Inst();
} }
} }

View file

@ -31,5 +31,6 @@ namespace ingame_overlay {
std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{ -1 }); std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{ -1 });
void StopRendererDetection(); void StopRendererDetection();
void FreeRendererDetection(); void FreeDetector();
} }

View file

@ -207,7 +207,7 @@ void Steam_Overlay::UnSetupOverlay()
if (!Ready() && future_renderer.valid()) { if (!Ready() && future_renderer.valid()) {
if (future_renderer.wait_for(std::chrono::milliseconds{500}) == std::future_status::ready) { if (future_renderer.wait_for(std::chrono::milliseconds{500}) == std::future_status::ready) {
future_renderer.get(); future_renderer.get();
ingame_overlay::FreeRendererDetection(); ingame_overlay::FreeDetector();
} }
} }
} }