diff --git a/.clang-format b/.clang-format index 9f9743a..c484d5e 100644 --- a/.clang-format +++ b/.clang-format @@ -39,3 +39,4 @@ SpacesInSquareBrackets: false Standard: Latest TabWidth: 2 UseTab: Never +ColumnLimit: 0 diff --git a/include/HttpAPI.h b/include/HttpAPI.h index 94fd5d1..782f553 100644 --- a/include/HttpAPI.h +++ b/include/HttpAPI.h @@ -5,12 +5,12 @@ #pragma once #include - +typedef bool (*DownloadProgress) (size_t c, size_t t); class HTTP { public: - static bool Download(const std::string& IP, const std::string& Path); + static bool Download(const std::string& IP, const std::string& Path, DownloadProgress DP = ProgressBar); static std::string Post(const std::string& IP, const std::string& Fields); - static std::string Get(const std::string& IP); + static std::string Get(const std::string& IP, DownloadProgress DP = ProgressBar); static bool ProgressBar(size_t c, size_t t); public: diff --git a/include/Launcher.h b/include/Launcher.h index 2e16ee7..3cca235 100644 --- a/include/Launcher.h +++ b/include/Launcher.h @@ -37,6 +37,8 @@ class Launcher { void LaunchGame(); void CheckKey(); void SetupMOD(); + static void AdminRelaunch(); + static void Relaunch(); static std::string QueryValue(HKEY& hKey, const char* Name); public: // Getters and Setters @@ -54,19 +56,19 @@ class Launcher { void HandleIPC(const std::string& Data); std::string GetLocalAppdata(); void UpdatePresence(); - void AdminRelaunch(); void RichPresence(); void WindowsInit(); void UpdateCheck(); void ResetMods(); void EnableMP(); - void Relaunch(); void ListenIPC(); void Abort(); public: // variables static inline std::thread EntryThread{}; static inline VersionParser SupportedVersion{"0.25.4.0"}; + static inline std::string Version{"2.0"}; + static inline std::string FullVersion{Version + ".1"}; private: // variables uint32_t GamePID{0}; @@ -83,14 +85,12 @@ class Launcher { std::string BeamVersion{}; std::string BeamUserPath{}; std::string DiscordMessage{}; - std::string Version{"2.0"}; Server ServerHandler{this}; std::string TargetBuild{"default"}; std::string GameConfigPath{}; std::string ProfileConfigPath{}; std::string CacheConfigPath{}; static inline std::atomic Shutdown{false}, Exit{false}; - std::string FullVersion{Version + ".99"}; std::unique_ptr IPCToGame{}; std::unique_ptr IPCFromGame{}; }; diff --git a/src/Launcher.cpp b/src/Launcher.cpp index 2f1b35e..4a07715 100644 --- a/src/Launcher.cpp +++ b/src/Launcher.cpp @@ -237,14 +237,14 @@ void Launcher::QueryRegistry() { void Launcher::AdminRelaunch() { system("cls"); - ShellExecuteA(nullptr, "runas", CurrentPath.string().c_str(), nullptr, + ShellExecuteA(nullptr, "runas", fs::current_path().string().c_str(), nullptr, nullptr, SW_SHOWNORMAL); ShowWindow(GetConsoleWindow(), 0); throw ShutdownException("Relaunching"); } void Launcher::Relaunch() { - ShellExecuteA(nullptr, "open", CurrentPath.string().c_str(), nullptr, + ShellExecuteA(nullptr, "open", fs::current_path().string().c_str(), nullptr, nullptr, SW_SHOWNORMAL); ShowWindow(GetConsoleWindow(), 0); std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/src/Network/HttpAPI.cpp b/src/Network/HttpAPI.cpp index 793a7ab..62f3619 100644 --- a/src/Network/HttpAPI.cpp +++ b/src/Network/HttpAPI.cpp @@ -14,7 +14,7 @@ bool HTTP::isDownload = false; std::atomic CliRef = nullptr; -std::string HTTP::Get(const std::string& IP) { +std::string HTTP::Get(const std::string& IP, DownloadProgress DP) { static std::mutex Lock; std::scoped_lock Guard(Lock); @@ -24,7 +24,7 @@ std::string HTTP::Get(const std::string& IP) { CliRef.store(&cli); cli.set_connection_timeout(std::chrono::seconds(5)); cli.set_follow_location(true); - auto res = cli.Get(IP.substr(pos).c_str(), ProgressBar); + auto res = cli.Get(IP.substr(pos).c_str(), DP); std::string Ret; if (res.error() == httplib::Error::Success) { @@ -105,12 +105,12 @@ bool HTTP::ProgressBar(size_t c, size_t t) { return true; } -bool HTTP::Download(const std::string& IP, const std::string& Path) { +bool HTTP::Download(const std::string& IP, const std::string& Path, DownloadProgress DP) { static std::mutex Lock; std::scoped_lock Guard(Lock); isDownload = true; - std::string Ret = Get(IP); + std::string Ret = Get(IP, DP); isDownload = false; if (Ret.empty()) return false; diff --git a/src/gui/Gui.cpp b/src/gui/Gui.cpp index 43107ec..33f6053 100644 --- a/src/gui/Gui.cpp +++ b/src/gui/Gui.cpp @@ -2,6 +2,7 @@ /// Created by Anonymous275 on 12/27/21 /// Copyright (c) 2021-present Anonymous275 read the LICENSE file for more info. /// +// clang-format off #include #ifndef WX_PRECOMP #include @@ -24,6 +25,7 @@ #include "HttpAPI.h" #include #endif +// clang-format on /*/////////// TestFrame class /////////// class MyTestFrame : public wxFrame { @@ -39,7 +41,7 @@ class MyTestFrame : public wxFrame { class MyApp : public wxApp { public: bool OnInit() override; - //static inline MyTestFrame* TestFrame; + // static inline MyTestFrame* TestFrame; }; /////////// AccountFrame class /////////// @@ -48,7 +50,7 @@ class MyAccountFrame : public wxFrame { MyAccountFrame(); private: - static inline wxTextCtrl* ctrlUsername, *ctrlPassword; + static inline wxTextCtrl *ctrlUsername, *ctrlPassword; bool DarkMode = wxSystemSettings::GetAppearance().IsDark(); void OnClickRegister(wxCommandEvent& event); void OnClickLogout(wxCommandEvent& event); @@ -63,12 +65,15 @@ class MyMainFrame : public wxFrame { static void GameVersionLabel(); static inline MyAccountFrame* AccountFrame; static inline MyMainFrame* MainFrameInstance; + static inline std::thread UpdateThread; + wxGauge* UpdateBar; + wxStaticText* txtUpdate; wxBitmapButton* BitAccount; void OnClickAccount(wxCommandEvent& event); private: wxStaticText* txtStatusResult; - static inline wxStaticText* txtGameVersion, *txtPlayers, *txtModVersion, *txtServers; + static inline wxStaticText *txtGameVersion, *txtPlayers, *txtModVersion, *txtServers; wxButton* btnLaunch; bool DarkMode = wxSystemSettings::GetAppearance().IsDark(); @@ -89,55 +94,56 @@ class MySettingsFrame : public wxFrame { void UpdateProfileDirectory(const std::string& path); void UpdateCacheDirectory(const std::string& path); - private: wxCheckBox* checkConsole; - wxDirPickerCtrl* ctrlGameDirectory, *ctrlProfileDirectory, *ctrlCacheDirectory; + wxDirPickerCtrl *ctrlGameDirectory, *ctrlProfileDirectory, *ctrlCacheDirectory; wxChoice* choiceController; bool DarkMode = wxSystemSettings::GetAppearance().IsDark(); void OnClickConsole(wxCommandEvent& event); - void OnChangedGameDir (wxFileDirPickerEvent& event); - void OnChangedProfileDir (wxFileDirPickerEvent& event); - void OnChangedCacheDir (wxFileDirPickerEvent& event); - void OnChangedBuild (wxCommandEvent& event); + void OnChangedGameDir(wxFileDirPickerEvent& event); + void OnChangedProfileDir(wxFileDirPickerEvent& event); + void OnChangedCacheDir(wxFileDirPickerEvent& event); + void OnChangedBuild(wxCommandEvent& event); void OnAutoDetectGame(wxCommandEvent& event); void OnAutoDetectProfile(wxCommandEvent& event); void OnResetCache(wxCommandEvent& event); wxDECLARE_EVENT_TABLE(); }; +// clang-format off /////////// Event Tables /////////// -//MainFrame (ID range 1 to 99): +// MainFrame (ID range 1 to 99): wxBEGIN_EVENT_TABLE(MyMainFrame, wxFrame) - EVT_BUTTON(1, MyMainFrame::OnClickAccount) - EVT_BUTTON(2, MyMainFrame::OnClickSettings) - EVT_BUTTON(3, MyMainFrame::OnClickLaunch) - EVT_BUTTON(4, MyMainFrame::OnClickLogo) - wxEND_EVENT_TABLE() + EVT_BUTTON(1, MyMainFrame::OnClickAccount) + EVT_BUTTON(2, MyMainFrame::OnClickSettings) + EVT_BUTTON(3, MyMainFrame::OnClickLaunch) + EVT_BUTTON(4, MyMainFrame::OnClickLogo) +wxEND_EVENT_TABLE() - //AccountFrame (ID range 100 to 199): - wxBEGIN_EVENT_TABLE(MyAccountFrame, wxFrame) - EVT_BUTTON(100, MyAccountFrame::OnClickLogout) - EVT_BUTTON(101, MyAccountFrame::OnClickRegister) - EVT_BUTTON(102, MyAccountFrame::OnClickLogin) - wxEND_EVENT_TABLE() +// AccountFrame (ID range 100 to 199): +wxBEGIN_EVENT_TABLE(MyAccountFrame, wxFrame) + EVT_BUTTON(100, MyAccountFrame::OnClickLogout) + EVT_BUTTON(101, MyAccountFrame::OnClickRegister) + EVT_BUTTON(102, MyAccountFrame::OnClickLogin) +wxEND_EVENT_TABLE() - //SettingsFrame (ID range 200 to 299): - wxBEGIN_EVENT_TABLE(MySettingsFrame, wxFrame) - EVT_DIRPICKER_CHANGED(200, MySettingsFrame::OnChangedGameDir) - EVT_DIRPICKER_CHANGED(201, MySettingsFrame::OnChangedProfileDir) - EVT_DIRPICKER_CHANGED(202, MySettingsFrame::OnChangedCacheDir) - EVT_BUTTON(203, MySettingsFrame::OnAutoDetectGame) - EVT_BUTTON(204, MySettingsFrame::OnAutoDetectProfile) - EVT_BUTTON(205, MySettingsFrame::OnResetCache) - EVT_CHOICE(206, MySettingsFrame::OnChangedBuild) - EVT_CHECKBOX(207, MySettingsFrame::OnClickConsole) - wxEND_EVENT_TABLE() +// SettingsFrame (ID range 200 to 299): +wxBEGIN_EVENT_TABLE(MySettingsFrame, wxFrame) + EVT_DIRPICKER_CHANGED(200, MySettingsFrame::OnChangedGameDir) + EVT_DIRPICKER_CHANGED(201, MySettingsFrame::OnChangedProfileDir) + EVT_DIRPICKER_CHANGED(202, MySettingsFrame::OnChangedCacheDir) + EVT_BUTTON(203, MySettingsFrame::OnAutoDetectGame) + EVT_BUTTON(204, MySettingsFrame::OnAutoDetectProfile) + EVT_BUTTON(205, MySettingsFrame::OnResetCache) + EVT_CHOICE(206, MySettingsFrame::OnChangedBuild) + EVT_CHECKBOX(207, MySettingsFrame::OnClickConsole) +wxEND_EVENT_TABLE(); +// clang-format on - /////////// Get Stats Function /////////// - void MyMainFrame::GetStats () { +/////////// Get Stats Function /////////// +void MyMainFrame::GetStats() { std::string results = HTTP::Get("https://backend.beammp.com/stats_raw"); nlohmann::json jf = nlohmann::json::parse(results, nullptr, false); @@ -148,12 +154,12 @@ wxBEGIN_EVENT_TABLE(MyMainFrame, wxFrame) if (jf["Players"].get() < 559) txtPlayers->SetForegroundColour("green"); else - txtPlayers->SetForegroundColour(wxColour(255,173,0)); + txtPlayers->SetForegroundColour(wxColour(255, 173, 0)); if (jf["PublicServers"].get() > 679) txtServers->SetForegroundColour("green"); else - txtServers->SetForegroundColour(wxColour(255,173,0)); + txtServers->SetForegroundColour(wxColour(255, 173, 0)); } else { txtPlayers->SetLabel("NA"); @@ -191,6 +197,81 @@ void MySettingsFrame::UpdateCacheDirectory(const std::string& path) { UIData::CachePath = path; } +/////////// UpdateConfig Function /////////// +template +void UpdateConfig(const std::string& key, ValueType&& value) { + if (fs::exists("Launcher.toml")) { + toml::parse_result config = toml::parse_file("Launcher.toml"); + config.insert_or_assign(key, value); + + std::ofstream tml("Launcher.toml"); + if (tml.is_open()) { + tml << config; + tml.close(); + } else wxMessageBox("Failed to modify config file", "Error"); + } +} + +/////////// Auto Detect Game Function /////////// +std::string AutoDetectGame() { + HKEY BeamNG; + std::string GamePath; + LONG RegRes = + RegOpenKeyExA(HKEY_CURRENT_USER, R"(Software\BeamNG\BeamNG.drive)", 0, + KEY_READ, &BeamNG); + if (RegRes == ERROR_SUCCESS) { + GamePath = Launcher::QueryValue(BeamNG, "rootpath"); + RegCloseKey(BeamNG); + } + if (!GamePath.empty()) { + if (GamePath.ends_with('\\')) GamePath.pop_back(); + UpdateConfig("GamePath", GamePath); + return GamePath; + } else { + wxMessageBox("Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive", "Error"); + return ""; + } +} + +/////////// Auto Detect Profile Function /////////// +std::string AutoDetectProfile() { + HKEY BeamNG; + std::string ProfilePath; + LONG RegRes = + RegOpenKeyExA(HKEY_CURRENT_USER, R"(Software\BeamNG\BeamNG.drive)", 0, + KEY_READ, &BeamNG); + if (RegRes == ERROR_SUCCESS) { + ProfilePath = Launcher::QueryValue(BeamNG, "userpath_override"); + RegCloseKey(BeamNG); + } + if (ProfilePath.empty()) { + PWSTR folderPath = nullptr; + HRESULT hr = + SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &folderPath); + + if (!SUCCEEDED(hr)) { + wxMessageBox( + "Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive", + "Error"); + return ""; + } else { + _bstr_t bstrPath(folderPath); + std::string Path((char*)bstrPath); + CoTaskMemFree(folderPath); + ProfilePath = Path + "\\BeamNG.drive"; + } + } + UpdateConfig("ProfilePath", ProfilePath); + return ProfilePath; +} + +/////////// Reset Cache Function /////////// +std::string ResetCache() { + std::string CachePath = fs::current_path().append("Resources").string(); + UpdateConfig("CachePath", CachePath); + return CachePath; +} + /////////// Load Config Function /////////// void LoadConfig() { if (fs::exists("Launcher.toml")) { @@ -227,11 +308,14 @@ void LoadConfig() { if (tml.is_open()) { tml << "UI = true\n" "Build = 'Default'\n" - "GamePath = 'C:\\Program Files'\n" - "ProfilePath = 'C:\\Program Files'\n" - "CachePath = 'Resources'\n" + "GamePath = ''\n" + "ProfilePath = ''\n" + "CachePath = ''\n" "Console = false"; tml.close(); + AutoDetectGame(); + AutoDetectProfile(); + ResetCache(); LoadConfig(); } else wxMessageBox("Failed to create config file", "Error"); } @@ -290,7 +374,7 @@ void CheckKey() { Json d = Json::parse(Buffer, nullptr, false); if (Buffer == "-1" || Buffer.at(0) != '{' || d.is_discarded()) { - wxMessageBox( "Couldn't connect to auth server, you might be offline!", "Warning", wxICON_WARNING); + wxMessageBox("Couldn't connect to auth server, you might be offline!", "Warning", wxICON_WARNING); return; } if (d["success"].get()) { @@ -298,18 +382,17 @@ void CheckKey() { UpdateKey(d["private_key"].get()); UIData::PublicKey = d["public_key"].get(); UIData::UserRole = d["role"].get(); - UIData::Username = d["username"].get(); + UIData::Username = d["username"].get(); } else UpdateKey(""); } else UpdateKey(""); } else UpdateKey(""); } -void WindowsConsole (bool isChecked); - +void WindowsConsole(bool isChecked); +void UpdateCheck(); /////////// OnInit Function /////////// bool MyApp::OnInit() { - - if(!fs::exists("icons")) { + if (!fs::exists("icons")) { fs::create_directory("icons"); } @@ -319,9 +402,11 @@ bool MyApp::OnInit() { WindowsConsole(UIData::Console); - auto* MainFrame = new MyMainFrame(); + auto* MainFrame = new MyMainFrame(); MyMainFrame::MainFrameInstance = MainFrame; - MainFrame->SetIcon(wxIcon("icons/BeamMP_black.png",wxBITMAP_TYPE_PNG)); + MyMainFrame::UpdateThread = std::thread (UpdateCheck); + + MainFrame->SetIcon(wxIcon("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG)); // Set MainFrame properties: MainFrame->SetSize(1000, 650); @@ -330,15 +415,14 @@ bool MyApp::OnInit() { if (wxSystemSettings::GetAppearance().IsDark()) { MainFrame->SetBackgroundColour(wxColour(40, 40, 40)); MainFrame->SetForegroundColour(wxColour(255, 255, 255)); - } - else { + } else { MainFrame->SetBackgroundColour(wxColour("white")); MainFrame->SetForegroundColour(wxColour("white")); } wxFileSystem::AddHandler(new wxInternetFSHandler); MainFrame->Show(true); - //Test Frame Properties: + // Test Frame Properties: /*TestFrame = new MyTestFrame(); TestFrame->SetIcon(wxIcon("icons/BeamMP_black.png",wxBITMAP_TYPE_PNG)); @@ -359,7 +443,7 @@ bool MyApp::OnInit() { } /////////// Windows Console Function /////////// -void WindowsConsole (bool isChecked) { +void WindowsConsole(bool isChecked) { if (isChecked) { AllocConsole(); FILE* pNewStdout = nullptr; @@ -369,8 +453,7 @@ void WindowsConsole (bool isChecked) { ::freopen_s(&pNewStdout, "CONOUT$", "w", stdout); ::freopen_s(&pNewStderr, "CONOUT$", "w", stderr); ::freopen_s(&pNewStdin, "CONIN$", "r", stdin); - } - else { + } else { FreeConsole(); ::fclose(stdout); ::fclose(stderr); @@ -389,36 +472,92 @@ void WindowsConsole (bool isChecked) { } /////////// Read json Function /////////// -std::string jsonRead () { - fs::path path = fs::path (UIData::GamePath).append("integrity.json"); +std::string jsonRead() { + fs::path path = fs::path(UIData::GamePath).append("integrity.json"); if (fs::exists(path)) { std::ifstream ifs(path); nlohmann::json jf = nlohmann::json::parse(ifs, nullptr, false); if (!jf.is_discarded() && !jf.empty()) return jf["version"]; - } - else wxMessageBox("Couldn't read game version, check game path in settings", "Error"); + } else wxMessageBox("Couldn't read game version, check game path in settings", "Error"); return ""; } /////////// Picture Type Function /////////// // JPG 0 / PNG 1 -std::string PictureType (const std::string& picture) { +std::string PictureType(const std::string& picture) { for (int i = 0; i < 15; i++) { - if(picture[i] == 'J') + if (picture[i] == 'J') return ".jpg"; - else if (picture[i] == 'P' && picture[i+1] == 'N') + else if (picture[i] == 'P' && picture[i + 1] == 'N') return ".png"; } return ""; } /////////// Get Picture Name Function /////////// -std::string GetPictureName () { +std::string GetPictureName() { for (const auto& entry : fs::recursive_directory_iterator("icons")) { if (entry.path().filename().string().find(UIData::Username) != std::string::npos) { return entry.path().string(); } } + return ""; +} + +bool ProgressBar (size_t c, size_t t) { + int Percent = int(round(double(c) / double(t) * 100)); + MyMainFrame::MainFrameInstance->UpdateBar->SetValue(Percent); + MyMainFrame::MainFrameInstance->txtUpdate->SetLabel("Downloading " + std::to_string(Percent) + "%"); + return true; +} + +/////////// Update Check Function /////////// +void UpdateCheck() { + std::string link; + std::string HTTP = HTTP::Get("https://beammp.com/builds/launcher?version=true"); + bool fallback = false; + if (HTTP.find_first_of("0123456789") == std::string::npos) { + HTTP = HTTP::Get("https://backup1.beammp.com/builds/launcher?version=true"); + fallback = true; + if (HTTP.find_first_of("0123456789") == std::string::npos) + wxMessageBox("Primary Servers Offline! sorry for the inconvenience!", "Error"); + } + if (fallback) { + link = "https://backup1.beammp.com/builds/launcher?download=true"; + } else link = "https://beammp.com/builds/launcher?download=true"; + auto CurrentPath = fs::current_path(); + std::string EP(CurrentPath.append("BeamMP-Launcher.exe").string()), Back(CurrentPath.append("BeamMP-Launcher.back").string()); + LOG(INFO) < VersionParser(Launcher::FullVersion)) { + system("cls"); + MyMainFrame::MainFrameInstance->txtUpdate->SetLabel("Downloading..."); + if (std::rename(EP.c_str(), Back.c_str())) { + wxMessageBox("Failed to create a backup!", "Error"); + } + + if (!HTTP::Download(link, EP, ProgressBar)) { + wxMessageBox("Launcher Update failed! trying again...", "Error"); + + std::this_thread::sleep_for(std::chrono::seconds(2)); + + if (!HTTP::Download(link, EP, ProgressBar)) { + wxMessageBox("Launcher Update failed!", "Error"); + std::this_thread::sleep_for(std::chrono::seconds(5)); + Launcher::AdminRelaunch(); + } + } + Launcher::Relaunch(); + } else MyMainFrame::MainFrameInstance->txtUpdate->SetLabel("BeamMP V" + Launcher::FullVersion); + } /////////// TestFrame Function /////////// @@ -433,57 +572,57 @@ file->SetForegroundColour("white"); /////////// Main Frame Content /////////// MyMainFrame::MyMainFrame() : - wxFrame(nullptr, wxID_ANY, "BeamMP Launcher V3", wxDefaultPosition,wxDefaultSize, + wxFrame(nullptr, wxID_ANY, "BeamMP Launcher V3", wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX) { - auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(1000,650)); + auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(1000, 650)); - //News: - wxWebView::New() ->Create(panel, wxID_ANY, "https://beammp.com", wxPoint(10, 70), wxSize(950, 400)); + // News: + wxWebView::New()->Create(panel, wxID_ANY, "https://beammp.com", wxPoint(10, 70), wxSize(950, 400)); auto* txtNews = new wxStaticText(panel, wxID_ANY, wxT("News"), wxPoint(10, 40)); MyMainFrame::SetFocus(); auto* HorizontalLine1 = new wxStaticLine(panel, wxID_ANY, wxPoint(10, 60), wxSize(950, 1)); auto* HorizontalLine2 = new wxStaticLine(panel, wxID_ANY, wxPoint(10, 480), wxSize(950, 1)); - //Hyperlinks: - auto* HyperForum = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Forum"), wxT("https://forum.beammp.com"), wxPoint(10, 10)); + // Hyperlinks: + auto* HyperForum = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Forum"), wxT("https://forum.beammp.com"), wxPoint(10, 10)); auto* txtSeparator1 = new wxStaticText(panel, wxID_ANY, wxT("|"), wxPoint(55, 10)); - auto* HyperDiscord = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Discord"), wxT("https://discord.gg/beammp"), wxPoint(70, 10)); + auto* HyperDiscord = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Discord"), wxT("https://discord.gg/beammp"), wxPoint(70, 10)); auto* txtSeparator2 = new wxStaticText(panel, wxID_ANY, wxT("|"), wxPoint(120, 10)); - auto* HyperGithub = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("GitHub"), wxT("https://github.com/BeamMP"), wxPoint(130, 10)); + auto* HyperGithub = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("GitHub"), wxT("https://github.com/BeamMP"), wxPoint(130, 10)); auto* txtSeparator3 = new wxStaticText(panel, wxID_ANY, wxT("|"), wxPoint(180, 10)); - auto* HyperWiki = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Wiki"), wxT("https://wiki.beammp.com"), wxPoint(195, 10)); + auto* HyperWiki = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Wiki"), wxT("https://wiki.beammp.com"), wxPoint(195, 10)); auto* txtSeparator4 = new wxStaticText(panel, wxID_ANY, wxT("|"), wxPoint(230, 10)); auto* HyperPatreon = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Patreon"), wxT("https://www.patreon.com/BeamMP"), wxPoint(240, 10)); - //Update: - auto* txtUpdate = new wxStaticText(panel, wxID_ANY, wxT("Updating BeamMP "), wxPoint(10, 490)); + // Update: + txtUpdate = new wxStaticText(panel, wxID_ANY, wxT("Updating BeamMP "), wxPoint(10, 490)); - auto* UpdateBar = new wxGauge(panel, wxID_ANY, 100, wxPoint(10, 520), wxSize(127, -1)); + UpdateBar = new wxGauge(panel, wxID_ANY, 100, wxPoint(10, 520), wxSize(127, -1)); UpdateBar->SetValue(0); - while (UpdateBar->GetValue() <76) { + while (UpdateBar->GetValue() < 101) { txtUpdate->SetLabel(wxT("Updating BeamMP: " + std::to_string(UpdateBar->GetValue()) + "%")); UpdateBar->SetValue(UpdateBar->GetValue() + 1); } - //Information: + // Information: auto* txtGameVersionTitle = new wxStaticText(panel, wxID_ANY, wxT("Game Version: "), wxPoint(160, 490)); - txtGameVersion = new wxStaticText(panel, wxID_ANY, "NA", wxPoint(240, 490)); + txtGameVersion = new wxStaticText(panel, wxID_ANY, "NA", wxPoint(240, 490)); auto* txtPlayersTitle = new wxStaticText(panel, wxID_ANY, wxT("Currently Playing:"), wxPoint(300, 490)); - txtPlayers = new wxStaticText(panel, wxID_ANY, wxT("NA"), wxPoint(400, 490)); + txtPlayers = new wxStaticText(panel, wxID_ANY, wxT("NA"), wxPoint(400, 490)); auto* txtPatreon = new wxStaticText(panel, wxID_ANY, wxT("Special thanks to our Patreon Members!"), wxPoint(570, 490)); auto* txtModVersionTitle = new wxStaticText(panel, wxID_ANY, wxT("Mod Version:"), wxPoint(160, 520)); - txtModVersion = new wxStaticText(panel, wxID_ANY, wxT("NA"), wxPoint(235, 520)); + txtModVersion = new wxStaticText(panel, wxID_ANY, wxT("NA"), wxPoint(235, 520)); auto* txtServersTitle = new wxStaticText(panel, wxID_ANY, wxT("Available Servers:"), wxPoint(300, 520)); - txtServers = new wxStaticText(panel, wxID_ANY, wxT("NA"), wxPoint(395, 520)); + txtServers = new wxStaticText(panel, wxID_ANY, wxT("NA"), wxPoint(395, 520)); auto* txtStatus = new wxStaticText(panel, wxID_ANY, wxT("Status: "), wxPoint(880, 520)); txtStatusResult = new wxStaticText(panel, wxID_ANY, wxT("Online"), wxPoint(920, 520)); @@ -492,30 +631,30 @@ MyMainFrame::MyMainFrame() : wxInitAllImageHandlers(); - //Account: - BitAccount = new wxBitmapButton(panel, 1, wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(45,45, wxIMAGE_QUALITY_HIGH)), wxPoint(20, 560), wxSize(45,45)); + // Account: + BitAccount = new wxBitmapButton(panel, 1, wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(45, 45, wxIMAGE_QUALITY_HIGH)), wxPoint(20, 560), wxSize(45, 45)); std::string PictureString = GetPictureName(); - if (UIData::LoginAuth && fs::exists( PictureString)) - BitAccount->SetBitmap(wxBitmapBundle(wxImage( PictureString).Scale(45, 45, wxIMAGE_QUALITY_HIGH))); + if (UIData::LoginAuth && fs::exists(PictureString)) + BitAccount->SetBitmap(wxBitmapBundle(wxImage(PictureString).Scale(45, 45, wxIMAGE_QUALITY_HIGH))); else - BitAccount->SetBitmap(wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(45,45, wxIMAGE_QUALITY_HIGH))); + BitAccount->SetBitmap(wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(45, 45, wxIMAGE_QUALITY_HIGH))); - //Buttons: - auto btnSettings = new wxButton(panel, 2, wxT("Settings"), wxPoint(730,570), wxSize(110, 25)); - btnLaunch = new wxButton(panel, 3, wxT("Launch"), wxPoint(850,570), wxSize(110, 25)); + // Buttons: + auto btnSettings = new wxButton(panel, 2, wxT("Settings"), wxPoint(730, 570), wxSize(110, 25)); + btnLaunch = new wxButton(panel, 3, wxT("Launch"), wxPoint(850, 570), wxSize(110, 25)); GetStats(); - //UI Colors: + // UI Colors: GameVersionLabel(); if (DarkMode) { - //Text Separators: + // Text Separators: txtSeparator1->SetForegroundColour("white"); txtSeparator2->SetForegroundColour("white"); txtSeparator3->SetForegroundColour("white"); txtSeparator4->SetForegroundColour("white"); - //Texts: + // Texts: txtNews->SetForegroundColour("white"); txtUpdate->SetForegroundColour("white"); txtGameVersionTitle->SetForegroundColour("white"); @@ -526,64 +665,63 @@ MyMainFrame::MyMainFrame() : txtPatreon->SetForegroundColour("white"); txtStatus->SetForegroundColour("white"); - //Line Separators: + // Line Separators: HorizontalLine1->SetForegroundColour("white"); HorizontalLine2->SetForegroundColour("white"); HorizontalLine3->SetForegroundColour("white"); - //Logo: - auto* logo = new wxBitmapButton(panel, 4, wxBitmapBundle(wxImage("icons/BeamMP_white.png", wxBITMAP_TYPE_PNG).Scale(100,100, wxIMAGE_QUALITY_HIGH)), wxPoint(850, -15), wxSize(100,100), wxBORDER_NONE); + // Logo: + auto* logo = new wxBitmapButton(panel, 4, wxBitmapBundle(wxImage("icons/BeamMP_white.png", wxBITMAP_TYPE_PNG).Scale(100, 100, wxIMAGE_QUALITY_HIGH)), wxPoint(850, -15), wxSize(100, 100), wxBORDER_NONE); logo->SetBackgroundColour(wxColour(40, 40, 40)); - } - else { - //Logo: - auto* logo = new wxBitmapButton(panel, 4, wxBitmapBundle(wxImage("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG).Scale(100,100, wxIMAGE_QUALITY_HIGH)), wxPoint(850, -15), wxSize(100,100), wxBORDER_NONE); + } else { + // Logo: + auto* logo = new wxBitmapButton(panel, 4, wxBitmapBundle(wxImage("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG).Scale(100, 100, wxIMAGE_QUALITY_HIGH)), wxPoint(850, -15), wxSize(100, 100), wxBORDER_NONE); logo->SetBackgroundColour("white"); } txtStatusResult->SetForegroundColour("green"); } /////////// Account Frame Content /////////// -MyAccountFrame::MyAccountFrame() : wxFrame(nullptr, wxID_ANY, "Account Manager", wxDefaultPosition,wxDefaultSize, +MyAccountFrame::MyAccountFrame() : + wxFrame(nullptr, wxID_ANY, "Account Manager", wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX) { MyAccountFrame::SetFocus(); - auto *handler = new wxPNGHandler; + auto* handler = new wxPNGHandler; wxImage::AddHandler(handler); - wxStaticBitmap *image; - image = new wxStaticBitmap( this, wxID_ANY, wxBitmapBundle(wxImage("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG).Scale(120,120, wxIMAGE_QUALITY_HIGH)), wxPoint(180,20), wxSize(120, 120)); - auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(500,650)); + wxStaticBitmap* image; + image = new wxStaticBitmap(this, wxID_ANY, wxBitmapBundle(wxImage("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG).Scale(120, 120, wxIMAGE_QUALITY_HIGH)), wxPoint(180, 20), wxSize(120, 120)); + auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(500, 650)); std::string PictureString = GetPictureName(); if (UIData::LoginAuth) { - if (fs::exists( PictureString)) - image->SetBitmap(wxBitmapBundle(wxImage( PictureString).Scale(120, 120, wxIMAGE_QUALITY_HIGH))); + if (fs::exists(PictureString)) + image->SetBitmap(wxBitmapBundle(wxImage(PictureString).Scale(120, 120, wxIMAGE_QUALITY_HIGH))); else - image->SetBitmap(wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(120,120, wxIMAGE_QUALITY_HIGH))); + image->SetBitmap(wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(120, 120, wxIMAGE_QUALITY_HIGH))); - auto* txtName = new wxStaticText(panel, wxID_ANY, wxT("Username: " + UIData::Username), wxPoint(180, 200)); - auto btnLogout = new wxButton(panel, 100, wxT("Logout"), wxPoint(185,550), wxSize(110, 25)); + auto* txtName = new wxStaticText(panel, wxID_ANY, wxT("Username: " + UIData::Username), wxPoint(180, 200)); + auto btnLogout = new wxButton(panel, 100, wxT("Logout"), wxPoint(185, 550), wxSize(110, 25)); - //UI Colors: + // UI Colors: if (DarkMode) { - //Text: + // Text: txtName->SetForegroundColour("white"); } - } - else { - image->SetBitmap(wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(120,120, wxIMAGE_QUALITY_HIGH))); + } else { + image->SetBitmap(wxBitmapBundle(wxImage("icons/default.png", wxBITMAP_TYPE_PNG).Scale(120, 120, wxIMAGE_QUALITY_HIGH))); auto* txtLogin = new wxStaticText(panel, wxID_ANY, wxT("Login with your BeamMP account."), wxPoint(150, 200)); - ctrlUsername = new wxTextCtrl (panel, wxID_ANY, wxT(""), wxPoint(131, 230), wxSize(220,25)); - ctrlPassword = new wxTextCtrl (panel, wxID_ANY, wxT(""), wxPoint(131, 300), wxSize(220,25), wxTE_PASSWORD); + ctrlUsername = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxPoint(131, 230), wxSize(220, 25)); + ctrlPassword = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxPoint(131, 300), wxSize(220, 25), wxTE_PASSWORD); ctrlUsername->SetHint("Username / Email"); ctrlPassword->SetHint("Password"); - auto btnRegister = new wxButton(panel, 101, wxT("Register"), wxPoint(250,375), wxSize(110, 25)); - auto btnLogin = new wxButton(panel, 102, wxT("Login"), wxPoint(120,375), wxSize(110, 25)); + auto btnRegister = new wxButton(panel, 101, wxT("Register"), wxPoint(250, 375), wxSize(110, 25)); + auto btnLogin = new wxButton(panel, 102, wxT("Login"), wxPoint(120, 375), wxSize(110, 25)); - //UI Colors: + // UI Colors: if (DarkMode) { - //Text: + // Text: txtLogin->SetForegroundColour("white"); } } @@ -591,25 +729,25 @@ MyAccountFrame::MyAccountFrame() : wxFrame(nullptr, wxID_ANY, "Account Manager", /////////// Settings Frame Content /////////// MySettingsFrame::MySettingsFrame() : - wxFrame(nullptr, wxID_ANY, "Settings", wxDefaultPosition,wxDefaultSize, + wxFrame(nullptr, wxID_ANY, "Settings", wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX) { - auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(500,650)); + auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(500, 650)); auto* txtGameDirectory = new wxStaticText(panel, wxID_ANY, wxT("Game Directory: "), wxPoint(30, 100)); - ctrlGameDirectory = new wxDirPickerCtrl (panel, 200, wxEmptyString, wxT("Game Directory"), wxPoint(130, 100), wxSize(300,-1)); + ctrlGameDirectory = new wxDirPickerCtrl(panel, 200, wxEmptyString, wxT("Game Directory"), wxPoint(130, 100), wxSize(300, -1)); ctrlGameDirectory->SetLabel("GamePath"); MySettingsFrame::SetFocus(); - auto btnDetectGameDirectory = new wxButton(panel, 203, wxT("Detect"), wxPoint(185,140), wxSize(90, 25)); + auto btnDetectGameDirectory = new wxButton(panel, 203, wxT("Detect"), wxPoint(185, 140), wxSize(90, 25)); auto* txtProfileDirectory = new wxStaticText(panel, wxID_ANY, wxT("Profile Directory: "), wxPoint(30, 200)); - ctrlProfileDirectory = new wxDirPickerCtrl (panel, 201, wxEmptyString, wxT("Profile Directory"), wxPoint(130, 200), wxSize(300,-1)); + ctrlProfileDirectory = new wxDirPickerCtrl(panel, 201, wxEmptyString, wxT("Profile Directory"), wxPoint(130, 200), wxSize(300, -1)); ctrlProfileDirectory->SetLabel("ProfilePath"); - auto btnDetectProfileDirectory = new wxButton(panel, 204, wxT("Detect"), wxPoint(185,240), wxSize(90, 25)); + auto btnDetectProfileDirectory = new wxButton(panel, 204, wxT("Detect"), wxPoint(185, 240), wxSize(90, 25)); auto* txtCacheDirectory = new wxStaticText(panel, wxID_ANY, wxT("Cache Directory: "), wxPoint(30, 300)); - ctrlCacheDirectory = new wxDirPickerCtrl (panel, 202, wxEmptyString, wxT("Cache Directory"), wxPoint(130, 300), wxSize(300,-1)); + ctrlCacheDirectory = new wxDirPickerCtrl(panel, 202, wxEmptyString, wxT("Cache Directory"), wxPoint(130, 300), wxSize(300, -1)); ctrlCacheDirectory->SetLabel("CachePath"); - auto btnCacheDirectory = new wxButton(panel, 205, wxT("Reset"), wxPoint(185,340), wxSize(90, 25)); + auto btnCacheDirectory = new wxButton(panel, 205, wxT("Reset"), wxPoint(185, 340), wxSize(90, 25)); auto* txtBuild = new wxStaticText(panel, wxID_ANY, wxT("Build: "), wxPoint(30, 400)); wxArrayString BuildChoices; @@ -617,42 +755,27 @@ MySettingsFrame::MySettingsFrame() : BuildChoices.Add("Release"); BuildChoices.Add("EA"); BuildChoices.Add("Dev"); - choiceController = new wxChoice (panel, 206, wxPoint(85, 400), wxSize(120, 20), BuildChoices); + choiceController = new wxChoice(panel, 206, wxPoint(85, 400), wxSize(120, 20), BuildChoices); choiceController->Select(0); - checkConsole = new wxCheckBox (panel, 207, " Show Console", wxPoint(30, 450)); + checkConsole = new wxCheckBox(panel, 207, " Show Console", wxPoint(30, 450)); - //UI Colors: + // UI Colors: if (DarkMode) { - //Text: + // Text: txtGameDirectory->SetForegroundColour("white"); txtProfileDirectory->SetForegroundColour("white"); txtCacheDirectory->SetForegroundColour("white"); txtBuild->SetForegroundColour("white"); checkConsole->SetForegroundColour("white"); - //Style: + // Style: ctrlCacheDirectory->SetWindowStyle(wxBORDER_NONE); ctrlProfileDirectory->SetWindowStyle(wxBORDER_NONE); ctrlGameDirectory->SetWindowStyle(wxBORDER_NONE); } } -/////////// UpdateConfig Function /////////// -template -void UpdateConfig (const std::string& key, ValueType&& value) { - if (fs::exists("Launcher.toml")) { - toml::parse_result config = toml::parse_file("Launcher.toml"); - config.insert_or_assign(key, value); - - std::ofstream tml("Launcher.toml"); - if (tml.is_open()) { - tml << config; - tml.close(); - } else wxMessageBox("Failed to modify config file", "Error"); - } -} - /////////// Game Version Label Function /////////// void MyMainFrame::GameVersionLabel() { std::string read = jsonRead(); @@ -660,7 +783,7 @@ void MyMainFrame::GameVersionLabel() { txtGameVersion->SetLabel(read); VersionParser CurrentVersion(read); if (CurrentVersion > Launcher::SupportedVersion) - txtGameVersion->SetForegroundColour(wxColour(255,173,0)); + txtGameVersion->SetForegroundColour(wxColour(255, 173, 0)); else if (CurrentVersion < Launcher::SupportedVersion) txtGameVersion->SetForegroundColour("red"); else txtGameVersion->SetForegroundColour("green"); @@ -675,13 +798,12 @@ void MyMainFrame::OnClickAccount(wxCommandEvent& event WXUNUSED(event)) { AccountFrame = new MyAccountFrame(); AccountFrame->SetSize(500, 650); AccountFrame->Center(); - AccountFrame->SetIcon(wxIcon("icons/BeamMP_black.png",wxBITMAP_TYPE_PNG)); + AccountFrame->SetIcon(wxIcon("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG)); if (wxSystemSettings::GetAppearance().IsDark()) { AccountFrame->SetBackgroundColour(wxColour(40, 40, 40)); AccountFrame->SetForegroundColour(wxColour(255, 255, 255)); - } - else { + } else { AccountFrame->SetBackgroundColour(wxColour("white")); AccountFrame->SetForegroundColour(wxColour("white")); } @@ -693,13 +815,12 @@ void MyMainFrame::OnClickSettings(wxCommandEvent& event WXUNUSED(event)) { auto* SettingsFrame = new MySettingsFrame(); SettingsFrame->SetSize(500, 650); SettingsFrame->Center(); - SettingsFrame->SetIcon(wxIcon("icons/BeamMP_black.png",wxBITMAP_TYPE_PNG)); + SettingsFrame->SetIcon(wxIcon("icons/BeamMP_black.png", wxBITMAP_TYPE_PNG)); if (wxSystemSettings::GetAppearance().IsDark()) { SettingsFrame->SetBackgroundColour(wxColour(40, 40, 40)); SettingsFrame->SetForegroundColour(wxColour(255, 255, 255)); - } - else { + } else { SettingsFrame->SetBackgroundColour(wxColour("white")); SettingsFrame->SetForegroundColour(wxColour("white")); } @@ -722,7 +843,7 @@ void MyMainFrame::OnClickLaunch(wxCommandEvent& event WXUNUSED(event)) { txtStatusResult->SetForegroundColour("purple"); btnLaunch->Disable(); - if(FirstTime) { + if (FirstTime) { wxMessageBox("Please launch BeamNG.drive manually in case of Steam issues.", "Alert"); FirstTime = false; } @@ -741,8 +862,8 @@ void MyAccountFrame::OnClickRegister(wxCommandEvent& event WXUNUSED(event)) { /////////// OnClick Login Event /////////// void MyAccountFrame::OnClickLogin(wxCommandEvent& event WXUNUSED(event)) { Json json; - json ["password"] = ctrlPassword->GetValue().utf8_string(); - json ["username"] = ctrlUsername->GetValue().utf8_string(); + json["password"] = ctrlPassword->GetValue().utf8_string(); + json["username"] = ctrlUsername->GetValue().utf8_string(); if (Login(json.dump())) { std::string picture = HTTP::Get("https://forum.beammp.com/user_avatar/forum.beammp.com/" + UIData::Username + "/240/4411_2.png"); @@ -776,7 +897,7 @@ void MySettingsFrame::OnClickConsole(wxCommandEvent& event) { /////////// OnChanged Game Path Event /////////// void MySettingsFrame::OnChangedGameDir(wxFileDirPickerEvent& event) { std::string NewPath = event.GetPath().utf8_string(); - std::string key = reinterpret_cast (event.GetEventObject())->GetLabel(); + std::string key = reinterpret_cast(event.GetEventObject())->GetLabel(); UpdateConfig(key, NewPath); UpdateGameDirectory(NewPath); } @@ -784,7 +905,7 @@ void MySettingsFrame::OnChangedGameDir(wxFileDirPickerEvent& event) { /////////// OnChanged Profile Path Event /////////// void MySettingsFrame::OnChangedProfileDir(wxFileDirPickerEvent& event) { std::string NewPath = event.GetPath().utf8_string(); - std::string key = reinterpret_cast (event.GetEventObject())->GetLabel(); + std::string key = reinterpret_cast(event.GetEventObject())->GetLabel(); UpdateConfig(key, NewPath); UpdateProfileDirectory(NewPath); } @@ -792,85 +913,49 @@ void MySettingsFrame::OnChangedProfileDir(wxFileDirPickerEvent& event) { /////////// OnChanged Cache Path Event /////////// void MySettingsFrame::OnChangedCacheDir(wxFileDirPickerEvent& event) { std::string NewPath = event.GetPath().utf8_string(); - std::string key = reinterpret_cast (event.GetEventObject())->GetLabel(); + std::string key = reinterpret_cast(event.GetEventObject())->GetLabel(); UpdateConfig(key, NewPath); UpdateCacheDirectory(NewPath); } /////////// OnChanged Build Event /////////// void MySettingsFrame::OnChangedBuild(wxCommandEvent& event) { - std::string key = reinterpret_cast (event.GetEventObject())->GetString(event.GetSelection()); + std::string key = reinterpret_cast(event.GetEventObject())->GetString(event.GetSelection()); UpdateConfig("Build", key); UIData::Build = key; } /////////// AutoDetect Game Function /////////// -void MySettingsFrame::OnAutoDetectGame (wxCommandEvent& event) { - HKEY BeamNG; - std::string GamePath; - LONG RegRes = - RegOpenKeyExA(HKEY_CURRENT_USER, R"(Software\BeamNG\BeamNG.drive)", 0, - KEY_READ, &BeamNG); - if (RegRes == ERROR_SUCCESS) { - GamePath = Launcher::QueryValue(BeamNG, "rootpath"); - RegCloseKey(BeamNG); - } - if (!GamePath.empty()) { - if (GamePath.ends_with('\\')) GamePath.pop_back(); - UpdateConfig("GamePath", GamePath); - UpdateGameDirectory(GamePath); - } - else - wxMessageBox("Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive", "Error"); +void MySettingsFrame::OnAutoDetectGame(wxCommandEvent& event) { + UpdateGameDirectory(AutoDetectGame()); } /////////// AutoDetect Profile Function /////////// -void MySettingsFrame::OnAutoDetectProfile(wxCommandEvent& event){ - HKEY BeamNG; - std::string ProfilePath; - LONG RegRes = - RegOpenKeyExA(HKEY_CURRENT_USER, R"(Software\BeamNG\BeamNG.drive)", 0, - KEY_READ, &BeamNG); - if (RegRes == ERROR_SUCCESS) { - ProfilePath = Launcher::QueryValue(BeamNG, "userpath_override"); - RegCloseKey(BeamNG); - } - if (ProfilePath.empty()) { - PWSTR folderPath = nullptr; - HRESULT hr = - SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &folderPath); - - if (!SUCCEEDED(hr)) { - wxMessageBox( - "Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive", - "Error"); - return; - } - else { - _bstr_t bstrPath(folderPath); - std::string Path((char*)bstrPath); - CoTaskMemFree(folderPath); - ProfilePath = Path + "\\BeamNG.drive"; - } - } - UpdateConfig("ProfilePath", ProfilePath); - ctrlProfileDirectory->SetPath(ProfilePath); +void MySettingsFrame::OnAutoDetectProfile(wxCommandEvent& event) { + UpdateProfileDirectory(AutoDetectProfile()); } /////////// Reset Cache Function /////////// void MySettingsFrame::OnResetCache(wxCommandEvent& event) { - std::string CachePath = fs::current_path().append("Resources").string(); - UpdateConfig("CachePath", CachePath); - ctrlCacheDirectory->SetPath(CachePath); + UpdateCacheDirectory(ResetCache()); } /////////// MAIN FUNCTION /////////// int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { wxDisableAsserts(); wxLog::SetLogLevel(wxLOG_Info); - new MyApp(); - int result = wxEntry(hInstance, hPrevInstance, lpCmdLine, nShowCmd); - if (Launcher::EntryThread.joinable()) - Launcher::EntryThread.join(); + int result = 0; + try { + new MyApp(); + result = wxEntry(hInstance, hPrevInstance, lpCmdLine, nShowCmd); + if (Launcher::EntryThread.joinable()) + Launcher::EntryThread.join(); + if (MyMainFrame::UpdateThread.joinable()) + MyMainFrame::UpdateThread.join(); + } catch (const ShutdownException& e) { + LOG(INFO) << "Launcher shutting down with reason: " << e.what(); + } catch (const std::exception& e) { + LOG(FATAL) << e.what(); + } return result; }