mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2025-07-01 23:46:59 +00:00
- new backend links
- self updating - add open_url lua function with filter
This commit is contained in:
parent
58e9fef53f
commit
a504114809
@ -35,7 +35,7 @@ add_executable(${PROJECT_NAME}
|
||||
src/Memory/IPC.cpp include/Memory/IPC.h
|
||||
src/Logger.cpp include/Logger.h
|
||||
#src/gui/Gui.cpp
|
||||
include/Json.h
|
||||
include/Json.h include/hashpp.h
|
||||
src/Network/HttpAPI.cpp include/HttpAPI.h
|
||||
src/Network/Server.cpp include/Server.h
|
||||
src/Network/Login.cpp src/Network/Update.cpp
|
||||
|
@ -33,10 +33,12 @@ class Launcher {
|
||||
void SendIPC(const std::string& Data, bool core = true);
|
||||
void LoadConfig(const fs::path& conf);
|
||||
void RunDiscordRPC();
|
||||
void UpdateCheck();
|
||||
void WaitForGame();
|
||||
void LaunchGame();
|
||||
void CheckKey();
|
||||
void SetupMOD();
|
||||
|
||||
static std::string QueryValue(HKEY& hKey, const char* Name);
|
||||
|
||||
public: // Getters and Setters
|
||||
@ -53,6 +55,7 @@ class Launcher {
|
||||
|
||||
private: // functions
|
||||
void HandleIPC(const std::string& Data);
|
||||
bool IsAllowedLink(const std::string& Link);
|
||||
std::string GetProfileVersion();
|
||||
fs::path GetProfileRoot();
|
||||
void UpdatePresence();
|
||||
@ -65,8 +68,8 @@ class Launcher {
|
||||
|
||||
public: // variables
|
||||
static inline std::thread EntryThread{};
|
||||
static inline std::string Version{"2.0"};
|
||||
static inline std::string FullVersion{Version + ".99"};
|
||||
static inline std::string Version{"2.1"};
|
||||
static inline std::string FullVersion{Version + ".0"};
|
||||
|
||||
private: // variables
|
||||
uint32_t GamePID{0};
|
||||
|
4642
include/hashpp.h
Normal file
4642
include/hashpp.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -48,7 +48,8 @@ void Launcher::LoadConfig(const fs::path& conf) { // check if json (issue)
|
||||
auto GameProfile = GetProfileRoot();
|
||||
std::ofstream tml(conf);
|
||||
if (tml.is_open()) {
|
||||
tml << "Build = 'Default'\n"
|
||||
tml << "# Build is the lua build, it can be either default, canary, or public\n"
|
||||
"Build = 'default'\n"
|
||||
"CachePath = 'Resources'\n"
|
||||
"ProfilePath = '"
|
||||
<< GameProfile.string() << "'";
|
||||
|
108
src/Handler.cpp
108
src/Handler.cpp
@ -8,57 +8,69 @@
|
||||
#include "Logger.h"
|
||||
#include "Memory/BeamNG.h"
|
||||
#include "Memory/Memory.h"
|
||||
#include <regex>
|
||||
|
||||
void Launcher::HandleIPC(const std::string& Data) { //TODO Improve all cases since SendIPC can be called async
|
||||
char Code = Data.at(0), SubCode = 0;
|
||||
if (Data.length() > 1) SubCode = Data.at(1);
|
||||
switch (Code) {
|
||||
case 'A':
|
||||
ServerHandler.StartUDP();
|
||||
break;
|
||||
case 'B':
|
||||
ServerHandler.Close();
|
||||
SendIPC(Code + HTTP::Get("https://backend.beammp.com/servers-info"));
|
||||
LOG(INFO) << "Sent Server List";
|
||||
break;
|
||||
case 'C':
|
||||
ServerHandler.Close();
|
||||
ServerHandler.Connect(Data);
|
||||
while (ServerHandler.getModList().empty() &&
|
||||
!ServerHandler.Terminated()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
if (ServerHandler.getModList() == "-") SendIPC("L");
|
||||
else SendIPC("L" + ServerHandler.getModList());
|
||||
break;
|
||||
case 'U':
|
||||
SendIPC("Ul" + ServerHandler.getUIStatus());
|
||||
break;
|
||||
case 'M':
|
||||
SendIPC(ServerHandler.getMap());
|
||||
break;
|
||||
case 'Q':
|
||||
if (SubCode == 'S') {
|
||||
char Code = Data.at(0), SubCode = 0;
|
||||
if (Data.length() > 1) SubCode = Data.at(1);
|
||||
switch (Code) {
|
||||
case 'A':
|
||||
ServerHandler.StartUDP();
|
||||
break;
|
||||
case 'B':
|
||||
ServerHandler.Close();
|
||||
}
|
||||
if (SubCode == 'G') exit(2);
|
||||
break;
|
||||
case 'R': // will send mod name
|
||||
ServerHandler.setModLoaded();
|
||||
break;
|
||||
case 'Z':
|
||||
SendIPC("Z" + Version);
|
||||
break;
|
||||
case 'N':
|
||||
if (SubCode == 'c') {
|
||||
SendIPC("N{\"Auth\":" + std::to_string(LoginAuth) + "}");
|
||||
} else {
|
||||
SendIPC("N" + Login(Data.substr(Data.find(':') + 1)));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SendIPC(Code + HTTP::Get("https://backend.beammp.com/servers-info"));
|
||||
LOG(INFO) << "Sent Server List";
|
||||
break;
|
||||
case 'C':
|
||||
ServerHandler.Close();
|
||||
ServerHandler.Connect(Data);
|
||||
while (ServerHandler.getModList().empty() &&
|
||||
!ServerHandler.Terminated()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
if (ServerHandler.getModList() == "-") SendIPC("L");
|
||||
else SendIPC("L" + ServerHandler.getModList());
|
||||
break;
|
||||
case 'U':
|
||||
SendIPC("Ul" + ServerHandler.getUIStatus());
|
||||
break;
|
||||
case 'M':
|
||||
SendIPC(ServerHandler.getMap());
|
||||
break;
|
||||
case 'Q':
|
||||
if (SubCode == 'S') {
|
||||
ServerHandler.Close();
|
||||
}
|
||||
if (SubCode == 'G') exit(2);
|
||||
break;
|
||||
case 'R': // will send mod name
|
||||
ServerHandler.setModLoaded();
|
||||
break;
|
||||
case 'Z':
|
||||
SendIPC("Z" + Version);
|
||||
break;
|
||||
case 'N':
|
||||
if (SubCode == 'c') {
|
||||
SendIPC("N{\"Auth\":" + std::to_string(LoginAuth) + "}");
|
||||
} else {
|
||||
SendIPC("N" + Login(Data.substr(Data.find(':') + 1)));
|
||||
}
|
||||
break;
|
||||
case 'O': //open default browser with URL
|
||||
if(IsAllowedLink(Data.substr(1))) {
|
||||
ShellExecuteA(nullptr, "open", Data.substr(1).c_str(), nullptr, nullptr,SW_SHOW); ///TODO: Look at when working on linux port
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Launcher::IsAllowedLink(const std::string& Link) {
|
||||
std::regex link_pattern(R"(https:\/\/(?:\w+)?(?:\.)?(?:beammp|discord)\.com)");
|
||||
std::smatch link_match;
|
||||
return std::regex_search(Link,link_match, link_pattern) && link_match.position() == 0;
|
||||
}
|
||||
|
||||
void Server::ServerParser(const std::string& Data) {
|
||||
|
@ -31,7 +31,7 @@ Launcher::Launcher(int argc, char* argv[]) :
|
||||
DiscordTime = std::time(nullptr);
|
||||
WindowsInit();
|
||||
SetUnhandledExceptionFilter(CrashHandler);
|
||||
LOG(INFO) << "Starting Launcher V" << FullVersion;
|
||||
LOG(INFO) << "Starting Launcher v" << FullVersion;
|
||||
if (argc > 1) LoadConfig(fs::current_path() / argv[1]);
|
||||
else LoadConfig(fs::current_path() / "Launcher.toml");
|
||||
}
|
||||
@ -234,4 +234,4 @@ const fs::path& Launcher::getCachePath() {
|
||||
fs::create_directories(LauncherCache);
|
||||
}
|
||||
return LauncherCache;
|
||||
}
|
||||
}
|
@ -97,14 +97,25 @@ int LuaPop(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaOpenURL(lua_State* L) {
|
||||
if (lua_gettop(L) == 1) {
|
||||
size_t Size;
|
||||
const char* Data = GELua::lua_tolstring(L, 1, &Size);
|
||||
std::string msg(Data, Size);
|
||||
BeamNG::SendIPC("CO" + msg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BeamNG::RegisterGEFunctions() {
|
||||
Memory::Print("Registering GE Functions");
|
||||
GELuaTable::Begin(GELua::State);
|
||||
GELuaTable::InsertFunction(GELua::State, "Core", Core);
|
||||
GELuaTable::InsertFunction(GELua::State, "Game", Game);
|
||||
GELuaTable::InsertFunction(GELua::State, "try_pop", LuaPop);
|
||||
GELuaTable::End(GELua::State, "MP");
|
||||
Memory::Print("Registered!");
|
||||
Memory::Print("Registering GE Functions");
|
||||
GELuaTable::Begin(GELua::State);
|
||||
GELuaTable::InsertFunction(GELua::State, "Core", Core);
|
||||
GELuaTable::InsertFunction(GELua::State, "Game", Game);
|
||||
GELuaTable::InsertFunction(GELua::State, "try_pop", LuaPop);
|
||||
GELuaTable::InsertFunction(GELua::State, "open_url", LuaOpenURL);
|
||||
GELuaTable::End(GELua::State, "MP");
|
||||
Memory::Print("Registered!");
|
||||
}
|
||||
|
||||
void BeamNG::SendIPC(const std::string& Data) {
|
||||
|
@ -35,43 +35,47 @@ std::string GetFail(const std::string& R) {
|
||||
}
|
||||
|
||||
std::string Launcher::Login(const std::string& fields) {
|
||||
if (fields == "LO") {
|
||||
LoginAuth = false;
|
||||
UpdateKey("");
|
||||
return "";
|
||||
}
|
||||
LOG(INFO) << "Attempting to authenticate...";
|
||||
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
|
||||
Json d = Json::parse(Buffer, nullptr, false);
|
||||
if (fields == "LO") {
|
||||
LoginAuth = false;
|
||||
UpdateKey("");
|
||||
return "";
|
||||
}
|
||||
LOG(INFO) << "Attempting to authenticate...";
|
||||
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
|
||||
Json d = Json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer == "-1") {
|
||||
return GetFail("Failed to communicate with the auth system!");
|
||||
}
|
||||
if (Buffer == "-1") {
|
||||
return GetFail("Failed to communicate with the auth system!");
|
||||
}
|
||||
|
||||
if (Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
LOG(ERROR) << Buffer;
|
||||
return GetFail(
|
||||
"Invalid answer from authentication servers, please try again "
|
||||
"later!");
|
||||
}
|
||||
if (Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
LOG(ERROR) << Buffer;
|
||||
return GetFail(
|
||||
"Invalid answer from authentication servers, please try again "
|
||||
"later!");
|
||||
}
|
||||
|
||||
if (!d["success"].is_null() && d["success"].get<bool>()) {
|
||||
LoginAuth = true;
|
||||
if (!d["private_key"].is_null()) {
|
||||
UpdateKey(d["private_key"].get<std::string>());
|
||||
}
|
||||
if (!d["public_key"].is_null()) {
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
}
|
||||
LOG(INFO) << "Authentication successful!";
|
||||
} else LOG(WARNING) << "Authentication failed!";
|
||||
if (!d["success"].is_null() && d["success"].get<bool>()) {
|
||||
LoginAuth = true;
|
||||
if (!d["private_key"].is_null()) {
|
||||
UpdateKey(d["private_key"].get<std::string>());
|
||||
}
|
||||
if (!d["public_key"].is_null()) {
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
}
|
||||
if (!d["role"].is_null()) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
LOG(INFO) << "Authentication successful!";
|
||||
} else
|
||||
LOG(WARNING) << "Authentication failed!";
|
||||
|
||||
if (!d["message"].is_null()) {
|
||||
d.erase("private_key");
|
||||
d.erase("public_key");
|
||||
return d.dump();
|
||||
}
|
||||
return GetFail("Invalid message parsing!");
|
||||
if (!d["message"].is_null()) {
|
||||
d.erase("private_key");
|
||||
d.erase("public_key");
|
||||
return d.dump();
|
||||
}
|
||||
return GetFail("Invalid message parsing!");
|
||||
}
|
||||
|
||||
void Launcher::CheckKey() {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Json.h"
|
||||
#include "Launcher.h"
|
||||
#include "Logger.h"
|
||||
#include "hashpp.h"
|
||||
|
||||
VersionParser::VersionParser(const std::string& from_string) {
|
||||
std::string token;
|
||||
@ -40,17 +41,20 @@ size_t DirCount(const std::filesystem::path& path) {
|
||||
}
|
||||
|
||||
void Launcher::ResetMods() {
|
||||
if (!fs::exists(MPUserPath)) {
|
||||
fs::create_directories(MPUserPath);
|
||||
return;
|
||||
}
|
||||
if (DirCount(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);
|
||||
if (!fs::exists(MPUserPath)) {
|
||||
fs::create_directories(MPUserPath);
|
||||
return;
|
||||
}
|
||||
if (DirCount(MPUserPath) > 3) {
|
||||
LOG(WARNING)
|
||||
<< "mods/multiplayer will be cleared in 15 seconds, close to abort";
|
||||
std::this_thread::sleep_for(std::chrono::seconds(15));
|
||||
}
|
||||
for (auto &de: std::filesystem::directory_iterator(MPUserPath)) {
|
||||
if (de.path().filename() != "BeamMP.zip") {
|
||||
std::filesystem::remove(de.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::EnableMP() {
|
||||
@ -78,13 +82,43 @@ void Launcher::EnableMP() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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").string());
|
||||
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/mod?branch=" + TargetBuild + "&pk=" + PublicKey);
|
||||
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
|
||||
|
||||
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, (MPUserPath / "BeamMP.zip").string());
|
||||
|
||||
ResetMods();
|
||||
EnableMP();
|
||||
|
||||
if (FileHash != LatestHash) {
|
||||
LOG(INFO) << "Downloading BeamMP Update " << LatestHash;
|
||||
HTTP::Download(
|
||||
"https://backend.beammp.com/builds/mod?download=true"
|
||||
"&pk=" +
|
||||
PublicKey + "&branch=" + TargetBuild,
|
||||
(MPUserPath / "BeamMP.zip").string());
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::UpdateCheck() {
|
||||
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + TargetBuild + "&pk=" + PublicKey);
|
||||
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
|
||||
|
||||
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, "BeamMP-Launcher.exe");
|
||||
|
||||
if(FileHash != LatestHash) {
|
||||
LOG(INFO) << "Launcher update found!";
|
||||
fs::remove("BeamMP-Launcher.back");
|
||||
fs::rename("BeamMP-Launcher.exe", "BeamMP-Launcher.back");
|
||||
LOG(INFO) << "Downloading Launcher update " << LatestHash;
|
||||
HTTP::Download(
|
||||
"https://backend.beammp.com/builds/launcher?download=true"
|
||||
"&pk=" +
|
||||
PublicKey + "&branch=" + TargetBuild,
|
||||
"BeamMP-Launcher.exe");
|
||||
throw ShutdownException("Launcher update");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,9 +9,10 @@
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
Launcher launcher(argc, argv);
|
||||
launcher.UpdateCheck();
|
||||
launcher.RunDiscordRPC();
|
||||
launcher.CheckKey();
|
||||
// launcher.SetupMOD();
|
||||
launcher.SetupMOD();
|
||||
launcher.LaunchGame();
|
||||
launcher.WaitForGame();
|
||||
LOG(INFO) << "Launcher shutting down";
|
||||
|
Loading…
x
Reference in New Issue
Block a user