Refactor the component system

This commit is contained in:
momo5502 2022-11-11 17:00:34 +01:00
parent 13be8f3894
commit ef39098e28
10 changed files with 286 additions and 302 deletions

View File

@ -757,9 +757,9 @@ namespace arxan
//restore_debug_functions(); //restore_debug_functions();
} }
int priority() override component_priority priority() const override
{ {
return 9999; return component_priority::arxan;
} }
private: private:

View File

@ -444,7 +444,7 @@ namespace demonware
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void pre_load() override component()
{ {
udp_servers.create<stun_server>("stun.us.demonware.net"); udp_servers.create<stun_server>("stun.us.demonware.net");
udp_servers.create<stun_server>("stun.eu.demonware.net"); udp_servers.create<stun_server>("stun.eu.demonware.net");

View File

@ -196,7 +196,7 @@ namespace exception
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void pre_load() override component()
{ {
main_thread_id = GetCurrentThreadId(); main_thread_id = GetCurrentThreadId();
SetUnhandledExceptionFilter(exception_filter); SetUnhandledExceptionFilter(exception_filter);

View File

@ -10,7 +10,9 @@ namespace splash
namespace namespace
{ {
HWND window{}; HWND window{};
HANDLE image{};
std::thread window_thread{}; std::thread window_thread{};
std::atomic_bool join_safe{false};
HANDLE load_splash_image() HANDLE load_splash_image()
{ {
@ -51,53 +53,73 @@ namespace splash
window_thread.detach(); window_thread.detach();
} }
} }
void show()
{
WNDCLASSA wnd_class;
const auto self = utils::nt::library::get_by_address(load_splash_image);
wnd_class.style = CS_DROPSHADOW;
wnd_class.cbClsExtra = 0;
wnd_class.cbWndExtra = 0;
wnd_class.lpszMenuName = nullptr;
wnd_class.lpfnWndProc = DefWindowProcA;
wnd_class.hInstance = self;
wnd_class.hIcon = LoadIconA(self, MAKEINTRESOURCEA(ID_ICON));
wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING);
wnd_class.hbrBackground = reinterpret_cast<HBRUSH>(6);
wnd_class.lpszClassName = "Black Ops III Splash Screen";
if (RegisterClassA(&wnd_class))
{
const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN);
const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN);
if (image)
{
window = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII",
WS_POPUP | WS_SYSMENU,
(x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr,
nullptr,
self, nullptr);
if (window)
{
auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu,
0, 0,
320, 100, window, nullptr, self, nullptr);
if (image_window)
{
RECT rect;
SendMessageA(image_window, 0x172u, 0, reinterpret_cast<LPARAM>(image));
GetWindowRect(image_window, &rect);
const int width = rect.right - rect.left;
rect.left = (x_pixels - width) / 2;
const int height = rect.bottom - rect.top;
rect.top = (y_pixels - height) / 2;
rect.right = rect.left + width;
rect.bottom = rect.top + height;
AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0);
SetWindowPos(window, nullptr, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_NOZORDER);
SetWindowRgn(window,
CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15,
15), TRUE);
ShowWindow(window, SW_SHOW);
UpdateWindow(window);
}
} }
class component final : public component_interface
{
public:
void pre_load() override
{
this->image_ = load_splash_image();
enable_dpi_awareness();
window_thread = std::thread([this]
{
this->draw();
});
} }
void pre_destroy() override
{
destroy_window();
if (window_thread.joinable())
{
window_thread.detach();
} }
} }
void post_unpack() override bool draw_frame()
{
destroy_window();
}
private:
std::atomic_bool join_safe_{false};
HANDLE image_{};
void draw()
{
this->show();
while (this->draw_frame())
{
std::this_thread::sleep_for(1ms);
}
window = nullptr;
UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{});
}
bool draw_frame() const
{ {
if (!window) if (!window)
{ {
@ -125,69 +147,45 @@ namespace splash
return success; return success;
} }
void show() void draw()
{ {
WNDCLASSA wnd_class; show();
while (draw_frame())
const auto self = utils::nt::library::get_by_address(load_splash_image);
wnd_class.style = CS_DROPSHADOW;
wnd_class.cbClsExtra = 0;
wnd_class.cbWndExtra = 0;
wnd_class.lpszMenuName = nullptr;
wnd_class.lpfnWndProc = DefWindowProcA;
wnd_class.hInstance = self;
wnd_class.hIcon = LoadIconA(self, MAKEINTRESOURCEA(ID_ICON));
wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING);
wnd_class.hbrBackground = reinterpret_cast<HBRUSH>(6);
wnd_class.lpszClassName = "Black Ops III Splash Screen";
if (RegisterClassA(&wnd_class))
{ {
const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN); std::this_thread::sleep_for(1ms);
const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN); }
if (image_) window = nullptr;
{ UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{});
window = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII",
WS_POPUP | WS_SYSMENU,
(x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr,
nullptr,
self, nullptr);
if (window)
{
auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu,
0, 0,
320, 100, window, nullptr, self, nullptr);
if (image_window)
{
RECT rect;
SendMessageA(image_window, 0x172u, 0, reinterpret_cast<LPARAM>(image_));
GetWindowRect(image_window, &rect);
const int width = rect.right - rect.left;
rect.left = (x_pixels - width) / 2;
const int height = rect.bottom - rect.top;
rect.top = (y_pixels - height) / 2;
rect.right = rect.left + width;
rect.bottom = rect.top + height;
AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0);
SetWindowPos(window, nullptr, rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_NOZORDER);
SetWindowRgn(window,
CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15,
15), TRUE);
ShowWindow(window, SW_SHOW);
UpdateWindow(window);
} }
} }
class component final : public component_interface
{
public:
component()
{
enable_dpi_awareness();
image = load_splash_image();
window_thread = std::thread([this]
{
draw();
});
}
void pre_destroy() override
{
destroy_window();
if (window_thread.joinable())
{
window_thread.detach();
} }
} }
void post_unpack() override
{
destroy_window();
} }
}; };

View File

@ -235,9 +235,9 @@ namespace steam_proxy
} }
} }
int priority() override component_priority priority() const override
{ {
return 998; // Run after the updater return component_priority::steam_proxy;
} }
}; };

View File

@ -130,7 +130,7 @@ namespace updater
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void pre_load() override component()
{ {
cleanup_update(); cleanup_update();
@ -150,9 +150,9 @@ namespace updater
join(); join();
} }
int priority() override component_priority priority() const override
{ {
return 999; return component_priority::updater;
} }
private: private:

View File

@ -1,14 +1,20 @@
#pragma once #pragma once
enum class component_priority
{
min = 0,
// must run after the updater
steam_proxy,
updater,
// must have the highest priority
arxan,
};
class component_interface class component_interface
{ {
public: public:
virtual ~component_interface() = default; virtual ~component_interface() = default;
virtual void pre_load()
{
}
virtual void post_load() virtual void post_load()
{ {
} }
@ -21,13 +27,8 @@ public:
{ {
} }
virtual bool is_supported() virtual component_priority priority() const
{ {
return true; return component_priority::min;
}
virtual int priority()
{
return 0;
} }
}; };

View File

@ -3,10 +3,36 @@
#include <utils/nt.hpp> #include <utils/nt.hpp>
void component_loader::register_component(std::unique_ptr<component_interface>&& component_) namespace component_loader
{
namespace
{
std::vector<std::unique_ptr<component_interface>>& get_components()
{
using component_vector = std::vector<std::unique_ptr<component_interface>>;
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>
;
static component_vector_container components(new component_vector,
[](const component_vector* component_vector)
{
pre_destroy();
delete component_vector;
});
return *components;
}
std::vector<registration_functor>& get_registration_functors()
{
static std::vector<registration_functor> functors;
return functors;
}
void activate_component(std::unique_ptr<component_interface> component)
{ {
auto& components = get_components(); auto& components = get_components();
components.push_back(std::move(component_)); components.push_back(std::move(component));
std::ranges::stable_sort(components, [](const std::unique_ptr<component_interface>& a, std::ranges::stable_sort(components, [](const std::unique_ptr<component_interface>& a,
const std::unique_ptr<component_interface>& b) const std::unique_ptr<component_interface>& b)
@ -14,18 +40,27 @@ void component_loader::register_component(std::unique_ptr<component_interface>&&
return a->priority() > b->priority(); return a->priority() > b->priority();
}); });
} }
}
bool component_loader::pre_load() void register_component(registration_functor functor)
{
if (!get_components().empty())
{
throw std::runtime_error("Registration is too late");
}
get_registration_functors().push_back(std::move(functor));
}
bool activate()
{ {
static auto res = [] static auto res = []
{ {
clean();
try try
{ {
for (const auto& component_ : get_components()) for (auto& functor : get_registration_functors())
{ {
component_->pre_load(); activate_component(functor());
} }
} }
catch (premature_shutdown_trigger&) catch (premature_shutdown_trigger&)
@ -34,7 +69,7 @@ bool component_loader::pre_load()
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
return false; return false;
} }
@ -44,17 +79,15 @@ bool component_loader::pre_load()
return res; return res;
} }
bool component_loader::post_load() bool post_load()
{ {
static auto res = [] static auto res = []
{ {
clean();
try try
{ {
for (const auto& component_ : get_components()) for (const auto& component : get_components())
{ {
component_->post_load(); component->post_load();
} }
} }
catch (premature_shutdown_trigger&) catch (premature_shutdown_trigger&)
@ -63,7 +96,7 @@ bool component_loader::post_load()
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
return false; return false;
} }
@ -73,22 +106,20 @@ bool component_loader::post_load()
return res; return res;
} }
void component_loader::post_unpack() void post_unpack()
{ {
static auto res = [] static auto res = []
{ {
clean();
try try
{ {
for (const auto& component_ : get_components()) for (const auto& component : get_components())
{ {
component_->post_unpack(); component->post_unpack();
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
return false; return false;
} }
@ -101,22 +132,20 @@ void component_loader::post_unpack()
} }
} }
void component_loader::pre_destroy() void pre_destroy()
{ {
static auto res = [] static auto res = []
{ {
clean();
try try
{ {
for (const auto& component_ : get_components()) for (const auto& component : get_components())
{ {
component_->pre_destroy(); component->pre_destroy();
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
return false; return false;
} }
@ -129,40 +158,10 @@ void component_loader::pre_destroy()
} }
} }
void component_loader::clean() void trigger_premature_shutdown()
{
auto& components = get_components();
for (auto i = components.begin(); i != components.end();)
{
if (!(*i)->is_supported())
{
(*i)->pre_destroy();
i = components.erase(i);
}
else
{
++i;
}
}
}
void component_loader::trigger_premature_shutdown()
{ {
throw premature_shutdown_trigger(); throw premature_shutdown_trigger();
} }
std::vector<std::unique_ptr<component_interface>>& component_loader::get_components()
{
using component_vector = std::vector<std::unique_ptr<component_interface>>;
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
static component_vector_container components(new component_vector, [](const component_vector* component_vector)
{
pre_destroy();
delete component_vector;
});
return *components;
} }
size_t get_base() size_t get_base()

View File

@ -1,9 +1,19 @@
#pragma once #pragma once
#include "component_interface.hpp" #include "component_interface.hpp"
class component_loader final namespace component_loader
{ {
public: using registration_functor = std::function<std::unique_ptr<component_interface>()>;
void register_component(registration_functor functor);
bool activate();
bool post_load();
void post_unpack();
void pre_destroy();
[[noreturn]] void trigger_premature_shutdown();
class premature_shutdown_trigger final : public std::exception class premature_shutdown_trigger final : public std::exception
{ {
[[nodiscard]] const char* what() const noexcept override [[nodiscard]] const char* what() const noexcept override
@ -20,36 +30,12 @@ public:
public: public:
installer() installer()
{ {
register_component(std::make_unique<T>()); register_component([]
{
return std::make_unique<T>();
});
} }
}; };
template <typename T>
static T* get()
{
for (const auto& component_ : get_components())
{
if (typeid(*component_.get()) == typeid(T))
{
return reinterpret_cast<T*>(component_.get());
}
}
return nullptr;
}
static void register_component(std::unique_ptr<component_interface>&& component);
static bool pre_load();
static bool post_load();
static void post_unpack();
static void pre_destroy();
static void clean();
static void trigger_premature_shutdown();
private:
static std::vector<std::unique_ptr<component_interface>>& get_components();
}; };
#define REGISTER_COMPONENT(name) \ #define REGISTER_COMPONENT(name) \

View File

@ -183,7 +183,7 @@ namespace
{ {
remove_crash_file(); remove_crash_file();
if (!component_loader::pre_load()) if (!component_loader::activate())
{ {
return 1; return 1;
} }