mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-04-03 14:26:15 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c03b1d5946 | ||
|
|
5e73c7bce2 | ||
|
|
386f471362 | ||
|
|
6c3bfda23b | ||
|
|
5737e27bf3 | ||
|
|
1860c0aef1 | ||
|
|
9d20b678f9 | ||
|
|
be7594039e | ||
|
|
77f3375658 | ||
|
|
ae6e5b51bf | ||
|
|
8a0f87f476 | ||
|
|
33b2030f97 | ||
|
|
5b2eb0a1a0 | ||
|
|
f27d3c6120 | ||
|
|
7a4b24d616 | ||
|
|
b6b0e4ba3e | ||
|
|
a87aa7230a | ||
|
|
b9cc025083 | ||
|
|
c0ed056440 | ||
|
|
e6e5bf8327 | ||
|
|
e7cfb6e406 | ||
|
|
185818d174 |
@@ -11,7 +11,7 @@
|
||||
#include <string>
|
||||
class HTTP {
|
||||
public:
|
||||
static bool Download(const std::string& IP, const beammp_fs_string& Path);
|
||||
static bool Download(const std::string& IP, const beammp_fs_string& Path, const std::string& Hash);
|
||||
static std::string Post(const std::string& IP, const std::string& Fields);
|
||||
static std::string Get(const std::string& IP);
|
||||
static bool ProgressBar(size_t c, size_t t);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
void InitLauncher();
|
||||
beammp_fs_string GetEP(const beammp_fs_char* P = nullptr);
|
||||
std::filesystem::path GetBP(const beammp_fs_char* P = nullptr);
|
||||
std::filesystem::path GetGamePath();
|
||||
std::string GetVer();
|
||||
std::string GetPatch();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -29,7 +30,6 @@
|
||||
#endif
|
||||
|
||||
namespace Utils {
|
||||
|
||||
inline std::vector<std::string> Split(const std::string& String, const std::string& delimiter) {
|
||||
std::vector<std::string> Val;
|
||||
size_t pos;
|
||||
@@ -109,8 +109,8 @@ namespace Utils {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
inline std::map<std::string, std::map<std::string, std::string>> ParseINI(const std::string& contents) {
|
||||
std::map<std::string, std::map<std::string, std::string>> ini;
|
||||
inline std::map<std::string, std::variant<std::map<std::string, std::string>, std::string>> ParseINI(const std::string& contents) {
|
||||
std::map<std::string, std::variant<std::map<std::string, std::string>, std::string>> ini;
|
||||
|
||||
std::string currentSection;
|
||||
auto sections = Split(contents, "\n");
|
||||
@@ -137,18 +137,19 @@ namespace Utils {
|
||||
if (line[0] == '[') {
|
||||
currentSection = line.substr(1, line.find(']') - 1);
|
||||
} else {
|
||||
|
||||
if (currentSection.empty()) {
|
||||
invalidLineLog();
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key, value;
|
||||
size_t pos = line.find('=');
|
||||
if (pos != std::string::npos) {
|
||||
key = line.substr(0, pos);
|
||||
|
||||
key = key.substr(0, key.find_last_not_of(" \t") + 1);
|
||||
|
||||
value = line.substr(pos + 1);
|
||||
ini[currentSection][key] = value;
|
||||
if (currentSection.empty()) {
|
||||
ini[key] = value;
|
||||
} else {
|
||||
std::get<std::map<std::string, std::string>>(ini[currentSection])[key] = value;
|
||||
}
|
||||
} else {
|
||||
invalidLineLog();
|
||||
continue;
|
||||
@@ -158,7 +159,7 @@ namespace Utils {
|
||||
value.erase(0, value.find_first_not_of(" \t"));
|
||||
value.erase(value.find_last_not_of(" \t") + 1);
|
||||
|
||||
ini[currentSection][key] = value;
|
||||
std::get<std::map<std::string, std::string>>(ini[currentSection])[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ namespace Utils {
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline std::wstring ToWString(const std::string& s) {
|
||||
inline std::wstring ToWString(const std::string& s) {
|
||||
if (s.empty()) return std::wstring();
|
||||
|
||||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0);
|
||||
@@ -185,7 +186,7 @@ inline std::wstring ToWString(const std::string& s) {
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
inline std::string GetSha256HashReallyFast(const beammp_fs_string& filename) {
|
||||
inline std::string GetSha256HashReallyFastFile(const beammp_fs_string& filename) {
|
||||
try {
|
||||
EVP_MD_CTX* mdctx;
|
||||
const EVP_MD* md;
|
||||
@@ -237,7 +238,51 @@ inline std::wstring ToWString(const std::string& s) {
|
||||
for (size_t i = 0; i < sha256_len; i++) {
|
||||
char buf[3];
|
||||
sprintf(buf, "%02x", sha256_value[i]);
|
||||
buf[2] = 0;
|
||||
buf[2] = '\0';
|
||||
result += buf;
|
||||
}
|
||||
return result;
|
||||
} catch (const std::exception& e) {
|
||||
error(beammp_wide("Sha256 hashing of '") + filename + beammp_wide("' failed: ") + ToWString(e.what()));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
inline std::string GetSha256HashReallyFast(const std::string& text, const beammp_fs_string& filename) {
|
||||
try {
|
||||
EVP_MD_CTX* mdctx;
|
||||
const EVP_MD* md;
|
||||
uint8_t sha256_value[EVP_MAX_MD_SIZE];
|
||||
md = EVP_sha256();
|
||||
if (md == nullptr) {
|
||||
throw std::runtime_error("EVP_sha256() failed");
|
||||
}
|
||||
|
||||
mdctx = EVP_MD_CTX_new();
|
||||
if (mdctx == nullptr) {
|
||||
throw std::runtime_error("EVP_MD_CTX_new() failed");
|
||||
}
|
||||
if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
throw std::runtime_error("EVP_DigestInit_ex2() failed");
|
||||
}
|
||||
|
||||
if (!EVP_DigestUpdate(mdctx, text.data(), text.size())) {
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
throw std::runtime_error("EVP_DigestUpdate() failed");
|
||||
}
|
||||
|
||||
unsigned int sha256_len = 0;
|
||||
if (!EVP_DigestFinal_ex(mdctx, sha256_value, &sha256_len)) {
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
throw std::runtime_error("EVP_DigestFinal_ex() failed");
|
||||
}
|
||||
EVP_MD_CTX_free(mdctx);
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < sha256_len; i++) {
|
||||
char buf[3];
|
||||
sprintf(buf, "%02x", sha256_value[i]);
|
||||
buf[2] = '\0';
|
||||
result += buf;
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -54,10 +54,10 @@ std::filesystem::path GetGamePath() {
|
||||
debug("Successfully parsed startup.ini");
|
||||
|
||||
std::wstring userPath;
|
||||
if (ini.contains("filesystem") && ini["filesystem"].contains("UserPath"))
|
||||
userPath = Utils::ToWString(ini["filesystem"]["UserPath"]);
|
||||
if (ini.contains("filesystem") && std::get<std::map<std::string, std::string>>(ini["filesystem"]).contains("UserPath"))
|
||||
userPath = Utils::ToWString(std::get<std::map<std::string, std::string>>(ini["filesystem"])["UserPath"]);
|
||||
|
||||
if (!userPath.empty())
|
||||
if (!userPath.empty() && Path.empty())
|
||||
if (userPath = Utils::ExpandEnvVars(userPath); std::filesystem::exists(userPath)) {
|
||||
Path = userPath;
|
||||
debug(L"Using custom user folder path from startup.ini: " + Path.wstring());
|
||||
@@ -66,32 +66,54 @@ std::filesystem::path GetGamePath() {
|
||||
}
|
||||
|
||||
if (Path.empty()) {
|
||||
HKEY hKey;
|
||||
LPCTSTR sk = "Software\\BeamNG\\BeamNG.drive";
|
||||
LONG openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey);
|
||||
if (openRes != ERROR_SUCCESS) {
|
||||
fatal("Please launch the game at least once!");
|
||||
wchar_t* appDataPath = new wchar_t[MAX_PATH];
|
||||
HRESULT result = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataPath);
|
||||
|
||||
if (!SUCCEEDED(result)) {
|
||||
fatal("Cannot get Local Appdata directory");
|
||||
}
|
||||
|
||||
auto BeamNGAppdataPath = std::filesystem::path(appDataPath) / "BeamNG";
|
||||
|
||||
if (const auto beamngIniPath = BeamNGAppdataPath / "BeamNG.Drive.ini"; exists(beamngIniPath)) {
|
||||
if (std::ifstream beamngIni(beamngIniPath); beamngIni.is_open()) {
|
||||
std::string contents((std::istreambuf_iterator(beamngIni)), std::istreambuf_iterator<char>());
|
||||
beamngIni.close();
|
||||
|
||||
auto ini = Utils::ParseINI(contents);
|
||||
if (ini.empty())
|
||||
warn("Failed to parse BeamNG.Drive.ini");
|
||||
else
|
||||
debug("Successfully parsed BeamNG.Drive.ini");
|
||||
|
||||
std::wstring userPath;
|
||||
|
||||
if (ini.contains("userFolder")) {
|
||||
userPath = Utils::ToWString(std::get<std::string>(ini["userFolder"]));
|
||||
userPath.erase(0, userPath.find_first_not_of(L" \t"));
|
||||
|
||||
}
|
||||
|
||||
if (!userPath.empty() && Path.empty())
|
||||
if (userPath = std::filesystem::path(Utils::ExpandEnvVars(userPath)); std::filesystem::exists(userPath)) {
|
||||
Path = userPath;
|
||||
debug(L"Using custom user folder path from BeamNG.Drive.ini: " + Path.wstring());
|
||||
} else
|
||||
warn(L"Found custom user folder path (" + userPath + L") in BeamNG.Drive.ini but it doesn't exist, skipping");
|
||||
}
|
||||
}
|
||||
Path = QueryKey(hKey, 4);
|
||||
|
||||
if (Path.empty()) {
|
||||
wchar_t* appDataPath = new wchar_t[MAX_PATH];
|
||||
HRESULT result = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataPath);
|
||||
|
||||
if (!SUCCEEDED(result)) {
|
||||
fatal("Cannot get Local Appdata directory");
|
||||
}
|
||||
|
||||
Path = std::filesystem::path(appDataPath) / "BeamNG.drive";
|
||||
|
||||
delete[] appDataPath;
|
||||
Path = BeamNGAppdataPath / "BeamNG.drive";
|
||||
}
|
||||
|
||||
delete[] appDataPath;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Ver = CheckVer(GetGameDir());
|
||||
Ver = Ver.substr(0, Ver.find('.', Ver.find('.') + 1));
|
||||
Path /= Utils::ToWString(Ver);
|
||||
Path /= Utils::ToWString("current");
|
||||
return Path;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
@@ -100,10 +122,10 @@ std::filesystem::path GetGamePath() {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
std::string homeDir = pw->pw_dir;
|
||||
|
||||
std::string Path = homeDir + "/.local/share/BeamNG.drive/";
|
||||
std::string Path = homeDir + "/.local/share/BeamNG/BeamNG.drive/";
|
||||
std::string Ver = CheckVer(GetGameDir());
|
||||
Ver = Ver.substr(0, Ver.find('.', Ver.find('.') + 1));
|
||||
Path += Ver + "/";
|
||||
Path += "current/";
|
||||
return Path;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -127,7 +127,7 @@ std::string HTTP::Post(const std::string& IP, const std::string& Fields) {
|
||||
return Ret;
|
||||
}
|
||||
|
||||
bool HTTP::Download(const std::string& IP, const beammp_fs_string& Path) {
|
||||
bool HTTP::Download(const std::string& IP, const beammp_fs_string& Path, const std::string& Hash) {
|
||||
static std::mutex Lock;
|
||||
std::scoped_lock Guard(Lock);
|
||||
|
||||
@@ -139,6 +139,16 @@ bool HTTP::Download(const std::string& IP, const beammp_fs_string& Path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string RetHash = Utils::GetSha256HashReallyFast(Ret, Path);
|
||||
|
||||
debug("Return hash: " + RetHash);
|
||||
debug("Expected hash: " + Hash);
|
||||
|
||||
if (RetHash != Hash) {
|
||||
error("Downloaded file hash does not match expected hash");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream File(Path, std::ios::binary);
|
||||
if (File.is_open()) {
|
||||
File << Ret;
|
||||
|
||||
@@ -445,7 +445,7 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
|
||||
}
|
||||
auto FileName = std::filesystem::path(ModInfoIter->FileName).stem().string() + "-" + ModInfoIter->Hash.substr(0, 8) + std::filesystem::path(ModInfoIter->FileName).extension().string();
|
||||
auto PathToSaveTo = (CachingDirectory / FileName);
|
||||
if (fs::exists(PathToSaveTo) && Utils::GetSha256HashReallyFast(PathToSaveTo) == ModInfoIter->Hash) {
|
||||
if (fs::exists(PathToSaveTo) && Utils::GetSha256HashReallyFastFile(PathToSaveTo) == ModInfoIter->Hash) {
|
||||
debug("Mod '" + FileName + "' found in cache");
|
||||
UpdateUl(false, std::to_string(ModNo) + "/" + std::to_string(TotalMods) + ": " + ModInfoIter->FileName);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
@@ -476,7 +476,7 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
|
||||
WaitForConfirm();
|
||||
continue;
|
||||
} else if (auto OldCachedPath = CachingDirectory / std::filesystem::path(ModInfoIter->FileName).filename();
|
||||
fs::exists(OldCachedPath) && Utils::GetSha256HashReallyFast(OldCachedPath) == ModInfoIter->Hash) {
|
||||
fs::exists(OldCachedPath) && Utils::GetSha256HashReallyFastFile(OldCachedPath) == ModInfoIter->Hash) {
|
||||
debug("Mod '" + FileName + "' found in old cache, copying it to the new cache");
|
||||
UpdateUl(false, std::to_string(ModNo) + "/" + std::to_string(TotalMods) + ": " + ModInfoIter->FileName);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
@@ -562,7 +562,7 @@ void NewSyncResources(SOCKET Sock, const std::string& Mods, const std::vector<Mo
|
||||
Terminate = true;
|
||||
}
|
||||
|
||||
if (Utils::GetSha256HashReallyFast(PathToSaveTo) != ModInfoIter->Hash) {
|
||||
if (Utils::GetSha256HashReallyFastFile(PathToSaveTo) != ModInfoIter->Hash) {
|
||||
error(beammp_wide("Failed to write or download the entire file '") + beammp_fs_string(PathToSaveTo) + beammp_wide("' correctly (hash mismatch)"));
|
||||
Terminate = true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <filesystem>
|
||||
#if defined(_WIN32)
|
||||
#include <shlobj_core.h>
|
||||
#elif defined(__linux__)
|
||||
#include "vdf_parser.hpp"
|
||||
#include <pwd.h>
|
||||
@@ -162,24 +163,66 @@ void FileList(std::vector<std::string>& a, const std::string& Path) {
|
||||
}
|
||||
void LegitimacyCheck() {
|
||||
#if defined(_WIN32)
|
||||
std::wstring Result;
|
||||
std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
|
||||
HKEY hKey;
|
||||
LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
|
||||
if (dwRegOPenKey == ERROR_SUCCESS) {
|
||||
Result = QueryKey(hKey, 3);
|
||||
if (Result.empty()) {
|
||||
debug("Failed to QUERY key HKEY_CURRENT_USER\\Software\\BeamNG\\BeamNG.drive");
|
||||
lowExit(3);
|
||||
}
|
||||
GameDir = Result;
|
||||
} else {
|
||||
debug("Failed to OPEN key HKEY_CURRENT_USER\\Software\\BeamNG\\BeamNG.drive");
|
||||
lowExit(4);
|
||||
wchar_t* appDataPath = new wchar_t[MAX_PATH];
|
||||
HRESULT result = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataPath);
|
||||
|
||||
if (!SUCCEEDED(result)) {
|
||||
fatal("Cannot get Local Appdata directory");
|
||||
}
|
||||
K3.clear();
|
||||
Result.clear();
|
||||
RegCloseKey(hKey);
|
||||
|
||||
auto BeamNGAppdataPath = std::filesystem::path(appDataPath) / "BeamNG";
|
||||
|
||||
if (const auto beamngIniPath = BeamNGAppdataPath / "BeamNG.Drive.ini"; exists(beamngIniPath)) {
|
||||
if (std::ifstream beamngIni(beamngIniPath); beamngIni.is_open()) {
|
||||
std::string contents((std::istreambuf_iterator(beamngIni)), std::istreambuf_iterator<char>());
|
||||
beamngIni.close();
|
||||
|
||||
auto ini = Utils::ParseINI(contents);
|
||||
if (ini.empty())
|
||||
lowExit(3);
|
||||
else
|
||||
debug("Successfully parsed BeamNG.Drive.ini");
|
||||
|
||||
if (ini.contains("installPath")) {
|
||||
std::wstring installPath = Utils::ToWString(std::get<std::string>(ini["installPath"]));
|
||||
installPath.erase(0, installPath.find_first_not_of(L" \t"));
|
||||
|
||||
if (installPath = std::filesystem::path(Utils::ExpandEnvVars(installPath)); std::filesystem::exists(installPath)) {
|
||||
GameDir = installPath;
|
||||
debug(L"GameDir from BeamNG.Drive.ini: " + installPath);
|
||||
} else {
|
||||
lowExit(4);
|
||||
}
|
||||
} else {
|
||||
lowExit(5);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::wstring Result;
|
||||
|
||||
std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
|
||||
|
||||
HKEY hKey;
|
||||
|
||||
LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
|
||||
if (dwRegOPenKey == ERROR_SUCCESS) {
|
||||
Result = QueryKey(hKey, 3);
|
||||
if (Result.empty()) {
|
||||
debug("Failed to QUERY key HKEY_CURRENT_USER\\Software\\BeamNG\\BeamNG.drive");
|
||||
lowExit(6);
|
||||
}
|
||||
GameDir = Result;
|
||||
debug(L"GameDir from registry: " + Result);
|
||||
} else {
|
||||
debug("Failed to OPEN key HKEY_CURRENT_USER\\Software\\BeamNG\\BeamNG.drive");
|
||||
lowExit(7);
|
||||
}
|
||||
K3.clear();
|
||||
Result.clear();
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
delete[] appDataPath;
|
||||
#elif defined(__linux__)
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
std::filesystem::path homeDir = pw->pw_dir;
|
||||
@@ -187,6 +230,7 @@ void LegitimacyCheck() {
|
||||
// Right now only steam is supported
|
||||
std::vector<std::filesystem::path> steamappsCommonPaths = {
|
||||
".steam/root/steamapps", // default
|
||||
".steam/steam/steamapps", // Legacy Steam installations
|
||||
".var/app/com.valvesoftware.Steam/.steam/root/steamapps", // flatpak
|
||||
"snap/steam/common/.local/share/Steam/steamapps" // snap
|
||||
};
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
#if defined(_WIN32)
|
||||
#elif defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#elif defined (__APPLE__)
|
||||
#include <unistd.h>
|
||||
#include <libproc.h>
|
||||
#endif // __APPLE__
|
||||
#include "Http.h"
|
||||
#include "Logger.h"
|
||||
#include "Network/network.hpp"
|
||||
@@ -81,10 +84,10 @@ beammp_fs_string GetEN() {
|
||||
}
|
||||
|
||||
std::string GetVer() {
|
||||
return "2.5";
|
||||
return "2.6";
|
||||
}
|
||||
std::string GetPatch() {
|
||||
return ".1";
|
||||
return ".3";
|
||||
}
|
||||
|
||||
beammp_fs_string GetEP(const beammp_fs_char* P) {
|
||||
@@ -94,6 +97,34 @@ beammp_fs_string GetEP(const beammp_fs_char* P) {
|
||||
}();
|
||||
return Ret;
|
||||
}
|
||||
|
||||
fs::path GetBP(const beammp_fs_char* P) {
|
||||
fs::path fspath = {};
|
||||
#if defined(_WIN32)
|
||||
beammp_fs_char path[256];
|
||||
GetModuleFileNameW(nullptr, path, sizeof(path));
|
||||
fspath = path;
|
||||
#elif defined(__linux__)
|
||||
fspath = fs::canonical("/proc/self/exe");
|
||||
#elif defined(__APPLE__)
|
||||
pid_t pid = getpid();
|
||||
char path[PROC_PIDPATHINFO_MAXSIZE];
|
||||
// While this is fine for a raw executable,
|
||||
// an application bundle is read-only and these files
|
||||
// should instead be placed in Application Support.
|
||||
proc_pidpath(pid, path, sizeof(path));
|
||||
fspath = std::string(path);
|
||||
#else
|
||||
fspath = beammp_fs_string(P);
|
||||
#endif
|
||||
fspath = fs::weakly_canonical(fspath.string() + "/..");
|
||||
#if defined(_WIN32)
|
||||
return fspath.wstring();
|
||||
#else
|
||||
return fspath.string();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
void ReLaunch() {
|
||||
std::wstring Arg;
|
||||
@@ -103,7 +134,7 @@ void ReLaunch() {
|
||||
}
|
||||
info("Relaunch!");
|
||||
system("cls");
|
||||
ShellExecuteW(nullptr, L"runas", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
ShellExecuteW(nullptr, L"runas", (GetBP() / GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
ShowWindow(GetConsoleWindow(), 0);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
@@ -114,7 +145,7 @@ void URelaunch() {
|
||||
Arg += Utils::ToWString(options.argv[c - 1]);
|
||||
Arg += L" ";
|
||||
}
|
||||
ShellExecuteW(nullptr, L"open", (GetEP() + GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
ShellExecuteW(nullptr, L"open", (GetBP() / GetEN()).c_str(), Arg.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
ShowWindow(GetConsoleWindow(), 0);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
@@ -128,7 +159,7 @@ void ReLaunch() {
|
||||
}
|
||||
info("Relaunch!");
|
||||
system("clear");
|
||||
int ret = execv(options.executable_name.c_str(), const_cast<char**>(options.argv));
|
||||
int ret = execv((GetBP() / GetEN()).c_str(), const_cast<char**>(options.argv));
|
||||
if (ret < 0) {
|
||||
error(std::string("execv() failed with: ") + strerror(errno) + ". Failed to relaunch");
|
||||
exit(1);
|
||||
@@ -137,7 +168,7 @@ void ReLaunch() {
|
||||
exit(1);
|
||||
}
|
||||
void URelaunch() {
|
||||
int ret = execv(options.executable_name.c_str(), const_cast<char**>(options.argv));
|
||||
int ret = execv((GetBP() / GetEN()).c_str(), const_cast<char**>(options.argv));
|
||||
if (ret < 0) {
|
||||
error(std::string("execv() failed with: ") + strerror(errno) + ". Failed to relaunch");
|
||||
exit(1);
|
||||
@@ -169,9 +200,9 @@ void CheckForUpdates(const std::string& CV) {
|
||||
"https://backend.beammp.com/version/launcher?branch=" + Branch + "&pk=" + PublicKey);
|
||||
|
||||
transform(LatestHash.begin(), LatestHash.end(), LatestHash.begin(), ::tolower);
|
||||
beammp_fs_string EP(GetEP() + GetEN()), Back(GetEP() + beammp_wide("BeamMP-Launcher.back"));
|
||||
beammp_fs_string BP(GetBP() / GetEN()), Back(GetBP() / beammp_wide("BeamMP-Launcher.back"));
|
||||
|
||||
std::string FileHash = Utils::GetSha256HashReallyFast(EP);
|
||||
std::string FileHash = Utils::GetSha256HashReallyFastFile(BP);
|
||||
|
||||
if (FileHash != LatestHash && IsOutdated(Version(VersionStrToInts(GetVer() + GetPatch())), Version(VersionStrToInts(LatestVersion)))) {
|
||||
if (!options.no_update) {
|
||||
@@ -179,14 +210,21 @@ void CheckForUpdates(const std::string& CV) {
|
||||
#if defined(__linux__)
|
||||
error("Auto update is NOT implemented for the Linux version. Please update manually ASAP as updates contain security patches.");
|
||||
#else
|
||||
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);
|
||||
GetBP() / (beammp_wide("new_") + GetEN()), LatestHash);
|
||||
std::error_code ec;
|
||||
fs::remove(Back, ec);
|
||||
if (ec == std::errc::permission_denied) {
|
||||
error("Failed to remove old backup file: " + ec.message() + ". Using alternative name.");
|
||||
fs::rename(BP, Back + beammp_wide(".") + Utils::ToWString(FileHash.substr(0, 8)));
|
||||
} else {
|
||||
fs::rename(BP, Back);
|
||||
}
|
||||
fs::rename(GetBP() / (beammp_wide("new_") + GetEN()), BP);
|
||||
URelaunch();
|
||||
#endif
|
||||
} else {
|
||||
@@ -247,8 +285,8 @@ void InitLauncher() {
|
||||
}
|
||||
#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 fs::path& path) {
|
||||
return (size_t)std::distance(fs::directory_iterator { path }, fs::directory_iterator {});
|
||||
}
|
||||
|
||||
void CheckMP(const beammp_fs_string& Path) {
|
||||
@@ -329,14 +367,14 @@ void PreGame(const beammp_fs_string& GamePath) {
|
||||
std::string ZipPath(GetGamePath() / R"(mods/multiplayer/beammp.zip)");
|
||||
#endif
|
||||
|
||||
std::string FileHash = fs::exists(ZipPath) ? Utils::GetSha256HashReallyFast(ZipPath) : "";
|
||||
std::string FileHash = fs::exists(ZipPath) ? Utils::GetSha256HashReallyFastFile(ZipPath) : "";
|
||||
|
||||
if (FileHash != LatestHash) {
|
||||
info("Downloading BeamMP Update " + LatestHash);
|
||||
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
|
||||
"&pk="
|
||||
+ PublicKey + "&branch=" + Branch,
|
||||
ZipPath);
|
||||
ZipPath, LatestHash);
|
||||
}
|
||||
|
||||
beammp_fs_string Target(GetGamePath() / beammp_wide("mods/unpacked/beammp"));
|
||||
|
||||
Reference in New Issue
Block a user