mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-04-06 15:56:26 +00:00
reformat
This commit is contained in:
214
src/Startup.cpp
214
src/Startup.cpp
@@ -6,25 +6,24 @@
|
||||
/// Created by Anonymous275 on 7/16/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <httplib.h>
|
||||
#include "zip_file.h"
|
||||
#include <httplib.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "Http.h"
|
||||
#include "Logger.h"
|
||||
#include "Network/network.hpp"
|
||||
#include "Security/Init.h"
|
||||
#include <filesystem>
|
||||
#include "Startup.h"
|
||||
#include "hashpp.h"
|
||||
#include "Logger.h"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include "Http.h"
|
||||
|
||||
|
||||
extern int TraceBack;
|
||||
bool Dev = false;
|
||||
@@ -42,23 +41,29 @@ VersionParser::VersionParser(const std::string& from_string) {
|
||||
}
|
||||
|
||||
std::strong_ordering VersionParser::operator<=>(
|
||||
const VersionParser& rhs) const noexcept {
|
||||
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[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;
|
||||
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);
|
||||
}
|
||||
|
||||
std::string GetEN(){
|
||||
std::string GetEN() {
|
||||
#if defined(_WIN32)
|
||||
return "BeamMP-Launcher.exe";
|
||||
#elif defined(__linux__)
|
||||
@@ -66,61 +71,61 @@ std::string GetEN(){
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetVer(){
|
||||
std::string GetVer() {
|
||||
return "2.0";
|
||||
}
|
||||
std::string GetPatch(){
|
||||
std::string GetPatch() {
|
||||
return ".85";
|
||||
}
|
||||
|
||||
std::string GetEP(char*P){
|
||||
static std::string Ret = [&](){
|
||||
std::string GetEP(char* P) {
|
||||
static std::string Ret = [&]() {
|
||||
std::string path(P);
|
||||
return path.substr(0, path.find_last_of("\\/") + 1);
|
||||
} ();
|
||||
}();
|
||||
return Ret;
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
void ReLaunch(int argc,char*args[]){
|
||||
void ReLaunch(int argc, char* args[]) {
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
for (int c = 2; c <= argc; c++) {
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
Arg += args[c - 1];
|
||||
}
|
||||
system("cls");
|
||||
ShellExecute(nullptr,"runas",(GetEP() + GetEN()).c_str(),Arg.c_str(),nullptr,SW_SHOWNORMAL);
|
||||
ShowWindow(GetConsoleWindow(),0);
|
||||
ShellExecute(nullptr, "runas", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
ShowWindow(GetConsoleWindow(), 0);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
}
|
||||
void URelaunch(int argc,char* args[]){
|
||||
void URelaunch(int argc, char* args[]) {
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
for (int c = 2; c <= argc; c++) {
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
Arg += args[c - 1];
|
||||
}
|
||||
ShellExecute(nullptr,"open",(GetEP() + GetEN()).c_str(),Arg.c_str(),nullptr,SW_SHOWNORMAL);
|
||||
ShowWindow(GetConsoleWindow(),0);
|
||||
ShellExecute(nullptr, "open", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
ShowWindow(GetConsoleWindow(), 0);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
void ReLaunch(int argc,char*args[]){
|
||||
void ReLaunch(int argc, char* args[]) {
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
for (int c = 2; c <= argc; c++) {
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
Arg += args[c - 1];
|
||||
}
|
||||
system("clear");
|
||||
execl((GetEP() + GetEN()).c_str(), Arg.c_str(), NULL);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
}
|
||||
void URelaunch(int argc,char* args[]){
|
||||
void URelaunch(int argc, char* args[]) {
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
for (int c = 2; c <= argc; c++) {
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
Arg += args[c - 1];
|
||||
}
|
||||
execl((GetEP() + GetEN()).c_str(), Arg.c_str(), NULL);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
@@ -128,81 +133,86 @@ void URelaunch(int argc,char* args[]){
|
||||
}
|
||||
#endif
|
||||
|
||||
void CheckName(int argc,char* args[]){
|
||||
#if defined(_WIN32)
|
||||
std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('\\')+1);
|
||||
#elif defined(__linux__)
|
||||
std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('/')+1);
|
||||
#endif
|
||||
if(FN != DN){
|
||||
if(fs::exists(DN))remove(DN.c_str());
|
||||
if(fs::exists(DN))ReLaunch(argc,args);
|
||||
void CheckName(int argc, char* args[]) {
|
||||
#if defined(_WIN32)
|
||||
std::string DN = GetEN(), CDir = args[0], FN = CDir.substr(CDir.find_last_of('\\') + 1);
|
||||
#elif defined(__linux__)
|
||||
std::string DN = GetEN(), CDir = args[0], FN = CDir.substr(CDir.find_last_of('/') + 1);
|
||||
#endif
|
||||
if (FN != DN) {
|
||||
if (fs::exists(DN))
|
||||
remove(DN.c_str());
|
||||
if (fs::exists(DN))
|
||||
ReLaunch(argc, args);
|
||||
std::rename(FN.c_str(), DN.c_str());
|
||||
URelaunch(argc,args);
|
||||
URelaunch(argc, args);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckForUpdates(int argc, char* args[], const std::string& CV) {
|
||||
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/launcher?branch=" + Branch + "&pk=" + PublicKey);
|
||||
std::string LatestVersion = HTTP::Get(
|
||||
"https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
|
||||
"https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
|
||||
|
||||
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
|
||||
std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back");
|
||||
|
||||
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, EP);
|
||||
#if defined(_WIN32)
|
||||
#elif defined(__linux__)
|
||||
system("clear");
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#elif defined(__linux__)
|
||||
system("clear");
|
||||
#endif
|
||||
|
||||
if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer()+GetPatch())) {
|
||||
if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer() + GetPatch())) {
|
||||
info("Launcher update found!");
|
||||
fs::remove(Back);
|
||||
fs::rename(EP, Back);
|
||||
info("Downloading Launcher update " + LatestHash);
|
||||
HTTP::Download(
|
||||
"https://backend.beammp.com/builds/launcher?download=true"
|
||||
"&pk=" +
|
||||
PublicKey + "&branch=" + Branch,
|
||||
EP);
|
||||
"https://backend.beammp.com/builds/launcher?download=true"
|
||||
"&pk="
|
||||
+ PublicKey + "&branch=" + Branch,
|
||||
EP);
|
||||
URelaunch(argc, args);
|
||||
} else info("Launcher version is up to date");
|
||||
} else
|
||||
info("Launcher version is up to date");
|
||||
TraceBack++;
|
||||
}
|
||||
|
||||
void CustomPort(int argc, char* argv[]){
|
||||
if(argc > 1){
|
||||
void CustomPort(int argc, char* argv[]) {
|
||||
if (argc > 1) {
|
||||
std::string Port = argv[1];
|
||||
if(Port.find_first_not_of("0123456789") == std::string::npos){
|
||||
if(std::stoi(Port) > 1000){
|
||||
if (Port.find_first_not_of("0123456789") == std::string::npos) {
|
||||
if (std::stoi(Port) > 1000) {
|
||||
DEFAULT_PORT = std::stoi(Port);
|
||||
warn("Running on custom port : " + std::to_string(DEFAULT_PORT));
|
||||
}
|
||||
}
|
||||
if(argc > 2)Dev = true;
|
||||
if (argc > 2)
|
||||
Dev = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void LinuxPatch(){
|
||||
void LinuxPatch() {
|
||||
HKEY hKey = nullptr;
|
||||
LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, R"(Software\Wine)", 0, KEY_READ, &hKey);
|
||||
if (result != ERROR_SUCCESS || getenv("USER") == nullptr)return;
|
||||
if (result != ERROR_SUCCESS || getenv("USER") == nullptr)
|
||||
return;
|
||||
RegCloseKey(hKey);
|
||||
info("Wine/Proton Detected! If you are on windows delete HKEY_CURRENT_USER\\Software\\Wine in regedit");
|
||||
info("Applying patches...");
|
||||
|
||||
result = RegCreateKey(HKEY_CURRENT_USER, R"(Software\Valve\Steam\Apps\284160)", &hKey);
|
||||
|
||||
if (result != ERROR_SUCCESS){
|
||||
if (result != ERROR_SUCCESS) {
|
||||
fatal(R"(failed to create HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
|
||||
return;
|
||||
}
|
||||
|
||||
result = RegSetValueEx(hKey, "Name", 0, REG_SZ, (BYTE*)"BeamNG.drive", 12);
|
||||
|
||||
if (result != ERROR_SUCCESS){
|
||||
if (result != ERROR_SUCCESS) {
|
||||
fatal(R"(failed to create the value "Name" under HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
|
||||
return;
|
||||
}
|
||||
@@ -236,93 +246,100 @@ void InitLauncher(int argc, char* argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t DirCount(const std::filesystem::path& path){
|
||||
return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{});
|
||||
size_t DirCount(const std::filesystem::path& path) {
|
||||
return (size_t)std::distance(std::filesystem::directory_iterator { path }, std::filesystem::directory_iterator {});
|
||||
}
|
||||
|
||||
void CheckMP(const std::string& Path) {
|
||||
if (!fs::exists(Path))return;
|
||||
if (!fs::exists(Path))
|
||||
return;
|
||||
size_t c = DirCount(fs::path(Path));
|
||||
try {
|
||||
for (auto& p : fs::directory_iterator(Path)){
|
||||
if(p.exists() && !p.is_directory()){
|
||||
for (auto& p : fs::directory_iterator(Path)) {
|
||||
if (p.exists() && !p.is_directory()) {
|
||||
std::string Name = p.path().filename().string();
|
||||
for(char&Ch : Name)Ch = char(tolower(Ch));
|
||||
if(Name != "beammp.zip")fs::remove(p.path());
|
||||
for (char& Ch : Name)
|
||||
Ch = char(tolower(Ch));
|
||||
if (Name != "beammp.zip")
|
||||
fs::remove(p.path());
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
fatal("We were unable to clean the multiplayer mods folder! Is the game still running or do you have something open in that folder?");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EnableMP(){
|
||||
void EnableMP() {
|
||||
std::string File(GetGamePath() + "mods/db.json");
|
||||
if(!fs::exists(File))return;
|
||||
if (!fs::exists(File))
|
||||
return;
|
||||
auto Size = fs::file_size(File);
|
||||
if(Size < 2)return;
|
||||
if (Size < 2)
|
||||
return;
|
||||
std::ifstream db(File);
|
||||
if(db.is_open()) {
|
||||
if (db.is_open()) {
|
||||
std::string Data(Size, 0);
|
||||
db.read(&Data[0], Size);
|
||||
db.close();
|
||||
nlohmann::json d = nlohmann::json::parse(Data, nullptr, false);
|
||||
if(Data.at(0) != '{' || d.is_discarded()) {
|
||||
//error("Failed to parse " + File); //TODO illegal formatting
|
||||
if (Data.at(0) != '{' || d.is_discarded()) {
|
||||
// error("Failed to parse " + File); //TODO illegal formatting
|
||||
return;
|
||||
}
|
||||
if(d.contains("mods") && d["mods"].contains("multiplayerbeammp")){
|
||||
if (d.contains("mods") && d["mods"].contains("multiplayerbeammp")) {
|
||||
d["mods"]["multiplayerbeammp"]["active"] = true;
|
||||
std::ofstream ofs(File);
|
||||
if(ofs.is_open()){
|
||||
if (ofs.is_open()) {
|
||||
ofs << d.dump();
|
||||
ofs.close();
|
||||
}else{
|
||||
} else {
|
||||
error("Failed to write " + File);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreGame(const std::string& GamePath){
|
||||
void PreGame(const std::string& GamePath) {
|
||||
std::string GameVer = CheckVer(GamePath);
|
||||
info("Game Version : " + GameVer);
|
||||
|
||||
|
||||
CheckMP(GetGamePath() + "mods/multiplayer");
|
||||
|
||||
if(!Dev) {
|
||||
if (!Dev) {
|
||||
std::string LatestHash = HTTP::Get("https://backend.beammp.com/sha/mod?branch=" + Branch + "&pk=" + PublicKey);
|
||||
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
|
||||
LatestHash.erase(std::remove_if(LatestHash.begin(), LatestHash.end(),
|
||||
[](auto const& c ) -> bool { return !std::isalnum(c); } ), LatestHash.end());
|
||||
[](auto const& c) -> bool { return !std::isalnum(c); }),
|
||||
LatestHash.end());
|
||||
|
||||
try {
|
||||
if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
}
|
||||
EnableMP();
|
||||
}catch(std::exception&e){
|
||||
} catch (std::exception& e) {
|
||||
fatal(e.what());
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__)
|
||||
// Linux version of the game cant handle mods with uppercase names
|
||||
std::string ZipPath(GetGamePath() + R"(mods/multiplayer/beammp.zip)");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, ZipPath);
|
||||
|
||||
if (FileHash != LatestHash) {
|
||||
info("Downloading BeamMP Update " + LatestHash);
|
||||
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
|
||||
"&pk=" + PublicKey + "&branch=" + Branch, ZipPath);
|
||||
"&pk="
|
||||
+ PublicKey + "&branch=" + Branch,
|
||||
ZipPath);
|
||||
}
|
||||
|
||||
std::string Target(GetGamePath() + "mods/unpacked/beammp");
|
||||
|
||||
if(fs::is_directory(Target)) {
|
||||
if (fs::is_directory(Target)) {
|
||||
fs::remove_all(Target);
|
||||
}
|
||||
}
|
||||
@@ -335,15 +352,15 @@ void set_headers(httplib::Response& res) {
|
||||
}
|
||||
|
||||
void StartProxy() {
|
||||
std::thread proxy([&](){
|
||||
std::thread proxy([&]() {
|
||||
httplib::Server HTTPProxy;
|
||||
httplib::Headers headers = {
|
||||
{"User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch()},
|
||||
{"Accept", "*/*"}
|
||||
{ "User-Agent", "BeamMP-Launcher/" + GetVer() + GetPatch() },
|
||||
{ "Accept", "*/*" }
|
||||
};
|
||||
std::string pattern = "/:any1";
|
||||
for (int i = 2; i <= 4; i++) {
|
||||
HTTPProxy.Get(pattern, [&](const httplib::Request &req, httplib::Response &res) {
|
||||
HTTPProxy.Get(pattern, [&](const httplib::Request& req, httplib::Response& res) {
|
||||
httplib::Client cli("https://backend.beammp.com");
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
@@ -359,7 +376,7 @@ void StartProxy() {
|
||||
}
|
||||
});
|
||||
|
||||
HTTPProxy.Post(pattern, [&](const httplib::Request &req, httplib::Response &res) {
|
||||
HTTPProxy.Post(pattern, [&](const httplib::Request& req, httplib::Response& res) {
|
||||
httplib::Client cli("https://backend.beammp.com");
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
@@ -369,7 +386,8 @@ void StartProxy() {
|
||||
headers.emplace("X-API-Version", req.get_header_value("X-API-Version"));
|
||||
}
|
||||
if (auto cli_res = cli.Post(req.path, headers, req.body,
|
||||
req.get_header_value("Content-Type")); cli_res) {
|
||||
req.get_header_value("Content-Type"));
|
||||
cli_res) {
|
||||
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type"));
|
||||
} else {
|
||||
res.set_content(to_string(cli_res.error()), "text/plain");
|
||||
|
||||
Reference in New Issue
Block a user