#include #include #include #include #include "steam/steam.hpp" #include "steam/interface.hpp" #include "game/game.hpp" #include "scheduler.hpp" class steam_proxy final : public module { public: void post_start() override { this->run_mod(); } void post_load() override { if (game::is_dedi()) return; this->load_client(); this->clean_up_on_error(); try { if (game::is_sp()) { this->start_mod("\xF0\x9F\x90\x8D Open-IW5 Singleplayer", 42680); } else if (game::is_mp()) { this->start_mod("\xF0\x9F\x90\x8D Open-IW5 Multiplayer", 42690); } } catch (std::exception& e) { printf("Steam: %s\n", e.what()); } } void pre_destroy() override { if (this->steam_client_module_) { if (this->steam_pipe_) { 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_); } } } private: utils::nt::library steam_client_module_; steam::interface client_engine_; steam::interface client_user_; steam::interface client_utils_; void* steam_pipe_ = nullptr; void* global_user_ = nullptr; void run_mod() const { const auto command = "-proc "; const char* parent_proc = strstr(GetCommandLineA(), command); if (parent_proc) { const auto pid = atoi(parent_proc + strlen(command)); const auto process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid); if (process_handle && process_handle != INVALID_HANDLE_VALUE) { WaitForSingleObject(process_handle, INFINITE); CloseHandle(process_handle); } module_loader::trigger_premature_shutdown(); } } 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); const auto client_engine = this->steam_client_module_ .invoke("CreateInterface", name.data(), nullptr); if (client_engine) return client_engine; } return nullptr; } void load_client() { const auto steam_path = ::steam::get_steam_install_directory(); if (steam_path.empty()) return; utils::nt::library::load(steam_path + "tier0_s.dll"); utils::nt::library::load(steam_path + "vstdlib_s.dll"); this->steam_client_module_ = utils::nt::library::load(steam_path + "steamclient.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->steam_pipe_, this->global_user_); // GetIClientUser this->client_utils_ = this->client_engine_.invoke(13, this->steam_pipe_); // GetIClientUtils } void start_mod(const std::string& title, size_t app_id) { if (!this->client_utils_ || !this->client_user_) return; if (!this->client_user_.invoke("BIsSubscribedApp", app_id)) { app_id = 480; // Spacewar } this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); const utils::nt::library self; const auto path = self.get_path(); char our_directory[MAX_PATH] = {0}; GetCurrentDirectoryA(sizeof(our_directory), our_directory); const std::string cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId()); game_id game_id; game_id.raw.type = 1; // k_EGameIDTypeGameMod game_id.raw.app_id = app_id & 0xFFFFFF; const auto mod_id = "OIW5"; game_id.raw.mod_id = *reinterpret_cast(mod_id) | 0x80000000; this->client_user_.invoke("SpawnProcess", self.get_path().data(), cmdline.data(), our_directory, game_id.bits, title.data(), app_id, 0, 0); } void clean_up_on_error() { 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_)) { scheduler::once(std::bind(&steam_proxy::clean_up_on_error, this)); return; } 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}; } }; REGISTER_MODULE(steam_proxy)