build: test format #1
							
								
								
									
										33
									
								
								.gitea/workflows/check-formatting.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								.gitea/workflows/check-formatting.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| name: check-formatting | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - "*" | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - "*" | ||||
|     types: [opened, synchronize, reopened] | ||||
|  | ||||
| jobs: | ||||
|   check-formatting: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Install LLVM | ||||
|         uses: KyleMayes/install-llvm-action@v2.0.5 | ||||
|         with: | ||||
|           version: "17.0" | ||||
|  | ||||
|       - name: Install dependencies (x64) | ||||
|         run: | | ||||
|           apt-get update | ||||
|           apt-get install libtinfo5 -y | ||||
|  | ||||
|       - name: Test formatting for all files | ||||
|         working-directory: ${{ github.workspace }} | ||||
|         run: | | ||||
|           export CLANG_FORMAT_BIN="${LLVM_PATH}/bin/clang-format" | ||||
|           ./scripts/check-format.sh | ||||
							
								
								
									
										8
									
								
								scripts/check-format.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								scripts/check-format.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| # Go to repository root | ||||
| cd "$(dirname "$0")/.." || exit 2 | ||||
|  | ||||
| CLANG_FORMAT_BIN="${CLANG_FORMAT_BIN:-clang-format}" | ||||
|  | ||||
| find ./src -iname '*.hpp' -o -iname '*.cpp' | xargs $CLANG_FORMAT_BIN -Werror -ferror-limit=1 --dry-run | ||||
| @@ -12,8 +12,19 @@ | ||||
|  | ||||
| #include "scheduler.hpp" | ||||
|  | ||||
| #include <xorstr.hpp> | ||||
|  | ||||
| namespace { | ||||
| utils::binary_resource runner_file(RUNNER, "iw4sp-runner.exe"); | ||||
| enum class ownership_state { | ||||
|   success, | ||||
|   unowned, | ||||
|   nosteam, | ||||
|   error, | ||||
| }; | ||||
|  | ||||
| ownership_state state_; | ||||
|  | ||||
| utils::binary_resource runner_file(RUNNER, xorstr_("iw4sp-runner.exe")); | ||||
| } // namespace | ||||
|  | ||||
| class steam_proxy final : public component_interface { | ||||
| @@ -23,22 +34,35 @@ public: | ||||
|     this->clean_up_on_error(); | ||||
|  | ||||
|     try { | ||||
|       this->start_mod("iw4x-sp singleplayer", 10180); | ||||
|       state_ = this->start_mod(xorstr_("iw4x-sp singleplayer"), 10180); | ||||
|     } catch (const std::exception& ex) { | ||||
|       printf("Steam: %s\n", ex.what()); | ||||
|       state_ = ownership_state::error; | ||||
|       printf(xorstr_("Steam: %s\n"), ex.what()); | ||||
|     } | ||||
|  | ||||
| #ifdef STEAM_OWNERSHIP_CHECK | ||||
|     if (utils::nt::is_wine()) { | ||||
|       state_ = ownership_state::success; | ||||
|       return; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifdef STEAM_OWNERSHIP_CHECK | ||||
|     evaluate_ownership_state(state_); | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   void pre_destroy() override { | ||||
|     if (this->steam_client_module_) { | ||||
|       if (this->steam_pipe_) { | ||||
|         if (this->global_user_) { | ||||
|           this->steam_client_module_.invoke<void>( | ||||
|               "Steam_ReleaseUser", this->steam_pipe_, this->global_user_); | ||||
|           this->steam_client_module_.invoke<void>(xorstr_("Steam_ReleaseUser"), | ||||
|                                                   this->steam_pipe_, | ||||
|                                                   this->global_user_); | ||||
|         } | ||||
|  | ||||
|         this->steam_client_module_.invoke<bool>("Steam_BReleaseSteamPipe", | ||||
|                                                 this->steam_pipe_); | ||||
|         this->steam_client_module_.invoke<bool>( | ||||
|             xorstr_("Steam_BReleaseSteamPipe"), this->steam_pipe_); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -59,10 +83,10 @@ private: | ||||
|  | ||||
|     for (auto i = 1; i < 1000; ++i) { | ||||
|       const auto* name = | ||||
|           utils::string::va("CLIENTENGINE_INTERFACE_VERSION{0:03}", i); | ||||
|           utils::string::va(xorstr_("CLIENTENGINE_INTERFACE_VERSION{0:03}"), i); | ||||
|  | ||||
|       auto* const client_engine = this->steam_client_module_.invoke<void*>( | ||||
|           "CreateInterface", name, nullptr); | ||||
|           xorstr_("CreateInterface"), name, nullptr); | ||||
|       if (client_engine) | ||||
|         return client_engine; | ||||
|     } | ||||
| @@ -75,10 +99,10 @@ private: | ||||
|     if (steam_path.empty()) | ||||
|       return; | ||||
|  | ||||
|     utils::nt::library::load(steam_path / "tier0_s.dll"); | ||||
|     utils::nt::library::load(steam_path / "vstdlib_s.dll"); | ||||
|     utils::nt::library::load(steam_path / xorstr_("tier0_s.dll")); | ||||
|     utils::nt::library::load(steam_path / xorstr_("vstdlib_s.dll")); | ||||
|     this->steam_client_module_ = | ||||
|         utils::nt::library::load(steam_path / "steamclient.dll"); | ||||
|         utils::nt::library::load(steam_path / xorstr_("steamclient.dll")); | ||||
|     if (!this->steam_client_module_) | ||||
|       return; | ||||
|  | ||||
| @@ -86,52 +110,62 @@ private: | ||||
|     if (!this->client_engine_) | ||||
|       return; | ||||
|  | ||||
|     this->steam_pipe_ = | ||||
|         this->steam_client_module_.invoke<void*>("Steam_CreateSteamPipe"); | ||||
|     this->steam_pipe_ = this->steam_client_module_.invoke<void*>( | ||||
|         xorstr_("Steam_CreateSteamPipe")); | ||||
|     this->global_user_ = this->steam_client_module_.invoke<void*>( | ||||
|         "Steam_ConnectToGlobalUser", this->steam_pipe_); | ||||
|         xorstr_("Steam_ConnectToGlobalUser"), this->steam_pipe_); | ||||
|     this->client_user_ = this->client_engine_.invoke<void*>( | ||||
|         8, this->steam_pipe_, this->global_user_); // GetIClientUser | ||||
|     this->client_utils_ = this->client_engine_.invoke<void*>( | ||||
|         14, this->steam_pipe_); // GetIClientUtils | ||||
|   } | ||||
|  | ||||
|   void start_mod(const std::string& title, const std::size_t app_id) { | ||||
|   ownership_state start_mod(const std::string& title, | ||||
|                             const std::size_t app_id) { | ||||
|     __try { | ||||
|       this->start_mod_unsafe(title, app_id); | ||||
|       return this->start_mod_unsafe(title, app_id); | ||||
|     } __except (EXCEPTION_EXECUTE_HANDLER) { | ||||
|       this->do_cleanup(); | ||||
|       return ownership_state::error; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void start_mod_unsafe(const std::string& title, std::size_t app_id) { | ||||
|   ownership_state start_mod_unsafe(const std::string& title, | ||||
|                                    std::size_t app_id) { | ||||
|     if (!this->client_utils_ || !this->client_user_) | ||||
|       return; | ||||
|       return ownership_state::nosteam; | ||||
|  | ||||
|     if (!this->client_user_.invoke<bool>("BIsSubscribedApp", app_id)) { | ||||
|     if (!this->client_user_.invoke<bool>(xorstr_("BIsSubscribedApp"), app_id)) { | ||||
| #ifdef _DEBUG | ||||
|       app_id = 480; // Spacewar | ||||
| #else | ||||
|       return ownership_state::unowned; | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     this->client_utils_.invoke<void>("SetAppIDForCurrentPipe", app_id, false); | ||||
|     this->client_utils_.invoke<void>(xorstr_("SetAppIDForCurrentPipe"), app_id, | ||||
|                                      false); | ||||
|  | ||||
|     char our_directory[MAX_PATH]{}; | ||||
|     GetCurrentDirectoryA(sizeof(our_directory), our_directory); | ||||
|  | ||||
|     const auto path = runner_file.get_extracted_file(); | ||||
|     const auto* cmd_line = | ||||
|         utils::string::va("\"{0}\" -proc {1}", path, GetCurrentProcessId()); | ||||
|     const auto* cmd_line = utils::string::va(xorstr_("\"{0}\" -proc {1}"), path, | ||||
|                                              GetCurrentProcessId()); | ||||
|  | ||||
|     game_id game_id; | ||||
|     game_id.raw.type = 1; // k_EGameIDTypeGameMod | ||||
|     game_id.raw.app_id = app_id & 0xFFFFFF; | ||||
|  | ||||
|     const auto* mod_id = "IW4"; | ||||
|     const auto* mod_id = "IW4x-SP"; | ||||
|     game_id.raw.mod_id = | ||||
|         *reinterpret_cast<const unsigned int*>(mod_id) | 0x80000000; | ||||
|  | ||||
|     this->client_user_.invoke<bool>("SpawnProcess", path.data(), cmd_line, | ||||
|                                     our_directory, game_id.bits, title.data(), | ||||
|                                     app_id, 0, 0, 0); | ||||
|     this->client_user_.invoke<bool>(xorstr_("SpawnProcess"), path.c_str(), | ||||
|                                     cmd_line, our_directory, game_id.bits, | ||||
|                                     title.c_str(), app_id, 0, 0, 0); | ||||
|  | ||||
|     return ownership_state::success; | ||||
|   } | ||||
|  | ||||
|   void do_cleanup() { | ||||
| @@ -151,9 +185,11 @@ private: | ||||
|           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_) && | ||||
|                   xorstr_("Steam_BConnected"), this->global_user_, | ||||
|                   this->steam_pipe_) && | ||||
|               this->steam_client_module_.invoke<bool>( | ||||
|                   "Steam_BLoggedOn", this->global_user_, this->steam_pipe_)) { | ||||
|                   xorstr_("Steam_BLoggedOn"), this->global_user_, | ||||
|                   this->steam_pipe_)) { | ||||
|             return scheduler::cond_continue; | ||||
|           } | ||||
|  | ||||
| @@ -162,6 +198,24 @@ private: | ||||
|         }, | ||||
|         scheduler::pipeline::async); | ||||
|   } | ||||
|  | ||||
| #ifdef STEAM_OWNERSHIP_CHECK | ||||
|   void evaluate_ownership_state(const ownership_state state) { | ||||
|     switch (state) { | ||||
|     case ownership_state::nosteam: | ||||
|       throw std::runtime_error( | ||||
|           xorstr_("Steam must be running to play this game!")); | ||||
|     case ownership_state::unowned: | ||||
|       throw std::runtime_error( | ||||
|           xorstr_("You must own the game on Steam to play this mod!")); | ||||
|     case ownership_state::error: | ||||
|       throw std::runtime_error( | ||||
|           xorstr_("Failed to verify ownership of the game!")); | ||||
|     case ownership_state::success: | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| REGISTER_COMPONENT(steam_proxy) | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| #include "nt.hpp" | ||||
|  | ||||
| #include <xorstr.hpp> | ||||
|  | ||||
| namespace utils::nt { | ||||
| library library::load(const std::string& name) { | ||||
|   return library(LoadLibraryA(name.c_str())); | ||||
| @@ -206,8 +208,8 @@ std::string library::get_dll_directory() { | ||||
|  | ||||
| bool is_wine() { | ||||
|   static const auto has_wine_export = []() -> bool { | ||||
|     const library ntdll("ntdll.dll"); | ||||
|     return ntdll.get_proc<void*>("wine_get_version"); | ||||
|     const library ntdll(xorstr_("ntdll.dll")); | ||||
|     return ntdll.get_proc<void*>(xorstr_("wine_get_version")); | ||||
|   }(); | ||||
|  | ||||
|   return has_wine_export; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user