mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-06-22 08:31:07 +00:00
Basic foundation done
This commit is contained in:
+1
-1
@@ -41,7 +41,7 @@ add_executable(${PROJECT_NAME}
|
|||||||
src/Network/Http.cpp include/Http.h
|
src/Network/Http.cpp include/Http.h
|
||||||
src/Network/Login.cpp src/Network/Update.cpp
|
src/Network/Login.cpp src/Network/Update.cpp
|
||||||
src/Discord.cpp src/Config.cpp
|
src/Discord.cpp src/Config.cpp
|
||||||
src/Memory/Memory.cpp include/Memory.h
|
src/BeamNG.cpp include/BeamNG.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
class Memory {
|
class BeamNG {
|
||||||
public:
|
public:
|
||||||
static size_t GetProcessID(const char* PName);
|
|
||||||
static size_t GetModuleBase(const char* Name);
|
static size_t GetModuleBase(const char* Name);
|
||||||
|
static uint32_t GetProcessID();
|
||||||
};
|
};
|
||||||
+8
-2
@@ -23,6 +23,7 @@ public: //constructors
|
|||||||
Launcher(int argc, char* argv[]);
|
Launcher(int argc, char* argv[]);
|
||||||
~Launcher();
|
~Launcher();
|
||||||
public: //available functions
|
public: //available functions
|
||||||
|
static void StaticAbort(Launcher* Instance = nullptr);
|
||||||
std::string Login(const std::string& fields);
|
std::string Login(const std::string& fields);
|
||||||
void RunDiscordRPC();
|
void RunDiscordRPC();
|
||||||
void QueryRegistry();
|
void QueryRegistry();
|
||||||
@@ -30,6 +31,7 @@ public: //available functions
|
|||||||
void LoadConfig();
|
void LoadConfig();
|
||||||
void LaunchGame();
|
void LaunchGame();
|
||||||
void CheckKey();
|
void CheckKey();
|
||||||
|
void SetupMOD();
|
||||||
public: //Getters
|
public: //Getters
|
||||||
const std::string& getFullVersion();
|
const std::string& getFullVersion();
|
||||||
const std::string& getUserRole();
|
const std::string& getUserRole();
|
||||||
@@ -40,22 +42,26 @@ private: //functions
|
|||||||
void RichPresence();
|
void RichPresence();
|
||||||
void WindowsInit();
|
void WindowsInit();
|
||||||
void UpdateCheck();
|
void UpdateCheck();
|
||||||
|
void ResetMods();
|
||||||
|
void EnableMP();
|
||||||
void Relaunch();
|
void Relaunch();
|
||||||
|
void Abort();
|
||||||
private: //variables
|
private: //variables
|
||||||
size_t GamePID{0};
|
uint32_t GamePID{0};
|
||||||
bool EnableUI = true;
|
bool EnableUI = true;
|
||||||
bool Shutdown = false;
|
|
||||||
bool LoginAuth = false;
|
bool LoginAuth = false;
|
||||||
fs::path CurrentPath{};
|
fs::path CurrentPath{};
|
||||||
std::string BeamRoot{};
|
std::string BeamRoot{};
|
||||||
std::string UserRole{};
|
std::string UserRole{};
|
||||||
std::string PublicKey{};
|
std::string PublicKey{};
|
||||||
std::thread DiscordRPC{};
|
std::thread DiscordRPC{};
|
||||||
|
std::string MPUserPath{};
|
||||||
std::string BeamVersion{};
|
std::string BeamVersion{};
|
||||||
std::string BeamUserPath{};
|
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::atomic<bool> Shutdown{false};
|
||||||
std::string FullVersion{Version + ".0"};
|
std::string FullVersion{Version + ".0"};
|
||||||
VersionParser SupportedVersion{"0.24.1.1"};
|
VersionParser SupportedVersion{"0.24.1.1"};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Memory.h"
|
#include "BeamNG.h"
|
||||||
#undef UNICODE
|
#undef UNICODE
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
|
|
||||||
size_t Memory::GetProcessID(const char* PName) {
|
uint32_t BeamNG::GetProcessID() {
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
PROCESSENTRY32 pe32;
|
PROCESSENTRY32 pe32;
|
||||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||||
@@ -18,7 +18,7 @@ size_t Memory::GetProcessID(const char* PName) {
|
|||||||
|
|
||||||
if(Process32First(Snapshot, &pe32)) {
|
if(Process32First(Snapshot, &pe32)) {
|
||||||
do{
|
do{
|
||||||
if(std::string(PName) == pe32.szExeFile)break;
|
if(std::string("BeamNG.drive.x64.exe") == pe32.szExeFile)break;
|
||||||
}while(Process32Next(Snapshot, &pe32));
|
}while(Process32Next(Snapshot, &pe32));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +30,6 @@ size_t Memory::GetProcessID(const char* PName) {
|
|||||||
return pe32.th32ProcessID;
|
return pe32.th32ProcessID;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Memory::GetModuleBase(const char* Name) {
|
size_t BeamNG::GetModuleBase(const char* Name) {
|
||||||
return (size_t)GetModuleHandleA(Name);
|
return (size_t)GetModuleHandleA(Name);
|
||||||
}
|
}
|
||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
void Launcher::RichPresence() {
|
void Launcher::RichPresence() {
|
||||||
Discord_Initialize("629743237988352010", nullptr, 1,nullptr);
|
Discord_Initialize("629743237988352010", nullptr, 1,nullptr);
|
||||||
int64_t Start{};
|
int64_t Start{};
|
||||||
while(!Shutdown) {
|
while(!Shutdown.load()) {
|
||||||
DiscordRichPresence discordPresence;
|
DiscordRichPresence discordPresence;
|
||||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||||
discordPresence.state = DiscordMessage.c_str();
|
discordPresence.state = DiscordMessage.c_str();
|
||||||
|
|||||||
+59
-12
@@ -6,25 +6,67 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Memory.h"
|
#include "BeamNG.h"
|
||||||
#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") {
|
||||||
|
Launcher::StaticAbort(this);
|
||||||
Log::Init();
|
Log::Init();
|
||||||
WindowsInit();
|
WindowsInit();
|
||||||
LOG(INFO) << "Starting Launcher V" << FullVersion;
|
LOG(INFO) << "Starting Launcher V" << FullVersion;
|
||||||
UpdateCheck();
|
UpdateCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
Launcher::~Launcher() {
|
void Launcher::Abort() {
|
||||||
Shutdown = true;
|
Shutdown.store(true);
|
||||||
if(DiscordRPC.joinable()) {
|
if(DiscordRPC.joinable()) {
|
||||||
DiscordRPC.join();
|
DiscordRPC.join();
|
||||||
}
|
}
|
||||||
|
if(!MPUserPath.empty()) {
|
||||||
|
ResetMods();
|
||||||
|
}
|
||||||
|
if(GamePID != 0) {
|
||||||
|
auto Handle = OpenProcess(PROCESS_TERMINATE, false, DWORD(GamePID));
|
||||||
|
TerminateProcess(Handle, 0);
|
||||||
|
CloseHandle(Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Launcher::~Launcher() {
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI CtrlHandler(DWORD Flag) {
|
||||||
|
if((Flag >= 0 && Flag < 3) || (Flag > 4 && Flag < 7)) {
|
||||||
|
Launcher::StaticAbort();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::StaticAbort(Launcher* Instance) {
|
||||||
|
static Launcher* Address;
|
||||||
|
if(Instance) {
|
||||||
|
Address = Instance;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Address->Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::WindowsInit() {
|
||||||
|
system("cls");
|
||||||
|
SetConsoleTitleA(("BeamMP Launcher v" + FullVersion).c_str());
|
||||||
|
if(!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
|
||||||
|
LOG(WARNING) << "Failed to set CtrlHandler";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::LaunchGame() {
|
void Launcher::LaunchGame() {
|
||||||
|
if(BeamNG::GetProcessID() != 0) {
|
||||||
|
LOG(FATAL) << "Game is already running, please close it and try again!";
|
||||||
|
throw ShutdownException("Fatal Error");
|
||||||
|
}
|
||||||
VersionParser GameVersion(BeamVersion);
|
VersionParser GameVersion(BeamVersion);
|
||||||
if(GameVersion.data[0] > SupportedVersion.data[0]) {
|
if(GameVersion.data[0] > SupportedVersion.data[0]) {
|
||||||
LOG(FATAL) << "BeamNG V" << BeamVersion << " not yet supported, please wait until we update BeamMP!";
|
LOG(FATAL) << "BeamNG V" << BeamVersion << " not yet supported, please wait until we update BeamMP!";
|
||||||
@@ -43,20 +85,22 @@ void Launcher::LaunchGame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::WaitForGame() {
|
void Launcher::WaitForGame() {
|
||||||
LOG(INFO) << "Waiting for game launch";
|
LOG(INFO) << "Waiting for the game, please start BeamNG manually in case of steam issues";
|
||||||
do{
|
do{
|
||||||
GamePID = Memory::GetProcessID("BeamNG.drive.x64.exe");
|
GamePID = BeamNG::GetProcessID();
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||||
}while(GamePID == 0 && !Shutdown);
|
}while(GamePID == 0 && !Shutdown.load());
|
||||||
|
if(Shutdown.load())return;
|
||||||
if(GamePID == 0) {
|
if(GamePID == 0) {
|
||||||
LOG(FATAL) << "Game process not found! aborting";
|
LOG(FATAL) << "Game process not found! aborting";
|
||||||
throw ShutdownException("Fatal Error");
|
throw ShutdownException("Fatal Error");
|
||||||
}else LOG(INFO) << "Game found! PID " << GamePID;
|
|
||||||
}
|
}
|
||||||
|
LOG(INFO) << "Game found! PID " << GamePID;
|
||||||
void Launcher::WindowsInit() {
|
//TODO: Inject then start IPC
|
||||||
system("cls");
|
while(!Shutdown.load() && BeamNG::GetProcessID() != 0) {
|
||||||
SetConsoleTitleA(("BeamMP Launcher v" + FullVersion).c_str());
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Game process was lost";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string QueryValue(HKEY& hKey, const char* Name) {
|
std::string QueryValue(HKEY& hKey, const char* Name) {
|
||||||
@@ -95,6 +139,9 @@ void Launcher::QueryRegistry() {
|
|||||||
VersionParser GameVer(BeamVersion);
|
VersionParser GameVer(BeamVersion);
|
||||||
BeamUserPath += GameVer.split[0] + '.' + GameVer.split[1] + '\\';
|
BeamUserPath += GameVer.split[0] + '.' + GameVer.split[1] + '\\';
|
||||||
}
|
}
|
||||||
|
if(!BeamUserPath.empty()) {
|
||||||
|
MPUserPath = BeamUserPath + "mods\\multiplayer";
|
||||||
|
}
|
||||||
if(!BeamRoot.empty() && !BeamVersion.empty() && !BeamUserPath.empty())return;
|
if(!BeamRoot.empty() && !BeamVersion.empty() && !BeamUserPath.empty())return;
|
||||||
}
|
}
|
||||||
LOG(FATAL) << "Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive";
|
LOG(FATAL) << "Please launch the game at least once, failed to read registry key Software\\BeamNG\\BeamNG.drive";
|
||||||
|
|||||||
@@ -102,15 +102,14 @@ bool HTTP::Download(const std::string &IP, const std::string &Path) {
|
|||||||
isDownload = false;
|
isDownload = false;
|
||||||
|
|
||||||
if(Ret.empty())return false;
|
if(Ret.empty())return false;
|
||||||
|
std::cout << "\n";
|
||||||
std::ofstream File(Path, std::ios::binary);
|
std::ofstream File(Path, std::ios::binary);
|
||||||
if(File.is_open()) {
|
if(File.is_open()) {
|
||||||
File << Ret;
|
File << Ret;
|
||||||
File.close();
|
File.close();
|
||||||
std::cout << "\n";
|
LOG(INFO) << "Download complete!";
|
||||||
LOG(INFO) << "Download Complete!";
|
|
||||||
} else {
|
} else {
|
||||||
LOG(INFO) << "Failed to open file directory: " << Path;
|
LOG(ERROR) << "Failed to open file directory: " << Path;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
|
#include "Json.h"
|
||||||
|
|
||||||
VersionParser::VersionParser(const std::string &from_string) {
|
VersionParser::VersionParser(const std::string &from_string) {
|
||||||
std::string token;
|
std::string token;
|
||||||
@@ -78,3 +79,57 @@ void Launcher::UpdateCheck() {
|
|||||||
Relaunch();
|
Relaunch();
|
||||||
}else LOG(INFO) << "Launcher version is up to date";
|
}else LOG(INFO) << "Launcher version is up to date";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t DirCount(const std::filesystem::path& path){
|
||||||
|
return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::ResetMods() {
|
||||||
|
if (!fs::exists(MPUserPath)) {
|
||||||
|
fs::create_directories(MPUserPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DirCount(fs::path(MPUserPath)) > 3) {
|
||||||
|
LOG(WARNING) << "mods/multiplayer will be cleared in 15 seconds, close to abort";
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(15));
|
||||||
|
}
|
||||||
|
fs::remove_all(MPUserPath);
|
||||||
|
fs::create_directories(MPUserPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::EnableMP() {
|
||||||
|
std::string File(BeamUserPath + "mods\\db.json");
|
||||||
|
if(!fs::exists(File))return;
|
||||||
|
auto Size = fs::file_size(File);
|
||||||
|
if(Size < 2)return;
|
||||||
|
std::ifstream db(File);
|
||||||
|
if(db.is_open()) {
|
||||||
|
std::string Data(Size, 0);
|
||||||
|
db.read(&Data[0], std::streamsize(Size));
|
||||||
|
db.close();
|
||||||
|
Json::Document d;
|
||||||
|
d.Parse(Data.c_str());
|
||||||
|
if(Data.at(0) != '{' || d.HasParseError())return;
|
||||||
|
if(!d["mods"].IsNull() && !d["mods"]["multiplayerbeammp"].IsNull()){
|
||||||
|
d["mods"]["multiplayerbeammp"]["active"] = true;
|
||||||
|
Json::StringBuffer buffer;
|
||||||
|
Json::Writer<Json::StringBuffer> writer(buffer);
|
||||||
|
d.Accept(writer);
|
||||||
|
std::ofstream ofs(File);
|
||||||
|
if(ofs.is_open()){
|
||||||
|
ofs << buffer.GetString();
|
||||||
|
ofs.close();
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Failed to write " << File;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launcher::SetupMOD() {
|
||||||
|
ResetMods();
|
||||||
|
EnableMP();
|
||||||
|
LOG(INFO) << "Downloading mod please wait";
|
||||||
|
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
|
||||||
|
"&pk=" + PublicKey + "&branch=" + TargetBuild, MPUserPath + "\\BeamMP.zip");
|
||||||
|
}
|
||||||
|
|||||||
+3
-3
@@ -14,15 +14,15 @@ int main(int argc, char* argv[]) {
|
|||||||
launcher.CheckKey();
|
launcher.CheckKey();
|
||||||
launcher.QueryRegistry();
|
launcher.QueryRegistry();
|
||||||
//UI call
|
//UI call
|
||||||
//download mod
|
launcher.SetupMOD();
|
||||||
launcher.LaunchGame();
|
launcher.LaunchGame();
|
||||||
launcher.WaitForGame();
|
launcher.WaitForGame();
|
||||||
|
LOG(INFO) << "Launcher shutting down";
|
||||||
|
|
||||||
} catch (const ShutdownException& e) {
|
} catch (const ShutdownException& e) {
|
||||||
LOG(INFO) << "Launcher shutting down with reason: " << e.what();
|
LOG(INFO) << "Launcher shutting down with reason: " << e.what();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LOG(FATAL) << e.what();
|
LOG(FATAL) << e.what();
|
||||||
}
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user