Small refactoring
This commit is contained in:
parent
5aefef6171
commit
5740210e72
@ -9,6 +9,9 @@ namespace splash
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
HWND window{};
|
||||||
|
std::thread window_thread{};
|
||||||
|
|
||||||
HANDLE load_splash_image()
|
HANDLE load_splash_image()
|
||||||
{
|
{
|
||||||
const auto self = utils::nt::library::get_by_address(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);
|
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
|
class component final : public component_interface
|
||||||
@ -36,7 +60,7 @@ namespace splash
|
|||||||
: image_(load_splash_image())
|
: image_(load_splash_image())
|
||||||
{
|
{
|
||||||
enable_dpi_awareness();
|
enable_dpi_awareness();
|
||||||
this->window_thread_ = std::thread([this]
|
window_thread = std::thread([this]
|
||||||
{
|
{
|
||||||
this->draw();
|
this->draw();
|
||||||
});
|
});
|
||||||
@ -44,64 +68,25 @@ namespace splash
|
|||||||
|
|
||||||
~component()
|
~component()
|
||||||
{
|
{
|
||||||
if (this->window_thread_.joinable())
|
if (window_thread.joinable())
|
||||||
{
|
{
|
||||||
this->window_thread_.detach();
|
window_thread.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pre_destroy() override
|
void pre_destroy() override
|
||||||
{
|
{
|
||||||
this->destroy();
|
destroy_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
this->destroy();
|
destroy_window();
|
||||||
}
|
|
||||||
|
|
||||||
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_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic_bool join_safe_{false};
|
std::atomic_bool join_safe_{false};
|
||||||
HWND window_{};
|
|
||||||
HANDLE image_{};
|
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()
|
void draw()
|
||||||
{
|
{
|
||||||
@ -111,13 +96,13 @@ namespace splash
|
|||||||
std::this_thread::sleep_for(1ms);
|
std::this_thread::sleep_for(1ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->window_ = nullptr;
|
window = nullptr;
|
||||||
UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{});
|
UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool draw_frame() const
|
bool draw_frame() const
|
||||||
{
|
{
|
||||||
if (!this->window_)
|
if (!window)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -130,7 +115,7 @@ namespace splash
|
|||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessageW(&msg);
|
DispatchMessageW(&msg);
|
||||||
|
|
||||||
if (msg.message == WM_DESTROY && msg.hwnd == this->window_)
|
if (msg.message == WM_DESTROY && msg.hwnd == window)
|
||||||
{
|
{
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
}
|
}
|
||||||
@ -167,17 +152,17 @@ namespace splash
|
|||||||
|
|
||||||
if (image_)
|
if (image_)
|
||||||
{
|
{
|
||||||
this->window_ = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII",
|
window = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII",
|
||||||
WS_POPUP | WS_SYSMENU,
|
WS_POPUP | WS_SYSMENU,
|
||||||
(x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr,
|
(x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
host, nullptr);
|
host, nullptr);
|
||||||
|
|
||||||
if (this->window_)
|
if (window)
|
||||||
{
|
{
|
||||||
auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu,
|
auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu,
|
||||||
0, 0,
|
0, 0,
|
||||||
320, 100, this->window_, nullptr, host, nullptr);
|
320, 100, window, nullptr, host, nullptr);
|
||||||
if (image_window)
|
if (image_window)
|
||||||
{
|
{
|
||||||
RECT rect;
|
RECT rect;
|
||||||
@ -193,15 +178,15 @@ namespace splash
|
|||||||
rect.right = rect.left + width;
|
rect.right = rect.left + width;
|
||||||
rect.bottom = rect.top + height;
|
rect.bottom = rect.top + height;
|
||||||
AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0);
|
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);
|
rect.bottom - rect.top, SWP_NOZORDER);
|
||||||
|
|
||||||
SetWindowRgn(this->window_,
|
SetWindowRgn(window,
|
||||||
CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15,
|
CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15,
|
||||||
15), TRUE);
|
15), TRUE);
|
||||||
|
|
||||||
ShowWindow(this->window_, SW_SHOW);
|
ShowWindow(window, SW_SHOW);
|
||||||
UpdateWindow(this->window_);
|
UpdateWindow(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,22 +196,18 @@ namespace splash
|
|||||||
|
|
||||||
void hide()
|
void hide()
|
||||||
{
|
{
|
||||||
auto* splash_component = component_loader::get<component>();
|
if (window && IsWindow(window))
|
||||||
if (splash_component)
|
|
||||||
{
|
{
|
||||||
splash_component->hide();
|
ShowWindow(window, SW_HIDE);
|
||||||
|
UpdateWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND get_window()
|
HWND get_window()
|
||||||
{
|
{
|
||||||
auto* splash_component = component_loader::get<component>();
|
return window;
|
||||||
if (splash_component)
|
|
||||||
{
|
|
||||||
return splash_component->get_window();
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,20 @@ namespace steam_proxy
|
|||||||
{
|
{
|
||||||
utils::binary_resource runner_file(RUNNER, "boiii-runner.exe");
|
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_item_map> subscribed_items;
|
||||||
|
|
||||||
enum class ownership_state
|
enum class ownership_state
|
||||||
{
|
{
|
||||||
success,
|
success,
|
||||||
@ -34,6 +48,129 @@ namespace steam_proxy
|
|||||||
static const auto disabled = utils::flags::has_flag("nosteam");
|
static const auto disabled = utils::flags::has_flag("nosteam");
|
||||||
return disabled;
|
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<void*>("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<void*>("Steam_CreateSteamPipe");
|
||||||
|
global_user = steam_client_module.invoke<void*>(
|
||||||
|
"Steam_ConnectToGlobalUser", steam_pipe);
|
||||||
|
|
||||||
|
client_user = client_engine.invoke<void*>(8, global_user, steam_pipe);
|
||||||
|
client_utils = client_engine.invoke<void*>(14, steam_pipe);
|
||||||
|
client_friends = client_engine.invoke<void*>(13, global_user, steam_pipe);
|
||||||
|
client_ugc = client_engine.invoke<void*>(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<bool>("Steam_BConnected", global_user,
|
||||||
|
steam_pipe)
|
||||||
|
&& steam_client_module.invoke<bool>("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<bool>("BIsSubscribedApp", app_id))
|
||||||
|
{
|
||||||
|
//app_id = 480; // Spacewar
|
||||||
|
return ownership_state::unowned;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_disabled())
|
||||||
|
{
|
||||||
|
return ownership_state::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_utils.invoke<void>("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<const unsigned int*>(mod_id) | 0x80000000;
|
||||||
|
|
||||||
|
client_user.invoke<bool>("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
|
class component final : public component_interface
|
||||||
@ -41,21 +178,15 @@ namespace steam_proxy
|
|||||||
public:
|
public:
|
||||||
void pre_start() override
|
void pre_start() override
|
||||||
{
|
{
|
||||||
/*if (is_disabled())
|
load_client();
|
||||||
{
|
clean_up_on_error();
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
this->load_client();
|
|
||||||
this->clean_up_on_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
#ifndef DEV_BUILD
|
|
||||||
try
|
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)
|
switch (res)
|
||||||
{
|
{
|
||||||
@ -72,261 +203,100 @@ namespace steam_proxy
|
|||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
printf("Steam: %s\n", e.what());
|
printf("Steam: %s\n", e.what());
|
||||||
MessageBoxA(GetForegroundWindow(), e.what(), "Error", MB_ICONERROR);
|
MessageBoxA(GetForegroundWindow(), e.what(), "BOIII Error", MB_ICONERROR);
|
||||||
TerminateProcess(GetCurrentProcess(), 1234);
|
TerminateProcess(GetCurrentProcess(), 1234);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pre_destroy() override
|
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_)
|
steam_client_module.invoke<void>("Steam_ReleaseUser", steam_pipe,
|
||||||
{
|
global_user);
|
||||||
this->steam_client_module_.invoke<void>("Steam_ReleaseUser", this->steam_pipe_,
|
|
||||||
this->global_user_);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->steam_client_module_.invoke<bool>("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<const char*>("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<uint32_t>("GetNumSubscribedItems", app_id);
|
|
||||||
|
|
||||||
if (!num_items)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint64_t> ids;
|
steam_client_module.invoke<bool>("Steam_BReleaseSteamPipe", steam_pipe);
|
||||||
ids.resize(num_items);
|
|
||||||
|
|
||||||
auto result = this->client_ugc_.invoke<uint32_t>("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<uint32_t>("GetItemState", app_id, ids[i]);
|
|
||||||
item.available = this->client_ugc_.invoke<bool>("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 (...)
|
|
||||||
{
|
|
||||||
this->client_ugc_ = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void access_subscribed_items(
|
|
||||||
const std::function<void(const subscribed_item_map&)>& 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_item_map> 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<void*>("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<void*>("Steam_CreateSteamPipe");
|
|
||||||
this->global_user_ = this->steam_client_module_.invoke<void*>(
|
|
||||||
"Steam_ConnectToGlobalUser", this->steam_pipe_);
|
|
||||||
this->client_user_ = this->client_engine_.invoke<void*>(8, this->global_user_, this->steam_pipe_);
|
|
||||||
// GetIClientUser
|
|
||||||
this->client_utils_ = this->client_engine_.invoke<void*>(14, this->steam_pipe_); // GetIClientUtils
|
|
||||||
this->client_friends_ = this->client_engine_.invoke<void*>(13, this->global_user_, this->steam_pipe_);
|
|
||||||
// GetIClientFriends
|
|
||||||
this->client_ugc_ = this->client_engine_.invoke<void*>(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<bool>("BIsSubscribedApp", app_id))
|
|
||||||
{
|
|
||||||
//app_id = 480; // Spacewar
|
|
||||||
return ownership_state::unowned;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_disabled())
|
|
||||||
{
|
|
||||||
return ownership_state::success;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->client_utils_.invoke<void>("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<const unsigned int*>(mod_id) | 0x80000000;
|
|
||||||
|
|
||||||
this->client_user_.invoke<bool>("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<bool>("Steam_BConnected", this->global_user_,
|
|
||||||
this->steam_pipe_)
|
|
||||||
&& this->steam_client_module_.invoke<bool>("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()
|
const utils::nt::library& get_overlay_module()
|
||||||
{
|
{
|
||||||
// TODO: Find a better way to do this
|
return steam_overlay_module;
|
||||||
return component_loader::get<component>()->get_overlay_module();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* get_player_name()
|
const char* get_player_name()
|
||||||
{
|
{
|
||||||
static std::string name = component_loader::get<component>()->get_player_name();
|
if (client_friends)
|
||||||
return name.data();
|
{
|
||||||
|
return client_friends.invoke<const char*>("GetPersonaName");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "boiii";
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_subscribed_items()
|
void update_subscribed_items()
|
||||||
{
|
{
|
||||||
component_loader::get<component>()->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<uint32_t>("GetNumSubscribedItems", app_id);
|
||||||
|
|
||||||
|
if (!num_items)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint64_t> ids;
|
||||||
|
ids.resize(num_items);
|
||||||
|
|
||||||
|
auto result = client_ugc.invoke<uint32_t>("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<uint32_t>("GetItemState", app_id, ids[i]);
|
||||||
|
item.available = client_ugc.invoke<bool>("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<void(const subscribed_item_map&)>& callback)
|
void access_subscribed_items(
|
||||||
|
const std::function<void(const subscribed_item_map&)>& callback)
|
||||||
{
|
{
|
||||||
component_loader::get<component>()->access_subscribed_items(callback);
|
subscribed_items.access(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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{};
|
const utils::progress_ui progress_ui{};
|
||||||
progress_ui.set_title("Updating BOIII");
|
progress_ui.set_title("Updating BOIII");
|
||||||
|
Loading…
Reference in New Issue
Block a user