mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-06-19 23:20:57 +00:00
added ShutdownException and registry queries
This commit is contained in:
+17
-1
@@ -10,14 +10,21 @@
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
struct VersionParser {
|
||||||
|
explicit VersionParser(const std::string& from_string);
|
||||||
|
std::strong_ordering operator<=>(VersionParser const& rhs) const noexcept;
|
||||||
|
bool operator==(VersionParser const& rhs) const noexcept;
|
||||||
|
std::vector<size_t> data;
|
||||||
|
};
|
||||||
|
|
||||||
class Launcher {
|
class Launcher {
|
||||||
public: //constructors
|
public: //constructors
|
||||||
Launcher(int argc, char* argv[]);
|
Launcher(int argc, char* argv[]);
|
||||||
~Launcher();
|
~Launcher();
|
||||||
public: //available functions
|
public: //available functions
|
||||||
std::string Login(const std::string& fields);
|
std::string Login(const std::string& fields);
|
||||||
bool Terminate() const;
|
|
||||||
void RunDiscordRPC();
|
void RunDiscordRPC();
|
||||||
|
void QueryRegistry();
|
||||||
void LoadConfig();
|
void LoadConfig();
|
||||||
void LaunchGame();
|
void LaunchGame();
|
||||||
void CheckKey();
|
void CheckKey();
|
||||||
@@ -36,11 +43,20 @@ private: //variables
|
|||||||
bool Shutdown = false;
|
bool Shutdown = false;
|
||||||
bool LoginAuth = false;
|
bool LoginAuth = false;
|
||||||
fs::path CurrentPath{};
|
fs::path CurrentPath{};
|
||||||
|
std::string BeamRoot{};
|
||||||
std::string UserRole{};
|
std::string UserRole{};
|
||||||
std::string PublicKey{};
|
std::string PublicKey{};
|
||||||
std::thread DiscordRPC{};
|
std::thread DiscordRPC{};
|
||||||
|
std::string BeamVersion{};
|
||||||
|
std::string BeamUserPath{};
|
||||||
std::string DiscordMessage{};
|
std::string DiscordMessage{};
|
||||||
std::string Version{"3.0"};
|
std::string Version{"3.0"};
|
||||||
std::string TargetBuild{"default"};
|
std::string TargetBuild{"default"};
|
||||||
std::string FullVersion{Version + ".0"};
|
std::string FullVersion{Version + ".0"};
|
||||||
|
VersionParser SupportedVersion{"0.24.1.1"};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShutdownException : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
explicit ShutdownException(const std::string& message): runtime_error(message){};
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-1
@@ -33,6 +33,7 @@ Build = "Default"
|
|||||||
cfg.close();
|
cfg.close();
|
||||||
}else{
|
}else{
|
||||||
LOG(FATAL) << "Failed to write config on disk!";
|
LOG(FATAL) << "Failed to write config on disk!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-20
@@ -9,7 +9,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
|
|
||||||
Launcher::Launcher(int argc, char* argv[]) : CurrentPath(std::filesystem::path(argv[0])), DiscordMessage("Just launched") {
|
Launcher::Launcher(int argc, char* argv[]) : CurrentPath(std::filesystem::path(argv[0])), DiscordMessage("Just launched") {
|
||||||
Log::Init();
|
Log::Init();
|
||||||
WindowsInit();
|
WindowsInit();
|
||||||
@@ -19,17 +18,25 @@ Launcher::Launcher(int argc, char* argv[]) : CurrentPath(std::filesystem::path(a
|
|||||||
|
|
||||||
Launcher::~Launcher() {
|
Launcher::~Launcher() {
|
||||||
Shutdown = true;
|
Shutdown = true;
|
||||||
LOG(INFO) << "Shutting down";
|
|
||||||
if(DiscordRPC.joinable()) {
|
if(DiscordRPC.joinable()) {
|
||||||
DiscordRPC.join();
|
DiscordRPC.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Launcher::Terminate() const {
|
|
||||||
return Shutdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::LaunchGame() {
|
void Launcher::LaunchGame() {
|
||||||
|
VersionParser GameVersion(BeamVersion);
|
||||||
|
if(GameVersion.data[0] > SupportedVersion.data[0]) {
|
||||||
|
LOG(FATAL) << "BeamNG V" << BeamVersion << " not yet supported, please wait until we update BeamMP!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
|
} else if(GameVersion.data[0] < SupportedVersion.data[0]) {
|
||||||
|
LOG(FATAL) << "BeamNG V" << BeamVersion << " not supported, please update and launch the new update!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
|
} else if(GameVersion > SupportedVersion) {
|
||||||
|
LOG(WARNING) << "BeamNG V" << BeamVersion << " is slightly newer than recommended, this might cause issues!";
|
||||||
|
} else if(GameVersion < SupportedVersion) {
|
||||||
|
LOG(WARNING) << "BeamNG V" << BeamVersion << " is slightly older than recommended, this might cause issues!";
|
||||||
|
}
|
||||||
|
|
||||||
ShellExecuteA(nullptr, nullptr, "steam://rungameid/284160", nullptr, nullptr, SW_SHOWNORMAL);
|
ShellExecuteA(nullptr, nullptr, "steam://rungameid/284160", nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
//ShowWindow(GetConsoleWindow(), HIDE_WINDOW);
|
//ShowWindow(GetConsoleWindow(), HIDE_WINDOW);
|
||||||
}
|
}
|
||||||
@@ -39,6 +46,45 @@ void Launcher::WindowsInit() {
|
|||||||
SetConsoleTitleA(("BeamMP Launcher v" + FullVersion).c_str());
|
SetConsoleTitleA(("BeamMP Launcher v" + FullVersion).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string QueryValue(HKEY& BeamNG, const char* Name) {
|
||||||
|
DWORD keySize;
|
||||||
|
BYTE buffer[1024];
|
||||||
|
ZeroMemory(buffer, 1024);
|
||||||
|
if(RegQueryValueExA(BeamNG, Name, nullptr, nullptr, buffer, &keySize) == ERROR_SUCCESS) {
|
||||||
|
return {(char*)buffer, keySize};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::QueryRegistry() {
|
||||||
|
HKEY BeamNG;
|
||||||
|
LONG RegRes = RegOpenKeyExA(HKEY_CURRENT_USER, R"(Software\BeamNG\BeamNG.drive)", 0, KEY_READ, &BeamNG);
|
||||||
|
if(RegRes == ERROR_SUCCESS) {
|
||||||
|
BeamRoot = QueryValue(BeamNG, "rootpath");
|
||||||
|
BeamVersion = QueryValue(BeamNG, "version");
|
||||||
|
BeamUserPath = QueryValue(BeamNG, "userpath_override");
|
||||||
|
//get shell folders for appdata dir
|
||||||
|
RegCloseKey(BeamNG);
|
||||||
|
if(!BeamRoot.empty() && !BeamVersion.empty())return;
|
||||||
|
}
|
||||||
|
LOG(FATAL) << "Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::AdminRelaunch() {
|
||||||
|
system("cls");
|
||||||
|
ShellExecuteA(nullptr, "runas", CurrentPath.string().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
|
ShowWindow(GetConsoleWindow(),0);
|
||||||
|
throw ShutdownException("Relaunching");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::Relaunch() {
|
||||||
|
ShellExecuteA(nullptr, "open", CurrentPath.string().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
|
ShowWindow(GetConsoleWindow(),0);
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
throw ShutdownException("Relaunching");
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& Launcher::getFullVersion() {
|
const std::string& Launcher::getFullVersion() {
|
||||||
return FullVersion;
|
return FullVersion;
|
||||||
}
|
}
|
||||||
@@ -51,17 +97,3 @@ const std::string& Launcher::getUserRole() {
|
|||||||
return UserRole;
|
return UserRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::AdminRelaunch() {
|
|
||||||
system("cls");
|
|
||||||
ShellExecuteA(nullptr, "runas", CurrentPath.string().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
|
||||||
ShowWindow(GetConsoleWindow(),0);
|
|
||||||
Shutdown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Launcher::Relaunch() {
|
|
||||||
ShellExecuteA(nullptr, "open", CurrentPath.string().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
|
||||||
ShowWindow(GetConsoleWindow(),0);
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
||||||
Shutdown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ void UpdateKey(const char* newKey){
|
|||||||
if(Key.is_open()){
|
if(Key.is_open()){
|
||||||
Key << newKey;
|
Key << newKey;
|
||||||
Key.close();
|
Key.close();
|
||||||
}else LOG(FATAL) << "Cannot write to disk!";
|
} else {
|
||||||
|
LOG(FATAL) << "Cannot write to disk!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
|
}
|
||||||
}else if(fs::exists("key")){
|
}else if(fs::exists("key")){
|
||||||
remove("key");
|
remove("key");
|
||||||
}
|
}
|
||||||
@@ -88,8 +91,9 @@ void Launcher::CheckKey() {
|
|||||||
Json::Document d;
|
Json::Document d;
|
||||||
d.Parse(Buffer.c_str());
|
d.Parse(Buffer.c_str());
|
||||||
if (Buffer == "-1" || Buffer.at(0) != '{' || d.HasParseError()) {
|
if (Buffer == "-1" || Buffer.at(0) != '{' || d.HasParseError()) {
|
||||||
LOG(ERROR) << Buffer;
|
LOG(DEBUG) << Buffer;
|
||||||
LOG(FATAL) << "Invalid answer from authentication servers, please try again later!";
|
LOG(FATAL) << "Invalid answer from authentication servers, please try again later!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
}
|
}
|
||||||
if(d["success"].GetBool()){
|
if(d["success"].GetBool()){
|
||||||
LoginAuth = true;
|
LoginAuth = true;
|
||||||
|
|||||||
+25
-26
@@ -6,32 +6,30 @@
|
|||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
#include <sstream>
|
|
||||||
struct Ver {
|
|
||||||
std::vector<size_t> data;
|
|
||||||
explicit Ver(const std::string& from_string) {
|
|
||||||
std::string token;
|
|
||||||
std::istringstream tokenStream(from_string);
|
|
||||||
while (std::getline(tokenStream, token, '.')) {
|
|
||||||
data.emplace_back(std::stol(token));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::strong_ordering operator<=>(Ver const& rhs) const noexcept {
|
|
||||||
size_t const fields = std::min(data.size(), rhs.data.size());
|
|
||||||
for(size_t i = 0; i != fields; ++i) {
|
|
||||||
if(data[i] == rhs.data[i]) continue;
|
|
||||||
else if(data[i] < rhs.data[i]) return std::strong_ordering::less;
|
|
||||||
else return std::strong_ordering::greater;
|
|
||||||
}
|
|
||||||
if(data.size() == rhs.data.size()) return std::strong_ordering::equal;
|
|
||||||
else if(data.size() > rhs.data.size()) return std::strong_ordering::greater;
|
|
||||||
else return std::strong_ordering::less;
|
|
||||||
}
|
|
||||||
bool operator==(Ver const& rhs) const noexcept {
|
|
||||||
return std::is_eq(*this <=> rhs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
VersionParser::VersionParser(const std::string &from_string) {
|
||||||
|
std::string token;
|
||||||
|
std::istringstream tokenStream(from_string);
|
||||||
|
while (std::getline(tokenStream, token, '.')) {
|
||||||
|
data.emplace_back(std::stol(token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::strong_ordering VersionParser::operator<=>(const VersionParser &rhs) const noexcept {
|
||||||
|
size_t const fields = std::min(data.size(), rhs.data.size());
|
||||||
|
for(size_t i = 0; i != fields; ++i) {
|
||||||
|
if(data[i] == rhs.data[i]) continue;
|
||||||
|
else if(data[i] < rhs.data[i]) return std::strong_ordering::less;
|
||||||
|
else return std::strong_ordering::greater;
|
||||||
|
}
|
||||||
|
if(data.size() == rhs.data.size()) return std::strong_ordering::equal;
|
||||||
|
else if(data.size() > rhs.data.size()) return std::strong_ordering::greater;
|
||||||
|
else return std::strong_ordering::less;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionParser::operator==(const VersionParser &rhs) const noexcept {
|
||||||
|
return std::is_eq(*this <=> rhs);
|
||||||
|
}
|
||||||
|
|
||||||
void Launcher::UpdateCheck() {
|
void Launcher::UpdateCheck() {
|
||||||
std::string link;
|
std::string link;
|
||||||
@@ -42,6 +40,7 @@ void Launcher::UpdateCheck() {
|
|||||||
fallback = true;
|
fallback = true;
|
||||||
if(HTTP.find_first_of("0123456789") == std::string::npos) {
|
if(HTTP.find_first_of("0123456789") == std::string::npos) {
|
||||||
LOG(FATAL) << "Primary Servers Offline! sorry for the inconvenience!";
|
LOG(FATAL) << "Primary Servers Offline! sorry for the inconvenience!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(fallback){
|
if(fallback){
|
||||||
@@ -58,7 +57,7 @@ void Launcher::UpdateCheck() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Ver(RemoteVer) > Ver(FullVersion)){
|
if(VersionParser(RemoteVer) > VersionParser(FullVersion)){
|
||||||
system("cls");
|
system("cls");
|
||||||
LOG(INFO) << "Update found! Downloading...";
|
LOG(INFO) << "Update found! Downloading...";
|
||||||
if(std::rename(EP.c_str(), Back.c_str())){
|
if(std::rename(EP.c_str(), Back.c_str())){
|
||||||
|
|||||||
+12
-2
@@ -4,14 +4,24 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
Launcher launcher(argc, argv);
|
try {
|
||||||
if(!launcher.Terminate()) {
|
Launcher launcher(argc, argv);
|
||||||
launcher.RunDiscordRPC();
|
launcher.RunDiscordRPC();
|
||||||
launcher.LoadConfig();
|
launcher.LoadConfig();
|
||||||
launcher.CheckKey();
|
launcher.CheckKey();
|
||||||
|
launcher.LaunchGame();
|
||||||
|
//launcher.WaitForGame();
|
||||||
|
launcher.QueryRegistry();
|
||||||
//UI call
|
//UI call
|
||||||
|
|
||||||
|
|
||||||
|
} catch (const ShutdownException& e) {
|
||||||
|
LOG(INFO) << "Launcher shutting down, reason: " << e.what();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG(FATAL) << e.what();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user