Merge pull request #39 from SamZahreddine/v3

fix auto detect on first launch
This commit is contained in:
Simon Abed El Sater 2022-08-19 12:19:53 +03:00 committed by GitHub
commit 4e8421a515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 313 additions and 227 deletions

View File

@ -39,3 +39,4 @@ SpacesInSquareBrackets: false
Standard: Latest Standard: Latest
TabWidth: 2 TabWidth: 2
UseTab: Never UseTab: Never
ColumnLimit: 0

View File

@ -5,12 +5,12 @@
#pragma once #pragma once
#include <string> #include <string>
typedef bool (*DownloadProgress) (size_t c, size_t t);
class HTTP { class HTTP {
public: 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 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); static bool ProgressBar(size_t c, size_t t);
public: public:

View File

@ -37,6 +37,8 @@ class Launcher {
void LaunchGame(); void LaunchGame();
void CheckKey(); void CheckKey();
void SetupMOD(); void SetupMOD();
static void AdminRelaunch();
static void Relaunch();
static std::string QueryValue(HKEY& hKey, const char* Name); static std::string QueryValue(HKEY& hKey, const char* Name);
public: // Getters and Setters public: // Getters and Setters
@ -54,19 +56,19 @@ class Launcher {
void HandleIPC(const std::string& Data); void HandleIPC(const std::string& Data);
std::string GetLocalAppdata(); std::string GetLocalAppdata();
void UpdatePresence(); void UpdatePresence();
void AdminRelaunch();
void RichPresence(); void RichPresence();
void WindowsInit(); void WindowsInit();
void UpdateCheck(); void UpdateCheck();
void ResetMods(); void ResetMods();
void EnableMP(); void EnableMP();
void Relaunch();
void ListenIPC(); void ListenIPC();
void Abort(); void Abort();
public: // variables public: // variables
static inline std::thread EntryThread{}; static inline std::thread EntryThread{};
static inline VersionParser SupportedVersion{"0.25.4.0"}; static inline VersionParser SupportedVersion{"0.25.4.0"};
static inline std::string Version{"2.0"};
static inline std::string FullVersion{Version + ".1"};
private: // variables private: // variables
uint32_t GamePID{0}; uint32_t GamePID{0};
@ -83,14 +85,12 @@ class Launcher {
std::string BeamVersion{}; std::string BeamVersion{};
std::string BeamUserPath{}; std::string BeamUserPath{};
std::string DiscordMessage{}; std::string DiscordMessage{};
std::string Version{"2.0"};
Server ServerHandler{this}; Server ServerHandler{this};
std::string TargetBuild{"default"}; std::string TargetBuild{"default"};
std::string GameConfigPath{}; std::string GameConfigPath{};
std::string ProfileConfigPath{}; std::string ProfileConfigPath{};
std::string CacheConfigPath{}; std::string CacheConfigPath{};
static inline std::atomic<bool> Shutdown{false}, Exit{false}; static inline std::atomic<bool> Shutdown{false}, Exit{false};
std::string FullVersion{Version + ".99"};
std::unique_ptr<IPC> IPCToGame{}; std::unique_ptr<IPC> IPCToGame{};
std::unique_ptr<IPC> IPCFromGame{}; std::unique_ptr<IPC> IPCFromGame{};
}; };

View File

@ -237,14 +237,14 @@ void Launcher::QueryRegistry() {
void Launcher::AdminRelaunch() { void Launcher::AdminRelaunch() {
system("cls"); system("cls");
ShellExecuteA(nullptr, "runas", CurrentPath.string().c_str(), nullptr, ShellExecuteA(nullptr, "runas", fs::current_path().string().c_str(), nullptr,
nullptr, SW_SHOWNORMAL); nullptr, SW_SHOWNORMAL);
ShowWindow(GetConsoleWindow(), 0); ShowWindow(GetConsoleWindow(), 0);
throw ShutdownException("Relaunching"); throw ShutdownException("Relaunching");
} }
void Launcher::Relaunch() { void Launcher::Relaunch() {
ShellExecuteA(nullptr, "open", CurrentPath.string().c_str(), nullptr, ShellExecuteA(nullptr, "open", fs::current_path().string().c_str(), nullptr,
nullptr, SW_SHOWNORMAL); nullptr, SW_SHOWNORMAL);
ShowWindow(GetConsoleWindow(), 0); ShowWindow(GetConsoleWindow(), 0);
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));

View File

@ -14,7 +14,7 @@
bool HTTP::isDownload = false; bool HTTP::isDownload = false;
std::atomic<httplib::Client*> CliRef = nullptr; std::atomic<httplib::Client*> CliRef = nullptr;
std::string HTTP::Get(const std::string& IP) { std::string HTTP::Get(const std::string& IP, DownloadProgress DP) {
static std::mutex Lock; static std::mutex Lock;
std::scoped_lock Guard(Lock); std::scoped_lock Guard(Lock);
@ -24,7 +24,7 @@ std::string HTTP::Get(const std::string& IP) {
CliRef.store(&cli); CliRef.store(&cli);
cli.set_connection_timeout(std::chrono::seconds(5)); cli.set_connection_timeout(std::chrono::seconds(5));
cli.set_follow_location(true); 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; std::string Ret;
if (res.error() == httplib::Error::Success) { if (res.error() == httplib::Error::Success) {
@ -105,12 +105,12 @@ bool HTTP::ProgressBar(size_t c, size_t t) {
return true; 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; static std::mutex Lock;
std::scoped_lock Guard(Lock); std::scoped_lock Guard(Lock);
isDownload = true; isDownload = true;
std::string Ret = Get(IP); std::string Ret = Get(IP, DP);
isDownload = false; isDownload = false;
if (Ret.empty()) return false; if (Ret.empty()) return false;

View File

@ -2,6 +2,7 @@
/// Created by Anonymous275 on 12/27/21 /// Created by Anonymous275 on 12/27/21
/// Copyright (c) 2021-present Anonymous275 read the LICENSE file for more info. /// Copyright (c) 2021-present Anonymous275 read the LICENSE file for more info.
/// ///
// clang-format off
#include <wx/wxprec.h> #include <wx/wxprec.h>
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include <wx/dc.h> #include <wx/dc.h>
@ -24,6 +25,7 @@
#include "HttpAPI.h" #include "HttpAPI.h"
#include <thread> #include <thread>
#endif #endif
// clang-format on
/*/////////// TestFrame class /////////// /*/////////// TestFrame class ///////////
class MyTestFrame : public wxFrame { class MyTestFrame : public wxFrame {
@ -39,7 +41,7 @@ class MyTestFrame : public wxFrame {
class MyApp : public wxApp { class MyApp : public wxApp {
public: public:
bool OnInit() override; bool OnInit() override;
//static inline MyTestFrame* TestFrame; // static inline MyTestFrame* TestFrame;
}; };
/////////// AccountFrame class /////////// /////////// AccountFrame class ///////////
@ -48,7 +50,7 @@ class MyAccountFrame : public wxFrame {
MyAccountFrame(); MyAccountFrame();
private: private:
static inline wxTextCtrl* ctrlUsername, *ctrlPassword; static inline wxTextCtrl *ctrlUsername, *ctrlPassword;
bool DarkMode = wxSystemSettings::GetAppearance().IsDark(); bool DarkMode = wxSystemSettings::GetAppearance().IsDark();
void OnClickRegister(wxCommandEvent& event); void OnClickRegister(wxCommandEvent& event);
void OnClickLogout(wxCommandEvent& event); void OnClickLogout(wxCommandEvent& event);
@ -63,12 +65,15 @@ class MyMainFrame : public wxFrame {
static void GameVersionLabel(); static void GameVersionLabel();
static inline MyAccountFrame* AccountFrame; static inline MyAccountFrame* AccountFrame;
static inline MyMainFrame* MainFrameInstance; static inline MyMainFrame* MainFrameInstance;
static inline std::thread UpdateThread;
wxGauge* UpdateBar;
wxStaticText* txtUpdate;
wxBitmapButton* BitAccount; wxBitmapButton* BitAccount;
void OnClickAccount(wxCommandEvent& event); void OnClickAccount(wxCommandEvent& event);
private: private:
wxStaticText* txtStatusResult; wxStaticText* txtStatusResult;
static inline wxStaticText* txtGameVersion, *txtPlayers, *txtModVersion, *txtServers; static inline wxStaticText *txtGameVersion, *txtPlayers, *txtModVersion, *txtServers;
wxButton* btnLaunch; wxButton* btnLaunch;
bool DarkMode = wxSystemSettings::GetAppearance().IsDark(); bool DarkMode = wxSystemSettings::GetAppearance().IsDark();
@ -89,55 +94,56 @@ class MySettingsFrame : public wxFrame {
void UpdateProfileDirectory(const std::string& path); void UpdateProfileDirectory(const std::string& path);
void UpdateCacheDirectory(const std::string& path); void UpdateCacheDirectory(const std::string& path);
private: private:
wxCheckBox* checkConsole; wxCheckBox* checkConsole;
wxDirPickerCtrl* ctrlGameDirectory, *ctrlProfileDirectory, *ctrlCacheDirectory; wxDirPickerCtrl *ctrlGameDirectory, *ctrlProfileDirectory, *ctrlCacheDirectory;
wxChoice* choiceController; wxChoice* choiceController;
bool DarkMode = wxSystemSettings::GetAppearance().IsDark(); bool DarkMode = wxSystemSettings::GetAppearance().IsDark();
void OnClickConsole(wxCommandEvent& event); void OnClickConsole(wxCommandEvent& event);
void OnChangedGameDir (wxFileDirPickerEvent& event); void OnChangedGameDir(wxFileDirPickerEvent& event);
void OnChangedProfileDir (wxFileDirPickerEvent& event); void OnChangedProfileDir(wxFileDirPickerEvent& event);
void OnChangedCacheDir (wxFileDirPickerEvent& event); void OnChangedCacheDir(wxFileDirPickerEvent& event);
void OnChangedBuild (wxCommandEvent& event); void OnChangedBuild(wxCommandEvent& event);
void OnAutoDetectGame(wxCommandEvent& event); void OnAutoDetectGame(wxCommandEvent& event);
void OnAutoDetectProfile(wxCommandEvent& event); void OnAutoDetectProfile(wxCommandEvent& event);
void OnResetCache(wxCommandEvent& event); void OnResetCache(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };
// clang-format off
/////////// Event Tables /////////// /////////// Event Tables ///////////
//MainFrame (ID range 1 to 99): // MainFrame (ID range 1 to 99):
wxBEGIN_EVENT_TABLE(MyMainFrame, wxFrame) wxBEGIN_EVENT_TABLE(MyMainFrame, wxFrame)
EVT_BUTTON(1, MyMainFrame::OnClickAccount) EVT_BUTTON(1, MyMainFrame::OnClickAccount)
EVT_BUTTON(2, MyMainFrame::OnClickSettings) EVT_BUTTON(2, MyMainFrame::OnClickSettings)
EVT_BUTTON(3, MyMainFrame::OnClickLaunch) EVT_BUTTON(3, MyMainFrame::OnClickLaunch)
EVT_BUTTON(4, MyMainFrame::OnClickLogo) EVT_BUTTON(4, MyMainFrame::OnClickLogo)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
//AccountFrame (ID range 100 to 199): // AccountFrame (ID range 100 to 199):
wxBEGIN_EVENT_TABLE(MyAccountFrame, wxFrame) wxBEGIN_EVENT_TABLE(MyAccountFrame, wxFrame)
EVT_BUTTON(100, MyAccountFrame::OnClickLogout) EVT_BUTTON(100, MyAccountFrame::OnClickLogout)
EVT_BUTTON(101, MyAccountFrame::OnClickRegister) EVT_BUTTON(101, MyAccountFrame::OnClickRegister)
EVT_BUTTON(102, MyAccountFrame::OnClickLogin) EVT_BUTTON(102, MyAccountFrame::OnClickLogin)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
//SettingsFrame (ID range 200 to 299): // SettingsFrame (ID range 200 to 299):
wxBEGIN_EVENT_TABLE(MySettingsFrame, wxFrame) wxBEGIN_EVENT_TABLE(MySettingsFrame, wxFrame)
EVT_DIRPICKER_CHANGED(200, MySettingsFrame::OnChangedGameDir) EVT_DIRPICKER_CHANGED(200, MySettingsFrame::OnChangedGameDir)
EVT_DIRPICKER_CHANGED(201, MySettingsFrame::OnChangedProfileDir) EVT_DIRPICKER_CHANGED(201, MySettingsFrame::OnChangedProfileDir)
EVT_DIRPICKER_CHANGED(202, MySettingsFrame::OnChangedCacheDir) EVT_DIRPICKER_CHANGED(202, MySettingsFrame::OnChangedCacheDir)
EVT_BUTTON(203, MySettingsFrame::OnAutoDetectGame) EVT_BUTTON(203, MySettingsFrame::OnAutoDetectGame)
EVT_BUTTON(204, MySettingsFrame::OnAutoDetectProfile) EVT_BUTTON(204, MySettingsFrame::OnAutoDetectProfile)
EVT_BUTTON(205, MySettingsFrame::OnResetCache) EVT_BUTTON(205, MySettingsFrame::OnResetCache)
EVT_CHOICE(206, MySettingsFrame::OnChangedBuild) EVT_CHOICE(206, MySettingsFrame::OnChangedBuild)
EVT_CHECKBOX(207, MySettingsFrame::OnClickConsole) EVT_CHECKBOX(207, MySettingsFrame::OnClickConsole)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE();
// clang-format on
/////////// Get Stats Function /////////// /////////// Get Stats Function ///////////
void MyMainFrame::GetStats () { void MyMainFrame::GetStats() {
std::string results = HTTP::Get("https://backend.beammp.com/stats_raw"); std::string results = HTTP::Get("https://backend.beammp.com/stats_raw");
nlohmann::json jf = nlohmann::json::parse(results, nullptr, false); nlohmann::json jf = nlohmann::json::parse(results, nullptr, false);
@ -148,12 +154,12 @@ wxBEGIN_EVENT_TABLE(MyMainFrame, wxFrame)
if (jf["Players"].get<int>() < 559) if (jf["Players"].get<int>() < 559)
txtPlayers->SetForegroundColour("green"); txtPlayers->SetForegroundColour("green");
else else
txtPlayers->SetForegroundColour(wxColour(255,173,0)); txtPlayers->SetForegroundColour(wxColour(255, 173, 0));
if (jf["PublicServers"].get<int>() > 679) if (jf["PublicServers"].get<int>() > 679)
txtServers->SetForegroundColour("green"); txtServers->SetForegroundColour("green");
else else
txtServers->SetForegroundColour(wxColour(255,173,0)); txtServers->SetForegroundColour(wxColour(255, 173, 0));
} else { } else {
txtPlayers->SetLabel("NA"); txtPlayers->SetLabel("NA");
@ -191,6 +197,81 @@ void MySettingsFrame::UpdateCacheDirectory(const std::string& path) {
UIData::CachePath = path; UIData::CachePath = path;
} }
/////////// UpdateConfig Function ///////////
template<typename ValueType>
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 /////////// /////////// Load Config Function ///////////
void LoadConfig() { void LoadConfig() {
if (fs::exists("Launcher.toml")) { if (fs::exists("Launcher.toml")) {
@ -227,11 +308,14 @@ void LoadConfig() {
if (tml.is_open()) { if (tml.is_open()) {
tml << "UI = true\n" tml << "UI = true\n"
"Build = 'Default'\n" "Build = 'Default'\n"
"GamePath = 'C:\\Program Files'\n" "GamePath = ''\n"
"ProfilePath = 'C:\\Program Files'\n" "ProfilePath = ''\n"
"CachePath = 'Resources'\n" "CachePath = ''\n"
"Console = false"; "Console = false";
tml.close(); tml.close();
AutoDetectGame();
AutoDetectProfile();
ResetCache();
LoadConfig(); LoadConfig();
} else wxMessageBox("Failed to create config file", "Error"); } else wxMessageBox("Failed to create config file", "Error");
} }
@ -290,7 +374,7 @@ void CheckKey() {
Json d = Json::parse(Buffer, nullptr, false); Json d = Json::parse(Buffer, nullptr, false);
if (Buffer == "-1" || Buffer.at(0) != '{' || d.is_discarded()) { 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; return;
} }
if (d["success"].get<bool>()) { if (d["success"].get<bool>()) {
@ -298,18 +382,17 @@ void CheckKey() {
UpdateKey(d["private_key"].get<std::string>()); UpdateKey(d["private_key"].get<std::string>());
UIData::PublicKey = d["public_key"].get<std::string>(); UIData::PublicKey = d["public_key"].get<std::string>();
UIData::UserRole = d["role"].get<std::string>(); UIData::UserRole = d["role"].get<std::string>();
UIData::Username = d["username"].get<std::string>(); UIData::Username = d["username"].get<std::string>();
} else UpdateKey(""); } else UpdateKey("");
} else UpdateKey(""); } else UpdateKey("");
} else UpdateKey(""); } else UpdateKey("");
} }
void WindowsConsole (bool isChecked); void WindowsConsole(bool isChecked);
void UpdateCheck();
/////////// OnInit Function /////////// /////////// OnInit Function ///////////
bool MyApp::OnInit() { bool MyApp::OnInit() {
if (!fs::exists("icons")) {
if(!fs::exists("icons")) {
fs::create_directory("icons"); fs::create_directory("icons");
} }
@ -319,9 +402,11 @@ bool MyApp::OnInit() {
WindowsConsole(UIData::Console); WindowsConsole(UIData::Console);
auto* MainFrame = new MyMainFrame(); auto* MainFrame = new MyMainFrame();
MyMainFrame::MainFrameInstance = MainFrame; 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: // Set MainFrame properties:
MainFrame->SetSize(1000, 650); MainFrame->SetSize(1000, 650);
@ -330,15 +415,14 @@ bool MyApp::OnInit() {
if (wxSystemSettings::GetAppearance().IsDark()) { if (wxSystemSettings::GetAppearance().IsDark()) {
MainFrame->SetBackgroundColour(wxColour(40, 40, 40)); MainFrame->SetBackgroundColour(wxColour(40, 40, 40));
MainFrame->SetForegroundColour(wxColour(255, 255, 255)); MainFrame->SetForegroundColour(wxColour(255, 255, 255));
} } else {
else {
MainFrame->SetBackgroundColour(wxColour("white")); MainFrame->SetBackgroundColour(wxColour("white"));
MainFrame->SetForegroundColour(wxColour("white")); MainFrame->SetForegroundColour(wxColour("white"));
} }
wxFileSystem::AddHandler(new wxInternetFSHandler); wxFileSystem::AddHandler(new wxInternetFSHandler);
MainFrame->Show(true); MainFrame->Show(true);
//Test Frame Properties: // Test Frame Properties:
/*TestFrame = new MyTestFrame(); /*TestFrame = new MyTestFrame();
TestFrame->SetIcon(wxIcon("icons/BeamMP_black.png",wxBITMAP_TYPE_PNG)); TestFrame->SetIcon(wxIcon("icons/BeamMP_black.png",wxBITMAP_TYPE_PNG));
@ -359,7 +443,7 @@ bool MyApp::OnInit() {
} }
/////////// Windows Console Function /////////// /////////// Windows Console Function ///////////
void WindowsConsole (bool isChecked) { void WindowsConsole(bool isChecked) {
if (isChecked) { if (isChecked) {
AllocConsole(); AllocConsole();
FILE* pNewStdout = nullptr; FILE* pNewStdout = nullptr;
@ -369,8 +453,7 @@ void WindowsConsole (bool isChecked) {
::freopen_s(&pNewStdout, "CONOUT$", "w", stdout); ::freopen_s(&pNewStdout, "CONOUT$", "w", stdout);
::freopen_s(&pNewStderr, "CONOUT$", "w", stderr); ::freopen_s(&pNewStderr, "CONOUT$", "w", stderr);
::freopen_s(&pNewStdin, "CONIN$", "r", stdin); ::freopen_s(&pNewStdin, "CONIN$", "r", stdin);
} } else {
else {
FreeConsole(); FreeConsole();
::fclose(stdout); ::fclose(stdout);
::fclose(stderr); ::fclose(stderr);
@ -389,36 +472,92 @@ void WindowsConsole (bool isChecked) {
} }
/////////// Read json Function /////////// /////////// Read json Function ///////////
std::string jsonRead () { std::string jsonRead() {
fs::path path = fs::path (UIData::GamePath).append("integrity.json"); fs::path path = fs::path(UIData::GamePath).append("integrity.json");
if (fs::exists(path)) { if (fs::exists(path)) {
std::ifstream ifs(path); std::ifstream ifs(path);
nlohmann::json jf = nlohmann::json::parse(ifs, nullptr, false); nlohmann::json jf = nlohmann::json::parse(ifs, nullptr, false);
if (!jf.is_discarded() && !jf.empty()) return jf["version"]; 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 ""; return "";
} }
/////////// Picture Type Function /////////// /////////// Picture Type Function ///////////
// JPG 0 / PNG 1 // 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++) { for (int i = 0; i < 15; i++) {
if(picture[i] == 'J') if (picture[i] == 'J')
return ".jpg"; return ".jpg";
else if (picture[i] == 'P' && picture[i+1] == 'N') else if (picture[i] == 'P' && picture[i + 1] == 'N')
return ".png"; return ".png";
} }
return ""; return "";
} }
/////////// Get Picture Name Function /////////// /////////// Get Picture Name Function ///////////
std::string GetPictureName () { std::string GetPictureName() {
for (const auto& entry : fs::recursive_directory_iterator("icons")) { for (const auto& entry : fs::recursive_directory_iterator("icons")) {
if (entry.path().filename().string().find(UIData::Username) != std::string::npos) { if (entry.path().filename().string().find(UIData::Username) != std::string::npos) {
return entry.path().string(); 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) <<EP + " AND " + Back;
if (fs::exists(Back)) remove(Back.c_str());
std::string RemoteVer;
for (char& c : HTTP) {
if (std::isdigit(c) || c == '.') {
RemoteVer += c;
}
}
if (VersionParser(RemoteVer) > 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 /////////// /////////// TestFrame Function ///////////
@ -433,57 +572,57 @@ file->SetForegroundColour("white");
/////////// Main Frame Content /////////// /////////// Main Frame Content ///////////
MyMainFrame::MyMainFrame() : 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) { 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: // News:
wxWebView::New() ->Create(panel, wxID_ANY, "https://beammp.com", wxPoint(10, 70), wxSize(950, 400)); 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)); auto* txtNews = new wxStaticText(panel, wxID_ANY, wxT("News"), wxPoint(10, 40));
MyMainFrame::SetFocus(); MyMainFrame::SetFocus();
auto* HorizontalLine1 = new wxStaticLine(panel, wxID_ANY, wxPoint(10, 60), wxSize(950, 1)); 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)); auto* HorizontalLine2 = new wxStaticLine(panel, wxID_ANY, wxPoint(10, 480), wxSize(950, 1));
//Hyperlinks: // Hyperlinks:
auto* HyperForum = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Forum"), wxT("https://forum.beammp.com"), wxPoint(10, 10)); 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* 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* 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* 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* 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)); auto* HyperPatreon = new wxHyperlinkCtrl(panel, wxID_ANY, wxT("Patreon"), wxT("https://www.patreon.com/BeamMP"), wxPoint(240, 10));
//Update: // Update:
auto* txtUpdate = new wxStaticText(panel, wxID_ANY, wxT("Updating BeamMP "), wxPoint(10, 490)); 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); UpdateBar->SetValue(0);
while (UpdateBar->GetValue() <76) { while (UpdateBar->GetValue() < 101) {
txtUpdate->SetLabel(wxT("Updating BeamMP: " + std::to_string(UpdateBar->GetValue()) + "%")); txtUpdate->SetLabel(wxT("Updating BeamMP: " + std::to_string(UpdateBar->GetValue()) + "%"));
UpdateBar->SetValue(UpdateBar->GetValue() + 1); UpdateBar->SetValue(UpdateBar->GetValue() + 1);
} }
//Information: // Information:
auto* txtGameVersionTitle = new wxStaticText(panel, wxID_ANY, wxT("Game Version: "), wxPoint(160, 490)); 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)); 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* 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)); 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)); 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)); auto* txtStatus = new wxStaticText(panel, wxID_ANY, wxT("Status: "), wxPoint(880, 520));
txtStatusResult = new wxStaticText(panel, wxID_ANY, wxT("Online"), wxPoint(920, 520)); txtStatusResult = new wxStaticText(panel, wxID_ANY, wxT("Online"), wxPoint(920, 520));
@ -492,30 +631,30 @@ MyMainFrame::MyMainFrame() :
wxInitAllImageHandlers(); wxInitAllImageHandlers();
//Account: // 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)); 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(); std::string PictureString = GetPictureName();
if (UIData::LoginAuth && fs::exists( PictureString)) if (UIData::LoginAuth && fs::exists(PictureString))
BitAccount->SetBitmap(wxBitmapBundle(wxImage( PictureString).Scale(45, 45, wxIMAGE_QUALITY_HIGH))); BitAccount->SetBitmap(wxBitmapBundle(wxImage(PictureString).Scale(45, 45, wxIMAGE_QUALITY_HIGH)));
else 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: // Buttons:
auto btnSettings = new wxButton(panel, 2, wxT("Settings"), wxPoint(730,570), wxSize(110, 25)); 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)); btnLaunch = new wxButton(panel, 3, wxT("Launch"), wxPoint(850, 570), wxSize(110, 25));
GetStats(); GetStats();
//UI Colors: // UI Colors:
GameVersionLabel(); GameVersionLabel();
if (DarkMode) { if (DarkMode) {
//Text Separators: // Text Separators:
txtSeparator1->SetForegroundColour("white"); txtSeparator1->SetForegroundColour("white");
txtSeparator2->SetForegroundColour("white"); txtSeparator2->SetForegroundColour("white");
txtSeparator3->SetForegroundColour("white"); txtSeparator3->SetForegroundColour("white");
txtSeparator4->SetForegroundColour("white"); txtSeparator4->SetForegroundColour("white");
//Texts: // Texts:
txtNews->SetForegroundColour("white"); txtNews->SetForegroundColour("white");
txtUpdate->SetForegroundColour("white"); txtUpdate->SetForegroundColour("white");
txtGameVersionTitle->SetForegroundColour("white"); txtGameVersionTitle->SetForegroundColour("white");
@ -526,64 +665,63 @@ MyMainFrame::MyMainFrame() :
txtPatreon->SetForegroundColour("white"); txtPatreon->SetForegroundColour("white");
txtStatus->SetForegroundColour("white"); txtStatus->SetForegroundColour("white");
//Line Separators: // Line Separators:
HorizontalLine1->SetForegroundColour("white"); HorizontalLine1->SetForegroundColour("white");
HorizontalLine2->SetForegroundColour("white"); HorizontalLine2->SetForegroundColour("white");
HorizontalLine3->SetForegroundColour("white"); HorizontalLine3->SetForegroundColour("white");
//Logo: // 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); 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)); logo->SetBackgroundColour(wxColour(40, 40, 40));
} } else {
else { // Logo:
//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);
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"); logo->SetBackgroundColour("white");
} }
txtStatusResult->SetForegroundColour("green"); txtStatusResult->SetForegroundColour("green");
} }
/////////// Account Frame Content /////////// /////////// 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) { wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX) {
MyAccountFrame::SetFocus(); MyAccountFrame::SetFocus();
auto *handler = new wxPNGHandler; auto* handler = new wxPNGHandler;
wxImage::AddHandler(handler); wxImage::AddHandler(handler);
wxStaticBitmap *image; 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)); 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)); auto* panel = new wxPanel(this, wxID_ANY, wxPoint(), wxSize(500, 650));
std::string PictureString = GetPictureName(); std::string PictureString = GetPictureName();
if (UIData::LoginAuth) { if (UIData::LoginAuth) {
if (fs::exists( PictureString)) if (fs::exists(PictureString))
image->SetBitmap(wxBitmapBundle(wxImage( PictureString).Scale(120, 120, wxIMAGE_QUALITY_HIGH))); image->SetBitmap(wxBitmapBundle(wxImage(PictureString).Scale(120, 120, wxIMAGE_QUALITY_HIGH)));
else 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* 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 btnLogout = new wxButton(panel, 100, wxT("Logout"), wxPoint(185, 550), wxSize(110, 25));
//UI Colors: // UI Colors:
if (DarkMode) { if (DarkMode) {
//Text: // Text:
txtName->SetForegroundColour("white"); txtName->SetForegroundColour("white");
} }
} } else {
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* txtLogin = new wxStaticText(panel, wxID_ANY, wxT("Login with your BeamMP account."), wxPoint(150, 200)); 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)); 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); ctrlPassword = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxPoint(131, 300), wxSize(220, 25), wxTE_PASSWORD);
ctrlUsername->SetHint("Username / Email"); ctrlUsername->SetHint("Username / Email");
ctrlPassword->SetHint("Password"); ctrlPassword->SetHint("Password");
auto btnRegister = new wxButton(panel, 101, wxT("Register"), wxPoint(250,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)); auto btnLogin = new wxButton(panel, 102, wxT("Login"), wxPoint(120, 375), wxSize(110, 25));
//UI Colors: // UI Colors:
if (DarkMode) { if (DarkMode) {
//Text: // Text:
txtLogin->SetForegroundColour("white"); txtLogin->SetForegroundColour("white");
} }
} }
@ -591,25 +729,25 @@ MyAccountFrame::MyAccountFrame() : wxFrame(nullptr, wxID_ANY, "Account Manager",
/////////// Settings Frame Content /////////// /////////// Settings Frame Content ///////////
MySettingsFrame::MySettingsFrame() : MySettingsFrame::MySettingsFrame() :
wxFrame(nullptr, wxID_ANY, "Settings", wxDefaultPosition,wxDefaultSize, wxFrame(nullptr, wxID_ANY, "Settings", wxDefaultPosition, wxDefaultSize,
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX) { 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)); 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"); ctrlGameDirectory->SetLabel("GamePath");
MySettingsFrame::SetFocus(); 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)); 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"); 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)); 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"); 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)); auto* txtBuild = new wxStaticText(panel, wxID_ANY, wxT("Build: "), wxPoint(30, 400));
wxArrayString BuildChoices; wxArrayString BuildChoices;
@ -617,42 +755,27 @@ MySettingsFrame::MySettingsFrame() :
BuildChoices.Add("Release"); BuildChoices.Add("Release");
BuildChoices.Add("EA"); BuildChoices.Add("EA");
BuildChoices.Add("Dev"); 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); 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) { if (DarkMode) {
//Text: // Text:
txtGameDirectory->SetForegroundColour("white"); txtGameDirectory->SetForegroundColour("white");
txtProfileDirectory->SetForegroundColour("white"); txtProfileDirectory->SetForegroundColour("white");
txtCacheDirectory->SetForegroundColour("white"); txtCacheDirectory->SetForegroundColour("white");
txtBuild->SetForegroundColour("white"); txtBuild->SetForegroundColour("white");
checkConsole->SetForegroundColour("white"); checkConsole->SetForegroundColour("white");
//Style: // Style:
ctrlCacheDirectory->SetWindowStyle(wxBORDER_NONE); ctrlCacheDirectory->SetWindowStyle(wxBORDER_NONE);
ctrlProfileDirectory->SetWindowStyle(wxBORDER_NONE); ctrlProfileDirectory->SetWindowStyle(wxBORDER_NONE);
ctrlGameDirectory->SetWindowStyle(wxBORDER_NONE); ctrlGameDirectory->SetWindowStyle(wxBORDER_NONE);
} }
} }
/////////// UpdateConfig Function ///////////
template <typename ValueType>
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 /////////// /////////// Game Version Label Function ///////////
void MyMainFrame::GameVersionLabel() { void MyMainFrame::GameVersionLabel() {
std::string read = jsonRead(); std::string read = jsonRead();
@ -660,7 +783,7 @@ void MyMainFrame::GameVersionLabel() {
txtGameVersion->SetLabel(read); txtGameVersion->SetLabel(read);
VersionParser CurrentVersion(read); VersionParser CurrentVersion(read);
if (CurrentVersion > Launcher::SupportedVersion) if (CurrentVersion > Launcher::SupportedVersion)
txtGameVersion->SetForegroundColour(wxColour(255,173,0)); txtGameVersion->SetForegroundColour(wxColour(255, 173, 0));
else if (CurrentVersion < Launcher::SupportedVersion) else if (CurrentVersion < Launcher::SupportedVersion)
txtGameVersion->SetForegroundColour("red"); txtGameVersion->SetForegroundColour("red");
else txtGameVersion->SetForegroundColour("green"); else txtGameVersion->SetForegroundColour("green");
@ -675,13 +798,12 @@ void MyMainFrame::OnClickAccount(wxCommandEvent& event WXUNUSED(event)) {
AccountFrame = new MyAccountFrame(); AccountFrame = new MyAccountFrame();
AccountFrame->SetSize(500, 650); AccountFrame->SetSize(500, 650);
AccountFrame->Center(); 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()) { if (wxSystemSettings::GetAppearance().IsDark()) {
AccountFrame->SetBackgroundColour(wxColour(40, 40, 40)); AccountFrame->SetBackgroundColour(wxColour(40, 40, 40));
AccountFrame->SetForegroundColour(wxColour(255, 255, 255)); AccountFrame->SetForegroundColour(wxColour(255, 255, 255));
} } else {
else {
AccountFrame->SetBackgroundColour(wxColour("white")); AccountFrame->SetBackgroundColour(wxColour("white"));
AccountFrame->SetForegroundColour(wxColour("white")); AccountFrame->SetForegroundColour(wxColour("white"));
} }
@ -693,13 +815,12 @@ void MyMainFrame::OnClickSettings(wxCommandEvent& event WXUNUSED(event)) {
auto* SettingsFrame = new MySettingsFrame(); auto* SettingsFrame = new MySettingsFrame();
SettingsFrame->SetSize(500, 650); SettingsFrame->SetSize(500, 650);
SettingsFrame->Center(); 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()) { if (wxSystemSettings::GetAppearance().IsDark()) {
SettingsFrame->SetBackgroundColour(wxColour(40, 40, 40)); SettingsFrame->SetBackgroundColour(wxColour(40, 40, 40));
SettingsFrame->SetForegroundColour(wxColour(255, 255, 255)); SettingsFrame->SetForegroundColour(wxColour(255, 255, 255));
} } else {
else {
SettingsFrame->SetBackgroundColour(wxColour("white")); SettingsFrame->SetBackgroundColour(wxColour("white"));
SettingsFrame->SetForegroundColour(wxColour("white")); SettingsFrame->SetForegroundColour(wxColour("white"));
} }
@ -722,7 +843,7 @@ void MyMainFrame::OnClickLaunch(wxCommandEvent& event WXUNUSED(event)) {
txtStatusResult->SetForegroundColour("purple"); txtStatusResult->SetForegroundColour("purple");
btnLaunch->Disable(); btnLaunch->Disable();
if(FirstTime) { if (FirstTime) {
wxMessageBox("Please launch BeamNG.drive manually in case of Steam issues.", "Alert"); wxMessageBox("Please launch BeamNG.drive manually in case of Steam issues.", "Alert");
FirstTime = false; FirstTime = false;
} }
@ -741,8 +862,8 @@ void MyAccountFrame::OnClickRegister(wxCommandEvent& event WXUNUSED(event)) {
/////////// OnClick Login Event /////////// /////////// OnClick Login Event ///////////
void MyAccountFrame::OnClickLogin(wxCommandEvent& event WXUNUSED(event)) { void MyAccountFrame::OnClickLogin(wxCommandEvent& event WXUNUSED(event)) {
Json json; Json json;
json ["password"] = ctrlPassword->GetValue().utf8_string(); json["password"] = ctrlPassword->GetValue().utf8_string();
json ["username"] = ctrlUsername->GetValue().utf8_string(); json["username"] = ctrlUsername->GetValue().utf8_string();
if (Login(json.dump())) { if (Login(json.dump())) {
std::string picture = HTTP::Get("https://forum.beammp.com/user_avatar/forum.beammp.com/" + UIData::Username + "/240/4411_2.png"); 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 /////////// /////////// OnChanged Game Path Event ///////////
void MySettingsFrame::OnChangedGameDir(wxFileDirPickerEvent& event) { void MySettingsFrame::OnChangedGameDir(wxFileDirPickerEvent& event) {
std::string NewPath = event.GetPath().utf8_string(); std::string NewPath = event.GetPath().utf8_string();
std::string key = reinterpret_cast<wxDirPickerCtrl*> (event.GetEventObject())->GetLabel(); std::string key = reinterpret_cast<wxDirPickerCtrl*>(event.GetEventObject())->GetLabel();
UpdateConfig(key, NewPath); UpdateConfig(key, NewPath);
UpdateGameDirectory(NewPath); UpdateGameDirectory(NewPath);
} }
@ -784,7 +905,7 @@ void MySettingsFrame::OnChangedGameDir(wxFileDirPickerEvent& event) {
/////////// OnChanged Profile Path Event /////////// /////////// OnChanged Profile Path Event ///////////
void MySettingsFrame::OnChangedProfileDir(wxFileDirPickerEvent& event) { void MySettingsFrame::OnChangedProfileDir(wxFileDirPickerEvent& event) {
std::string NewPath = event.GetPath().utf8_string(); std::string NewPath = event.GetPath().utf8_string();
std::string key = reinterpret_cast<wxDirPickerCtrl*> (event.GetEventObject())->GetLabel(); std::string key = reinterpret_cast<wxDirPickerCtrl*>(event.GetEventObject())->GetLabel();
UpdateConfig(key, NewPath); UpdateConfig(key, NewPath);
UpdateProfileDirectory(NewPath); UpdateProfileDirectory(NewPath);
} }
@ -792,85 +913,49 @@ void MySettingsFrame::OnChangedProfileDir(wxFileDirPickerEvent& event) {
/////////// OnChanged Cache Path Event /////////// /////////// OnChanged Cache Path Event ///////////
void MySettingsFrame::OnChangedCacheDir(wxFileDirPickerEvent& event) { void MySettingsFrame::OnChangedCacheDir(wxFileDirPickerEvent& event) {
std::string NewPath = event.GetPath().utf8_string(); std::string NewPath = event.GetPath().utf8_string();
std::string key = reinterpret_cast<wxDirPickerCtrl*> (event.GetEventObject())->GetLabel(); std::string key = reinterpret_cast<wxDirPickerCtrl*>(event.GetEventObject())->GetLabel();
UpdateConfig(key, NewPath); UpdateConfig(key, NewPath);
UpdateCacheDirectory(NewPath); UpdateCacheDirectory(NewPath);
} }
/////////// OnChanged Build Event /////////// /////////// OnChanged Build Event ///////////
void MySettingsFrame::OnChangedBuild(wxCommandEvent& event) { void MySettingsFrame::OnChangedBuild(wxCommandEvent& event) {
std::string key = reinterpret_cast<wxChoice*> (event.GetEventObject())->GetString(event.GetSelection()); std::string key = reinterpret_cast<wxChoice*>(event.GetEventObject())->GetString(event.GetSelection());
UpdateConfig("Build", key); UpdateConfig("Build", key);
UIData::Build = key; UIData::Build = key;
} }
/////////// AutoDetect Game Function /////////// /////////// AutoDetect Game Function ///////////
void MySettingsFrame::OnAutoDetectGame (wxCommandEvent& event) { void MySettingsFrame::OnAutoDetectGame(wxCommandEvent& event) {
HKEY BeamNG; UpdateGameDirectory(AutoDetectGame());
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");
} }
/////////// AutoDetect Profile Function /////////// /////////// AutoDetect Profile Function ///////////
void MySettingsFrame::OnAutoDetectProfile(wxCommandEvent& event){ void MySettingsFrame::OnAutoDetectProfile(wxCommandEvent& event) {
HKEY BeamNG; UpdateProfileDirectory(AutoDetectProfile());
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);
} }
/////////// Reset Cache Function /////////// /////////// Reset Cache Function ///////////
void MySettingsFrame::OnResetCache(wxCommandEvent& event) { void MySettingsFrame::OnResetCache(wxCommandEvent& event) {
std::string CachePath = fs::current_path().append("Resources").string(); UpdateCacheDirectory(ResetCache());
UpdateConfig("CachePath", CachePath);
ctrlCacheDirectory->SetPath(CachePath);
} }
/////////// MAIN FUNCTION /////////// /////////// MAIN FUNCTION ///////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
wxDisableAsserts(); wxDisableAsserts();
wxLog::SetLogLevel(wxLOG_Info); wxLog::SetLogLevel(wxLOG_Info);
new MyApp(); int result = 0;
int result = wxEntry(hInstance, hPrevInstance, lpCmdLine, nShowCmd); try {
if (Launcher::EntryThread.joinable()) new MyApp();
Launcher::EntryThread.join(); 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; return result;
} }