From 2b73c120a8762181551ec02570185dc87d5c2cf3 Mon Sep 17 00:00:00 2001 From: Anonymous275 <36374260+Anonymous-275@users.noreply.github.com> Date: Wed, 19 Jan 2022 21:36:52 +0200 Subject: [PATCH] Basic foundation done --- CMakeLists.txt | 2 +- include/{Memory.h => BeamNG.h} | 4 +- include/Launcher.h | 10 +++- src/{Memory/Memory.cpp => BeamNG.cpp} | 8 +-- src/Discord.cpp | 2 +- src/Launcher.cpp | 73 ++++++++++++++++++++++----- src/Network/Http.cpp | 9 ++-- src/Network/Update.cpp | 55 ++++++++++++++++++++ src/main.cpp | 6 +-- 9 files changed, 138 insertions(+), 31 deletions(-) rename include/{Memory.h => BeamNG.h} (76%) rename src/{Memory/Memory.cpp => BeamNG.cpp} (79%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e38fea..c7adec0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ add_executable(${PROJECT_NAME} src/Network/Http.cpp include/Http.h src/Network/Login.cpp src/Network/Update.cpp src/Discord.cpp src/Config.cpp - src/Memory/Memory.cpp include/Memory.h + src/BeamNG.cpp include/BeamNG.h ) diff --git a/include/Memory.h b/include/BeamNG.h similarity index 76% rename from include/Memory.h rename to include/BeamNG.h index bee4d59..cab8cf2 100644 --- a/include/Memory.h +++ b/include/BeamNG.h @@ -5,8 +5,8 @@ #include -class Memory { +class BeamNG { public: - static size_t GetProcessID(const char* PName); static size_t GetModuleBase(const char* Name); + static uint32_t GetProcessID(); }; \ No newline at end of file diff --git a/include/Launcher.h b/include/Launcher.h index 44216d5..4092ed9 100644 --- a/include/Launcher.h +++ b/include/Launcher.h @@ -23,6 +23,7 @@ public: //constructors Launcher(int argc, char* argv[]); ~Launcher(); public: //available functions + static void StaticAbort(Launcher* Instance = nullptr); std::string Login(const std::string& fields); void RunDiscordRPC(); void QueryRegistry(); @@ -30,6 +31,7 @@ public: //available functions void LoadConfig(); void LaunchGame(); void CheckKey(); + void SetupMOD(); public: //Getters const std::string& getFullVersion(); const std::string& getUserRole(); @@ -40,22 +42,26 @@ private: //functions void RichPresence(); void WindowsInit(); void UpdateCheck(); + void ResetMods(); + void EnableMP(); void Relaunch(); + void Abort(); private: //variables - size_t GamePID{0}; + uint32_t GamePID{0}; bool EnableUI = true; - bool Shutdown = false; bool LoginAuth = false; fs::path CurrentPath{}; std::string BeamRoot{}; std::string UserRole{}; std::string PublicKey{}; std::thread DiscordRPC{}; + std::string MPUserPath{}; std::string BeamVersion{}; std::string BeamUserPath{}; std::string DiscordMessage{}; std::string Version{"3.0"}; std::string TargetBuild{"default"}; + std::atomic Shutdown{false}; std::string FullVersion{Version + ".0"}; VersionParser SupportedVersion{"0.24.1.1"}; }; diff --git a/src/Memory/Memory.cpp b/src/BeamNG.cpp similarity index 79% rename from src/Memory/Memory.cpp rename to src/BeamNG.cpp index d61c1b6..1c4872e 100644 --- a/src/Memory/Memory.cpp +++ b/src/BeamNG.cpp @@ -5,12 +5,12 @@ #define WIN32_LEAN_AND_MEAN #include -#include "Memory.h" +#include "BeamNG.h" #undef UNICODE #include #include -size_t Memory::GetProcessID(const char* PName) { +uint32_t BeamNG::GetProcessID() { SetLastError(0); PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); @@ -18,7 +18,7 @@ size_t Memory::GetProcessID(const char* PName) { if(Process32First(Snapshot, &pe32)) { do{ - if(std::string(PName) == pe32.szExeFile)break; + if(std::string("BeamNG.drive.x64.exe") == pe32.szExeFile)break; }while(Process32Next(Snapshot, &pe32)); } @@ -30,6 +30,6 @@ size_t Memory::GetProcessID(const char* PName) { return pe32.th32ProcessID; } -size_t Memory::GetModuleBase(const char* Name) { +size_t BeamNG::GetModuleBase(const char* Name) { return (size_t)GetModuleHandleA(Name); } diff --git a/src/Discord.cpp b/src/Discord.cpp index 494e490..8a719a0 100644 --- a/src/Discord.cpp +++ b/src/Discord.cpp @@ -10,7 +10,7 @@ void Launcher::RichPresence() { Discord_Initialize("629743237988352010", nullptr, 1,nullptr); int64_t Start{}; - while(!Shutdown) { + while(!Shutdown.load()) { DiscordRichPresence discordPresence; memset(&discordPresence, 0, sizeof(discordPresence)); discordPresence.state = DiscordMessage.c_str(); diff --git a/src/Launcher.cpp b/src/Launcher.cpp index 8d3b6a3..7baedd6 100644 --- a/src/Launcher.cpp +++ b/src/Launcher.cpp @@ -6,25 +6,67 @@ #define WIN32_LEAN_AND_MEAN #include "Launcher.h" #include "Logger.h" -#include "Memory.h" +#include "BeamNG.h" #include #include Launcher::Launcher(int argc, char* argv[]) : CurrentPath(std::filesystem::path(argv[0])), DiscordMessage("Just launched") { + Launcher::StaticAbort(this); Log::Init(); WindowsInit(); LOG(INFO) << "Starting Launcher V" << FullVersion; UpdateCheck(); } -Launcher::~Launcher() { - Shutdown = true; +void Launcher::Abort() { + Shutdown.store(true); if(DiscordRPC.joinable()) { DiscordRPC.join(); } + if(!MPUserPath.empty()) { + ResetMods(); + } + if(GamePID != 0) { + auto Handle = OpenProcess(PROCESS_TERMINATE, false, DWORD(GamePID)); + TerminateProcess(Handle, 0); + CloseHandle(Handle); + } +} + +Launcher::~Launcher() { + Abort(); +} + +BOOL WINAPI CtrlHandler(DWORD Flag) { + if((Flag >= 0 && Flag < 3) || (Flag > 4 && Flag < 7)) { + Launcher::StaticAbort(); + return 1; + } + return 0; +} + +void Launcher::StaticAbort(Launcher* Instance) { + static Launcher* Address; + if(Instance) { + Address = Instance; + return; + } + Address->Abort(); +} + +void Launcher::WindowsInit() { + system("cls"); + SetConsoleTitleA(("BeamMP Launcher v" + FullVersion).c_str()); + if(!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { + LOG(WARNING) << "Failed to set CtrlHandler"; + } } void Launcher::LaunchGame() { + if(BeamNG::GetProcessID() != 0) { + LOG(FATAL) << "Game is already running, please close it and try again!"; + throw ShutdownException("Fatal Error"); + } VersionParser GameVersion(BeamVersion); if(GameVersion.data[0] > SupportedVersion.data[0]) { LOG(FATAL) << "BeamNG V" << BeamVersion << " not yet supported, please wait until we update BeamMP!"; @@ -43,20 +85,22 @@ void Launcher::LaunchGame() { } void Launcher::WaitForGame() { - LOG(INFO) << "Waiting for game launch"; + LOG(INFO) << "Waiting for the game, please start BeamNG manually in case of steam issues"; do{ - GamePID = Memory::GetProcessID("BeamNG.drive.x64.exe"); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - }while(GamePID == 0 && !Shutdown); + GamePID = BeamNG::GetProcessID(); + std::this_thread::sleep_for(std::chrono::seconds(2)); + }while(GamePID == 0 && !Shutdown.load()); + if(Shutdown.load())return; if(GamePID == 0) { LOG(FATAL) << "Game process not found! aborting"; throw ShutdownException("Fatal Error"); - }else LOG(INFO) << "Game found! PID " << GamePID; -} - -void Launcher::WindowsInit() { - system("cls"); - SetConsoleTitleA(("BeamMP Launcher v" + FullVersion).c_str()); + } + LOG(INFO) << "Game found! PID " << GamePID; + //TODO: Inject then start IPC + while(!Shutdown.load() && BeamNG::GetProcessID() != 0) { + std::this_thread::sleep_for(std::chrono::seconds(2)); + } + LOG(INFO) << "Game process was lost"; } std::string QueryValue(HKEY& hKey, const char* Name) { @@ -95,6 +139,9 @@ void Launcher::QueryRegistry() { VersionParser GameVer(BeamVersion); BeamUserPath += GameVer.split[0] + '.' + GameVer.split[1] + '\\'; } + if(!BeamUserPath.empty()) { + MPUserPath = BeamUserPath + "mods\\multiplayer"; + } if(!BeamRoot.empty() && !BeamVersion.empty() && !BeamUserPath.empty())return; } LOG(FATAL) << "Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive"; diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index 73dcbb1..84ce49d 100644 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -82,7 +82,7 @@ bool HTTP::ProgressBar(size_t c, size_t t){ static double progress_bar_adv; progress_bar_adv = round(double(c) / double(t) * 25); std::cout << "\r"; - std::cout << "Progress : [ "; + std::cout << "Progress: [ "; std::cout << round(double(c) / double(t) * 100); std::cout << "% ] ["; int i; @@ -102,15 +102,14 @@ bool HTTP::Download(const std::string &IP, const std::string &Path) { isDownload = false; if(Ret.empty())return false; - + std::cout << "\n"; std::ofstream File(Path, std::ios::binary); if(File.is_open()) { File << Ret; File.close(); - std::cout << "\n"; - LOG(INFO) << "Download Complete!"; + LOG(INFO) << "Download complete!"; } else { - LOG(INFO) << "Failed to open file directory: " << Path; + LOG(ERROR) << "Failed to open file directory: " << Path; return false; } return true; diff --git a/src/Network/Update.cpp b/src/Network/Update.cpp index 0eb5ab4..79a4787 100644 --- a/src/Network/Update.cpp +++ b/src/Network/Update.cpp @@ -6,6 +6,7 @@ #include "Launcher.h" #include "Logger.h" #include "Http.h" +#include "Json.h" VersionParser::VersionParser(const std::string &from_string) { std::string token; @@ -78,3 +79,57 @@ void Launcher::UpdateCheck() { Relaunch(); }else LOG(INFO) << "Launcher version is up to date"; } + +size_t DirCount(const std::filesystem::path& path){ + return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{}); +} + +void Launcher::ResetMods() { + if (!fs::exists(MPUserPath)) { + fs::create_directories(MPUserPath); + return; + } + if (DirCount(fs::path(MPUserPath)) > 3) { + LOG(WARNING) << "mods/multiplayer will be cleared in 15 seconds, close to abort"; + std::this_thread::sleep_for(std::chrono::seconds(15)); + } + fs::remove_all(MPUserPath); + fs::create_directories(MPUserPath); +} + +void Launcher::EnableMP() { + std::string File(BeamUserPath + "mods\\db.json"); + if(!fs::exists(File))return; + auto Size = fs::file_size(File); + if(Size < 2)return; + std::ifstream db(File); + if(db.is_open()) { + std::string Data(Size, 0); + db.read(&Data[0], std::streamsize(Size)); + db.close(); + Json::Document d; + d.Parse(Data.c_str()); + if(Data.at(0) != '{' || d.HasParseError())return; + if(!d["mods"].IsNull() && !d["mods"]["multiplayerbeammp"].IsNull()){ + d["mods"]["multiplayerbeammp"]["active"] = true; + Json::StringBuffer buffer; + Json::Writer writer(buffer); + d.Accept(writer); + std::ofstream ofs(File); + if(ofs.is_open()){ + ofs << buffer.GetString(); + ofs.close(); + } else { + LOG(ERROR) << "Failed to write " << File; + } + } + } +} + +void Launcher::SetupMOD() { + ResetMods(); + EnableMP(); + LOG(INFO) << "Downloading mod please wait"; + HTTP::Download("https://backend.beammp.com/builds/client?download=true" + "&pk=" + PublicKey + "&branch=" + TargetBuild, MPUserPath + "\\BeamMP.zip"); +} diff --git a/src/main.cpp b/src/main.cpp index 32ae3c7..b902aa7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,15 +14,15 @@ int main(int argc, char* argv[]) { launcher.CheckKey(); launcher.QueryRegistry(); //UI call - //download mod + launcher.SetupMOD(); launcher.LaunchGame(); launcher.WaitForGame(); - - + LOG(INFO) << "Launcher shutting down"; } catch (const ShutdownException& e) { LOG(INFO) << "Launcher shutting down with reason: " << e.what(); } catch (const std::exception& e) { LOG(FATAL) << e.what(); } + std::this_thread::sleep_for(std::chrono::seconds(5)); return 0; }