From 5740210e72801492e7a63515ea8b8ded81e97079 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 1 Oct 2022 11:08:42 +0200 Subject: [PATCH] Small refactoring --- src/client/component/splash.cpp | 117 +++---- src/client/component/steam_proxy.cpp | 444 +++++++++++++-------------- src/client/component/updater.cpp | 2 +- 3 files changed, 257 insertions(+), 306 deletions(-) diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp index b1eca502..bc2e4bed 100644 --- a/src/client/component/splash.cpp +++ b/src/client/component/splash.cpp @@ -9,6 +9,9 @@ namespace splash { namespace { + HWND window{}; + std::thread window_thread{}; + HANDLE load_splash_image() { const auto self = utils::nt::library::get_by_address(load_splash_image); @@ -27,6 +30,27 @@ namespace splash set_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); } } + + void destroy_window() + { + if (window && IsWindow(window)) + { + ShowWindow(window, SW_HIDE); + DestroyWindow(window); + window = nullptr; + + if (window_thread.joinable()) + { + window_thread.join(); + } + + window = nullptr; + } + else if (window_thread.joinable()) + { + window_thread.detach(); + } + } } class component final : public component_interface @@ -36,7 +60,7 @@ namespace splash : image_(load_splash_image()) { enable_dpi_awareness(); - this->window_thread_ = std::thread([this] + window_thread = std::thread([this] { this->draw(); }); @@ -44,64 +68,25 @@ namespace splash ~component() { - if (this->window_thread_.joinable()) + if (window_thread.joinable()) { - this->window_thread_.detach(); + window_thread.detach(); } } void pre_destroy() override { - this->destroy(); + destroy_window(); } void post_unpack() override { - this->destroy(); - } - - void hide() - { - if (this->window_ && IsWindow(this->window_)) - { - ShowWindow(this->window_, SW_HIDE); - UpdateWindow(this->window_); - } - - this->destroy(); - } - - HWND get_window() const - { - return this->window_; + destroy_window(); } private: std::atomic_bool join_safe_{false}; - HWND window_{}; HANDLE image_{}; - std::thread window_thread_{}; - - void destroy() - { - if (this->window_ && IsWindow(this->window_)) - { - ShowWindow(this->window_, SW_HIDE); - DestroyWindow(this->window_); - this->window_ = nullptr; - - if (this->window_thread_.joinable()) - { - this->window_thread_.join(); - } - - this->window_ = nullptr; - } - else if (this->window_thread_.joinable()) - { - this->window_thread_.detach(); - } - } void draw() { @@ -111,13 +96,13 @@ namespace splash std::this_thread::sleep_for(1ms); } - this->window_ = nullptr; + window = nullptr; UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{}); } bool draw_frame() const { - if (!this->window_) + if (!window) { return false; } @@ -130,7 +115,7 @@ namespace splash TranslateMessage(&msg); DispatchMessageW(&msg); - if (msg.message == WM_DESTROY && msg.hwnd == this->window_) + if (msg.message == WM_DESTROY && msg.hwnd == window) { PostQuitMessage(0); } @@ -167,17 +152,17 @@ namespace splash if (image_) { - this->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, - host, nullptr); + 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, + host, nullptr); - if (this->window_) + if (window) { auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, 0, 0, - 320, 100, this->window_, nullptr, host, nullptr); + 320, 100, window, nullptr, host, nullptr); if (image_window) { RECT rect; @@ -193,15 +178,15 @@ namespace splash rect.right = rect.left + width; rect.bottom = rect.top + height; AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0); - SetWindowPos(this->window_, nullptr, rect.left, rect.top, rect.right - rect.left, + SetWindowPos(window, nullptr, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); - SetWindowRgn(this->window_, + SetWindowRgn(window, CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15, 15), TRUE); - ShowWindow(this->window_, SW_SHOW); - UpdateWindow(this->window_); + ShowWindow(window, SW_SHOW); + UpdateWindow(window); } } } @@ -211,22 +196,18 @@ namespace splash void hide() { - auto* splash_component = component_loader::get(); - if (splash_component) + if (window && IsWindow(window)) { - splash_component->hide(); + ShowWindow(window, SW_HIDE); + UpdateWindow(window); } + + destroy_window(); } HWND get_window() { - auto* splash_component = component_loader::get(); - if (splash_component) - { - return splash_component->get_window(); - } - - return nullptr; + return window; } } diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp index 4d3027da..cf8c7882 100644 --- a/src/client/component/steam_proxy.cpp +++ b/src/client/component/steam_proxy.cpp @@ -21,6 +21,20 @@ namespace steam_proxy { utils::binary_resource runner_file(RUNNER, "boiii-runner.exe"); + utils::nt::library steam_client_module{}; + utils::nt::library steam_overlay_module{}; + + void* steam_pipe = nullptr; + void* global_user = nullptr; + + steam::interface client_engine{}; + steam::interface client_user{}; + steam::interface client_utils{}; + steam::interface client_friends{}; + steam::interface client_ugc{}; + + utils::concurrency::container subscribed_items; + enum class ownership_state { success, @@ -34,6 +48,129 @@ namespace steam_proxy static const auto disabled = utils::flags::has_flag("nosteam"); return disabled; } + + void* load_client_engine() + { + if (!steam_client_module) return nullptr; + + for (auto i = 1; i > 0; ++i) + { + std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i); + auto* const temp_client_engine = steam_client_module + .invoke("CreateInterface", name.data(), nullptr); + if (temp_client_engine) return temp_client_engine; + } + + return nullptr; + } + + void load_client() + { + const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); + if (steam_path.empty()) return; + + utils::nt::library::load(steam_path / "tier0_s64.dll"); + utils::nt::library::load(steam_path / "vstdlib_s64.dll"); + steam_overlay_module = utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); + steam_client_module = utils::nt::library::load(steam_path / "steamclient64.dll"); + if (!steam_client_module) return; + + client_engine = load_client_engine(); + if (!client_engine) return; + + steam_pipe = steam_client_module.invoke("Steam_CreateSteamPipe"); + global_user = steam_client_module.invoke( + "Steam_ConnectToGlobalUser", steam_pipe); + + client_user = client_engine.invoke(8, global_user, steam_pipe); + client_utils = client_engine.invoke(14, steam_pipe); + client_friends = client_engine.invoke(13, global_user, steam_pipe); + client_ugc = client_engine.invoke(61, global_user, steam_pipe); + } + + void do_cleanup() + { + client_engine = nullptr; + client_user = nullptr; + client_utils = nullptr; + + steam_pipe = nullptr; + global_user = nullptr; + + steam_client_module = utils::nt::library{nullptr}; + } + + void clean_up_on_error() + { + scheduler::schedule([] + { + if (steam_client_module + && steam_pipe + && global_user + && steam_client_module.invoke("Steam_BConnected", global_user, + steam_pipe) + && steam_client_module.invoke("Steam_BLoggedOn", global_user, steam_pipe) + ) + { + return scheduler::cond_continue; + } + + do_cleanup(); + return scheduler::cond_end; + }); + } + + ownership_state start_mod_unsafe(const std::string& title, size_t app_id) + { + if (!client_utils || !client_user) + { + return ownership_state::nosteam; + } + + if (!client_user.invoke("BIsSubscribedApp", app_id)) + { + //app_id = 480; // Spacewar + return ownership_state::unowned; + } + + if (is_disabled()) + { + return ownership_state::success; + } + + client_utils.invoke("SetAppIDForCurrentPipe", app_id, false); + + char our_directory[MAX_PATH] = {0}; + GetCurrentDirectoryA(sizeof(our_directory), our_directory); + + const auto path = runner_file.get_extracted_file(); + const std::string cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId()); + + steam::game_id game_id; + game_id.raw.type = 1; // k_EGameIDTypeGameMod + game_id.raw.app_id = app_id & 0xFFFFFF; + + const auto* mod_id = "bo3"; + game_id.raw.mod_id = *reinterpret_cast(mod_id) | 0x80000000; + + client_user.invoke("SpawnProcess", path.data(), cmdline.data(), our_directory, + &game_id.bits, title.data(), 0, 0, 0); + + return ownership_state::success; + } + + ownership_state start_mod(const std::string& title, const size_t app_id) + { + __try + { + return start_mod_unsafe(title, app_id); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + do_cleanup(); + return ownership_state::error; + } + } } class component final : public component_interface @@ -41,21 +178,15 @@ namespace steam_proxy public: void pre_start() override { - /*if (is_disabled()) - { - return; - }*/ - - this->load_client(); - this->clean_up_on_error(); + load_client(); + clean_up_on_error(); } void post_unpack() override { -#ifndef DEV_BUILD try { - const auto res = this->start_mod("\xE2\x98\x84\xEF\xB8\x8F" " BOIII"s, steam::SteamUtils()->GetAppID()); + const auto res = start_mod("\xE2\x98\x84\xEF\xB8\x8F" " BOIII"s, steam::SteamUtils()->GetAppID()); switch (res) { @@ -72,261 +203,100 @@ namespace steam_proxy catch (std::exception& e) { printf("Steam: %s\n", e.what()); - MessageBoxA(GetForegroundWindow(), e.what(), "Error", MB_ICONERROR); + MessageBoxA(GetForegroundWindow(), e.what(), "BOIII Error", MB_ICONERROR); TerminateProcess(GetCurrentProcess(), 1234); } -#endif } void pre_destroy() override { - if (this->steam_client_module_) + if (steam_client_module && steam_pipe) { - if (this->steam_pipe_) + if (global_user) { - if (this->global_user_) - { - this->steam_client_module_.invoke("Steam_ReleaseUser", this->steam_pipe_, - this->global_user_); - } - - this->steam_client_module_.invoke("Steam_BReleaseSteamPipe", this->steam_pipe_); - } - } - } - - const utils::nt::library& get_overlay_module() const - { - return steam_overlay_module_; - } - - const char* get_player_name() - { - return this->client_friends_.invoke("GetPersonaName"); - } - - void update_subscribed_items() - { - subscribed_item_map map{}; - - const auto _ = utils::finally([&] - { - this->subscribed_items_.access([&](subscribed_item_map& items) - { - items = std::move(map); - }); - }); - - if (!this->client_ugc_) - { - return; - } - - try - { - const auto app_id = steam::SteamUtils()->GetAppID(); - const auto num_items = this->client_ugc_.invoke("GetNumSubscribedItems", app_id); - - if (!num_items) - { - return; + steam_client_module.invoke("Steam_ReleaseUser", steam_pipe, + global_user); } - std::vector ids; - ids.resize(num_items); - - auto result = this->client_ugc_.invoke("GetSubscribedItems", app_id, ids.data(), - num_items); - result = std::min(num_items, result); - - for (uint32_t i = 0; i < result; ++i) - { - char buffer[0x1000] = {0}; - subscribed_item item{}; - - item.state = this->client_ugc_.invoke("GetItemState", app_id, ids[i]); - item.available = this->client_ugc_.invoke("GetItemInstallInfo", app_id, ids[i], - &item.size_on_disk, - buffer, - sizeof(buffer), &item.time_stamp); - item.path = buffer; - - map[ids[i]] = std::move(item); - } + steam_client_module.invoke("Steam_BReleaseSteamPipe", steam_pipe); } - catch (...) - { - this->client_ugc_ = {}; - } - } - - void access_subscribed_items( - const std::function& callback) - { - this->subscribed_items_.access(callback); - } - - private: - utils::nt::library steam_client_module_{}; - utils::nt::library steam_overlay_module_{}; - - steam::interface client_engine_{}; - steam::interface client_user_{}; - steam::interface client_utils_{}; - steam::interface client_friends_{}; - steam::interface client_ugc_{}; - - utils::concurrency::container subscribed_items_; - - void* steam_pipe_ = nullptr; - void* global_user_ = nullptr; - - void* load_client_engine() const - { - if (!this->steam_client_module_) return nullptr; - - for (auto i = 1; i > 0; ++i) - { - std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i); - auto* const client_engine = this->steam_client_module_ - .invoke("CreateInterface", name.data(), nullptr); - if (client_engine) return client_engine; - } - - return nullptr; - } - - void load_client() - { - const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); - if (steam_path.empty()) return; - - utils::nt::library::load(steam_path / "tier0_s64.dll"); - utils::nt::library::load(steam_path / "vstdlib_s64.dll"); - this->steam_overlay_module_ = utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); - this->steam_client_module_ = utils::nt::library::load(steam_path / "steamclient64.dll"); - if (!this->steam_client_module_) return; - - this->client_engine_ = load_client_engine(); - if (!this->client_engine_) return; - - this->steam_pipe_ = this->steam_client_module_.invoke("Steam_CreateSteamPipe"); - this->global_user_ = this->steam_client_module_.invoke( - "Steam_ConnectToGlobalUser", this->steam_pipe_); - this->client_user_ = this->client_engine_.invoke(8, this->global_user_, this->steam_pipe_); - // GetIClientUser - this->client_utils_ = this->client_engine_.invoke(14, this->steam_pipe_); // GetIClientUtils - this->client_friends_ = this->client_engine_.invoke(13, this->global_user_, this->steam_pipe_); - // GetIClientFriends - this->client_ugc_ = this->client_engine_.invoke(61, this->global_user_, this->steam_pipe_); - // GetIClientUGC - } - - ownership_state start_mod(const std::string& title, const size_t app_id) - { - __try - { - return this->start_mod_unsafe(title, app_id); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - this->do_cleanup(); - return ownership_state::error; - } - } - - ownership_state start_mod_unsafe(const std::string& title, size_t app_id) - { - if (!this->client_utils_ || !this->client_user_) - { - return ownership_state::nosteam; - } - - if (!this->client_user_.invoke("BIsSubscribedApp", app_id)) - { - //app_id = 480; // Spacewar - return ownership_state::unowned; - } - - if (is_disabled()) - { - return ownership_state::success; - } - - this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); - - char our_directory[MAX_PATH] = {0}; - GetCurrentDirectoryA(sizeof(our_directory), our_directory); - - const auto path = runner_file.get_extracted_file(); - const std::string cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId()); - - steam::game_id game_id; - game_id.raw.type = 1; // k_EGameIDTypeGameMod - game_id.raw.app_id = app_id & 0xFFFFFF; - - const auto* mod_id = "bo3"; - game_id.raw.mod_id = *reinterpret_cast(mod_id) | 0x80000000; - - this->client_user_.invoke("SpawnProcess", path.data(), cmdline.data(), our_directory, - &game_id.bits, title.data(), 0, 0, 0); - - return ownership_state::success; - } - - void do_cleanup() - { - this->client_engine_ = nullptr; - this->client_user_ = nullptr; - this->client_utils_ = nullptr; - - this->steam_pipe_ = nullptr; - this->global_user_ = nullptr; - - this->steam_client_module_ = utils::nt::library{nullptr}; - } - - void clean_up_on_error() - { - scheduler::schedule([this]() - { - if (this->steam_client_module_ - && this->steam_pipe_ - && this->global_user_ - && this->steam_client_module_.invoke("Steam_BConnected", this->global_user_, - this->steam_pipe_) - && this->steam_client_module_.invoke("Steam_BLoggedOn", this->global_user_, this->steam_pipe_) - ) - { - return scheduler::cond_continue; - } - - this->do_cleanup(); - return scheduler::cond_end; - }); } }; const utils::nt::library& get_overlay_module() { - // TODO: Find a better way to do this - return component_loader::get()->get_overlay_module(); + return steam_overlay_module; } const char* get_player_name() { - static std::string name = component_loader::get()->get_player_name(); - return name.data(); + if (client_friends) + { + return client_friends.invoke("GetPersonaName"); + } + + return "boiii"; } void update_subscribed_items() { - component_loader::get()->update_subscribed_items(); + subscribed_item_map map{}; + + const auto _ = utils::finally([&] + { + subscribed_items.access([&](subscribed_item_map& items) + { + items = std::move(map); + }); + }); + + if (!client_ugc) + { + return; + } + + try + { + const auto app_id = steam::SteamUtils()->GetAppID(); + const auto num_items = client_ugc.invoke("GetNumSubscribedItems", app_id); + + if (!num_items) + { + return; + } + + std::vector ids; + ids.resize(num_items); + + auto result = client_ugc.invoke("GetSubscribedItems", app_id, ids.data(), + num_items); + result = std::min(num_items, result); + + for (uint32_t i = 0; i < result; ++i) + { + char buffer[0x1000] = {0}; + subscribed_item item{}; + + item.state = client_ugc.invoke("GetItemState", app_id, ids[i]); + item.available = client_ugc.invoke("GetItemInstallInfo", app_id, ids[i], + &item.size_on_disk, + buffer, + sizeof(buffer), &item.time_stamp); + item.path = buffer; + + map[ids[i]] = std::move(item); + } + } + catch (...) + { + client_ugc = {}; + } } - void access_subscribed_items(const std::function& callback) + void access_subscribed_items( + const std::function& callback) { - component_loader::get()->access_subscribed_items(callback); + subscribed_items.access(callback); } } diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp index 086a37c4..ced16c06 100644 --- a/src/client/component/updater.cpp +++ b/src/client/component/updater.cpp @@ -93,7 +93,7 @@ namespace updater } } - void perform_update(HWND parent_window) + void perform_update(const HWND parent_window) { const utils::progress_ui progress_ui{}; progress_ui.set_title("Updating BOIII");