mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2026-07-24 07:30:37 +00:00
Merge branch 'linux'
This commit is contained in:
+5
-2
@@ -8,6 +8,9 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <zlib.h>
|
||||
#ifdef __linux__
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#define Biggest 30000
|
||||
std::string Comp(std::string Data){
|
||||
@@ -27,7 +30,7 @@ std::string Comp(std::string Data){
|
||||
deflateEnd(&defstream);
|
||||
int TO = defstream.total_out;
|
||||
std::string Ret(TO,0);
|
||||
memcpy_s(&Ret[0],TO,C,TO);
|
||||
memcpy(&Ret[0],C,TO);
|
||||
delete [] C;
|
||||
return Ret;
|
||||
}
|
||||
@@ -48,7 +51,7 @@ std::string DeComp(std::string Compressed){
|
||||
inflateEnd(&infstream);
|
||||
int TO = infstream.total_out;
|
||||
std::string Ret(TO,0);
|
||||
memcpy_s(&Ret[0],TO,C,TO);
|
||||
memcpy(&Ret[0],C,TO);
|
||||
delete [] C;
|
||||
return Ret;
|
||||
}
|
||||
+58
-58
@@ -1,58 +1,58 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 2/23/2021
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Network/network.h"
|
||||
#include <filesystem>
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include <cstdint>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string Branch;
|
||||
void ParseConfig(const nlohmann::json& d){
|
||||
if(d["Port"].is_number()){
|
||||
DEFAULT_PORT = d["Port"].get<int>();
|
||||
}
|
||||
//Default -1
|
||||
//Release 1
|
||||
//EA 2
|
||||
//Dev 3
|
||||
//Custom 3
|
||||
|
||||
if(d["Build"].is_string()){
|
||||
Branch = d["Build"].get<std::string>();
|
||||
for(char& c : Branch)c = char(tolower(c));
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInit(){
|
||||
if(fs::exists("Launcher.cfg")){
|
||||
std::ifstream cfg("Launcher.cfg");
|
||||
if(cfg.is_open()){
|
||||
auto Size = fs::file_size("Launcher.cfg");
|
||||
std::string Buffer(Size, 0);
|
||||
cfg.read(&Buffer[0], Size);
|
||||
cfg.close();
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
if(d.is_discarded()){
|
||||
fatal("Config failed to parse make sure it's valid JSON!");
|
||||
}
|
||||
ParseConfig(d);
|
||||
}else fatal("Failed to open Launcher.cfg!");
|
||||
}else{
|
||||
std::ofstream cfg("Launcher.cfg");
|
||||
if(cfg.is_open()){
|
||||
cfg <<
|
||||
R"({
|
||||
"Port": 4444,
|
||||
"Build": "Default"
|
||||
})";
|
||||
cfg.close();
|
||||
}else{
|
||||
fatal("Failed to write config on disk!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Created by Anonymous275 on 2/23/2021
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Network/network.hpp"
|
||||
#include <filesystem>
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include <cstdint>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string Branch;
|
||||
void ParseConfig(const nlohmann::json& d){
|
||||
if(d["Port"].is_number()){
|
||||
DEFAULT_PORT = d["Port"].get<int>();
|
||||
}
|
||||
//Default -1
|
||||
//Release 1
|
||||
//EA 2
|
||||
//Dev 3
|
||||
//Custom 3
|
||||
|
||||
if(d["Build"].is_string()){
|
||||
Branch = d["Build"].get<std::string>();
|
||||
for(char& c : Branch)c = char(tolower(c));
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigInit(){
|
||||
if(fs::exists("Launcher.cfg")){
|
||||
std::ifstream cfg("Launcher.cfg");
|
||||
if(cfg.is_open()){
|
||||
auto Size = fs::file_size("Launcher.cfg");
|
||||
std::string Buffer(Size, 0);
|
||||
cfg.read(&Buffer[0], Size);
|
||||
cfg.close();
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
if(d.is_discarded()){
|
||||
fatal("Config failed to parse make sure it's valid JSON!");
|
||||
}
|
||||
ParseConfig(d);
|
||||
}else fatal("Failed to open Launcher.cfg!");
|
||||
}else{
|
||||
std::ofstream cfg("Launcher.cfg");
|
||||
if(cfg.is_open()){
|
||||
cfg <<
|
||||
R"({
|
||||
"Port": 4444,
|
||||
"Build": "Default"
|
||||
})";
|
||||
cfg.close();
|
||||
}else{
|
||||
fatal("Failed to write config on disk!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+67
-1
@@ -6,13 +6,26 @@
|
||||
/// Created by Anonymous275 on 7/19/2020
|
||||
///
|
||||
|
||||
#include <Security/Init.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__)
|
||||
#include "vdf_parser.hpp"
|
||||
#include <pwd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <spawn.h>
|
||||
#endif
|
||||
|
||||
#include <Security/Init.h>
|
||||
#include <filesystem>
|
||||
#include "Startup.h"
|
||||
#include "Logger.h"
|
||||
#include <thread>
|
||||
|
||||
unsigned long GamePID = 0;
|
||||
#if defined(_WIN32)
|
||||
std::string QueryKey(HKEY hKey,int ID);
|
||||
std::string GetGamePath(){
|
||||
static std::string Path;
|
||||
@@ -40,7 +53,21 @@ std::string GetGamePath(){
|
||||
Path += Ver + "\\";
|
||||
return Path;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
std::string GetGamePath(){
|
||||
// Right now only steam is supported
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
std::string homeDir = pw->pw_dir;
|
||||
|
||||
std::string Path = homeDir + "/.local/share/BeamNG.drive/";
|
||||
std::string Ver = CheckVer(GetGameDir());
|
||||
Ver = Ver.substr(0,Ver.find('.',Ver.find('.')+1));
|
||||
Path += Ver + "/";
|
||||
return Path;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
void StartGame(std::string Dir){
|
||||
BOOL bSuccess = FALSE;
|
||||
PROCESS_INFORMATION pi;
|
||||
@@ -61,6 +88,45 @@ void StartGame(std::string Dir){
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
exit(2);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
void StartGame(std::string Dir) {
|
||||
int status;
|
||||
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
|
||||
char *argv[] = {filename.data(), NULL};
|
||||
pid_t pid;
|
||||
int result = posix_spawn(&pid, filename.c_str(), NULL, NULL, argv, environ);
|
||||
|
||||
if (result != 0) {
|
||||
error("Failed to Launch the game! launcher closing soon");
|
||||
return;
|
||||
} else {
|
||||
waitpid(pid, &status, 0);
|
||||
error("Game Closed! launcher closing soon");
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
exit(2);
|
||||
}
|
||||
#endif
|
||||
void StartGame(std::string Dir) {
|
||||
int status;
|
||||
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
|
||||
char *argv[] = {filename.data(), NULL};
|
||||
pid_t pid;
|
||||
int result = posix_spawn(&pid, filename.c_str(), NULL, NULL, argv, environ);
|
||||
|
||||
if (result != 0) {
|
||||
error("Failed to Launch the game! launcher closing soon");
|
||||
return;
|
||||
} else {
|
||||
waitpid(pid, &status, 0);
|
||||
error("Game Closed! launcher closing soon");
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
exit(2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void InitGame(const std::string& Dir){
|
||||
if(!Dev){
|
||||
|
||||
+35
-12
@@ -5,13 +5,22 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/20/2020
|
||||
///
|
||||
|
||||
#include "Network/network.h"
|
||||
#include "Network/network.hpp"
|
||||
#include "Security/Init.h"
|
||||
#include <regex>
|
||||
#include "Http.h"
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#elif defined(__linux__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "Startup.h"
|
||||
#include "Logger.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
@@ -207,13 +216,18 @@ void localRes(){
|
||||
}
|
||||
void CoreMain() {
|
||||
debug("Core Network on start!");
|
||||
WSADATA wsaData;
|
||||
SOCKET LSocket,CSocket;
|
||||
struct addrinfo *res = nullptr;
|
||||
struct addrinfo hints{};
|
||||
int iRes = WSAStartup(514, &wsaData); //2.2
|
||||
int iRes;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
iRes = WSAStartup(514, &wsaData); //2.2
|
||||
if (iRes)debug("WSAStartup failed with error: " + std::to_string(iRes));
|
||||
#endif
|
||||
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
@@ -261,6 +275,8 @@ void CoreMain() {
|
||||
KillSocket(LSocket);
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
int Handle(EXCEPTION_POINTERS *ep){
|
||||
char* hex = new char[100];
|
||||
sprintf_s(hex,100, "%lX", ep->ExceptionRecord->ExceptionCode);
|
||||
@@ -268,17 +284,24 @@ int Handle(EXCEPTION_POINTERS *ep){
|
||||
delete [] hex;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[noreturn]] void CoreNetwork(){
|
||||
while(true) {
|
||||
#ifndef __MINGW32__
|
||||
__try{
|
||||
#endif
|
||||
CoreMain();
|
||||
#ifndef __MINGW32__
|
||||
}__except(Handle(GetExceptionInformation())){}
|
||||
#endif
|
||||
#if not defined(__MINGW32__)
|
||||
__try{
|
||||
#endif
|
||||
|
||||
CoreMain();
|
||||
|
||||
#if not defined(__MINGW32__) and not defined(__linux__)
|
||||
}__except(Handle(GetExceptionInformation())){}
|
||||
#elif not defined(__MINGW32__) and defined(__linux__)
|
||||
} catch(...){
|
||||
except("(Core) Code : " + std::string(strerror(errno)));
|
||||
}
|
||||
#endif
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -7,18 +7,29 @@
|
||||
///
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#elif defined(__linux__)
|
||||
#include "linuxfixes.h"
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
std::string GetAddr(const std::string&IP){
|
||||
if(IP.find_first_not_of("0123456789.") == -1)return IP;
|
||||
WSADATA wsaData;
|
||||
hostent *host;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
if(WSAStartup(514, &wsaData) != 0){
|
||||
error("WSA Startup Failed!");
|
||||
WSACleanup();
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
host = gethostbyname(IP.c_str());
|
||||
if(!host){
|
||||
error("DNS lookup failed! on " + IP);
|
||||
|
||||
@@ -5,9 +5,20 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/25/2020
|
||||
///
|
||||
#include "Network/network.h"
|
||||
#include "Network/network.hpp"
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(__linux__)
|
||||
#include "linuxfixes.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include "Logger.h"
|
||||
#include <charconv>
|
||||
#include <string>
|
||||
@@ -117,12 +128,16 @@ SOCKET SetupListener(){
|
||||
if(GSocket != -1)return GSocket;
|
||||
struct addrinfo *result = nullptr;
|
||||
struct addrinfo hints{};
|
||||
int iRes;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
int iRes = WSAStartup(514, &wsaData); //2.2
|
||||
iRes = WSAStartup(514, &wsaData); //2.2
|
||||
if (iRes != 0) {
|
||||
error("(Proxy) WSAStartup failed with error: " + std::to_string(iRes));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
@@ -6,8 +6,19 @@
|
||||
/// Created by Anonymous275 on 4/11/2020
|
||||
///
|
||||
|
||||
#include "Network/network.h"
|
||||
#include "Network/network.hpp"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
#include "Startup.h"
|
||||
#include "Logger.h"
|
||||
@@ -38,7 +49,12 @@ std::vector<std::string> Split(const std::string& String,const std::string& deli
|
||||
|
||||
void CheckForDir(){
|
||||
if(!fs::exists("Resources")){
|
||||
// Could we just use fs::create_directory instead?
|
||||
#if defined(_WIN32)
|
||||
_wmkdir(L"Resources");
|
||||
#elif defined(__linux__)
|
||||
fs::create_directory(L"Resources");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void WaitForConfirm(){
|
||||
@@ -202,10 +218,10 @@ std::string MultiDownload(SOCKET MSock,SOCKET DSock, uint64_t Size, const std::s
|
||||
|
||||
///omg yes very ugly my god but i was in a rush will revisit
|
||||
std::string Ret(Size,0);
|
||||
memcpy_s(&Ret[0],MSize,MData,MSize);
|
||||
memcpy(&Ret[0],MData,MSize);
|
||||
delete[]MData;
|
||||
|
||||
memcpy_s(&Ret[MSize],DSize,DData,DSize);
|
||||
memcpy(&Ret[MSize],DData,DSize);
|
||||
delete[]DData;
|
||||
|
||||
return Ret;
|
||||
@@ -268,9 +284,21 @@ void SyncResources(SOCKET Sock){
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
}
|
||||
auto name = GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/'));
|
||||
#if defined(__linux__)
|
||||
// Linux version of the game doesnt support uppercase letters in mod names
|
||||
for(char &c : name){
|
||||
c = ::tolower(c);
|
||||
}
|
||||
#endif
|
||||
auto tmp_name = name + ".tmp";
|
||||
fs::copy_file(a,tmp_name,fs::copy_options::overwrite_existing);
|
||||
fs::rename(tmp_name, name);
|
||||
for(char &c : FName){
|
||||
c = ::tolower(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
fs::copy_file(a, GetGamePath() + "mods/multiplayer" + FName,
|
||||
} catch (std::exception& e) {
|
||||
error("Failed copy to the mods folder! " + std::string(e.what()));
|
||||
Terminate = true;
|
||||
@@ -310,6 +338,14 @@ void SyncResources(SOCKET Sock){
|
||||
if(!fs::exists(GetGamePath() + "mods/multiplayer")){
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
}
|
||||
|
||||
// Linux version of the game doesnt support uppercase letters in mod names
|
||||
#if defined(__linux__)
|
||||
for(char &c : FName){
|
||||
c = ::tolower(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
fs::copy_file(a,GetGamePath() + "mods/multiplayer" + FName, fs::copy_options::overwrite_existing);
|
||||
}
|
||||
WaitForConfirm();
|
||||
|
||||
@@ -6,9 +6,20 @@
|
||||
/// Created by Anonymous275 on 5/8/2020
|
||||
///
|
||||
#include "Zlib/Compressor.h"
|
||||
#include "Network/network.h"
|
||||
#include "Network/network.hpp"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "linuxfixes.h"
|
||||
#endif
|
||||
|
||||
#include "Logger.h"
|
||||
#include <string>
|
||||
#include <set>
|
||||
@@ -44,7 +55,11 @@ void UDPParser(std::string Packet){
|
||||
}
|
||||
void UDPRcv(){
|
||||
sockaddr_in FromServer{};
|
||||
#if defined(_WIN32)
|
||||
int clientLength = sizeof(FromServer);
|
||||
#elif defined(__linux__)
|
||||
socklen_t clientLength = sizeof(FromServer);
|
||||
#endif
|
||||
ZeroMemory(&FromServer, clientLength);
|
||||
std::string Ret(10240,0);
|
||||
if(UDPSock == -1)return;
|
||||
@@ -53,11 +68,14 @@ void UDPRcv(){
|
||||
UDPParser(Ret.substr(0,Rcv));
|
||||
}
|
||||
void UDPClientMain(const std::string& IP,int Port){
|
||||
#ifdef _WIN32
|
||||
WSADATA data;
|
||||
if (WSAStartup(514, &data)){
|
||||
error("Can't start Winsock!");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete ToServer;
|
||||
ToServer = new sockaddr_in;
|
||||
ToServer->sin_family = AF_INET;
|
||||
|
||||
@@ -10,11 +10,20 @@
|
||||
#include <vector>
|
||||
#include "Logger.h"
|
||||
#include <iostream>
|
||||
#include <ws2tcpip.h>
|
||||
#include <Zlib/Compressor.h>
|
||||
|
||||
#include "Network/network.h"
|
||||
#if defined(_WIN32)
|
||||
#include <ws2tcpip.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "Network/network.hpp"
|
||||
|
||||
int LastPort;
|
||||
std::string LastIP;
|
||||
@@ -116,10 +125,12 @@ std::string TCPRcv(SOCKET Sock){
|
||||
void TCPClientMain(const std::string& IP,int Port){
|
||||
LastIP = IP;
|
||||
LastPort = Port;
|
||||
WSADATA wsaData;
|
||||
SOCKADDR_IN ServerAddr;
|
||||
int RetCode;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
WSAStartup(514, &wsaData); //2.2
|
||||
#endif
|
||||
TCPSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(TCPSock == -1){
|
||||
@@ -127,6 +138,7 @@ void TCPClientMain(const std::string& IP,int Port){
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
ServerAddr.sin_family = AF_INET;
|
||||
ServerAddr.sin_port = htons(Port);
|
||||
inet_pton(AF_INET, IP.c_str(), &ServerAddr.sin_addr);
|
||||
@@ -152,6 +164,9 @@ void TCPClientMain(const std::string& IP,int Port){
|
||||
if(KillSocket(TCPSock) != 0)
|
||||
debug("(TCP) Cannot close socket. Error code: " + std::to_string(WSAGetLastError()));
|
||||
|
||||
#ifdef _WIN32
|
||||
if(WSACleanup() != 0)
|
||||
debug("(TCP) Client: WSACleanup() failed!...");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,14 @@
|
||||
///
|
||||
|
||||
#include <filesystem>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__)
|
||||
#include "vdf_parser.hpp"
|
||||
#include <vector>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@@ -46,8 +53,13 @@ void SteamExit(int code){
|
||||
}*/
|
||||
std::string GetGameDir(){
|
||||
//if(TraceBack != 4)Exit(0);
|
||||
#if defined(_WIN32)
|
||||
return GameDir.substr(0,GameDir.find_last_of('\\'));
|
||||
#elif defined(__linux__)
|
||||
return GameDir.substr(0,GameDir.find_last_of('/'));
|
||||
#endif
|
||||
}
|
||||
#ifdef _WIN32
|
||||
LONG OpenKey(HKEY root,const char* path,PHKEY hKey){
|
||||
return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey);
|
||||
}
|
||||
@@ -129,6 +141,8 @@ std::string QueryKey(HKEY hKey,int ID){
|
||||
delete [] buffer;
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
bool NameValid(const std::string& N){
|
||||
@@ -286,6 +300,7 @@ void LegitimacyCheck(){
|
||||
}else lowExit(2);
|
||||
K2.clear();
|
||||
RegCloseKey(hKey);*/
|
||||
#if defined(_WIN32)
|
||||
std::string Result;
|
||||
std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
|
||||
HKEY hKey;
|
||||
@@ -301,9 +316,27 @@ void LegitimacyCheck(){
|
||||
Result.clear();
|
||||
RegCloseKey(hKey);
|
||||
//if(TraceBack < 3)exit(-1);
|
||||
#elif defined(__linux__)
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
std::string homeDir = pw->pw_dir;
|
||||
// Right now only steam is supported
|
||||
std::ifstream libraryFolders(homeDir + "/.steam/root/steamapps/libraryfolders.vdf");
|
||||
auto root = tyti::vdf::read(libraryFolders);
|
||||
|
||||
for (auto folderInfo: root.childs){
|
||||
if (std::filesystem::exists(folderInfo.second->attribs["path"] + "/steamapps/common/BeamNG.drive/")){
|
||||
GameDir = folderInfo.second->attribs["path"] + "/steamapps/common/BeamNG.drive/";
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
std::string CheckVer(const std::string &dir){
|
||||
#if defined(_WIN32)
|
||||
std::string temp,Path = dir + "\\integrity.json";
|
||||
#elif defined(__linux__)
|
||||
std::string temp,Path = dir + "/integrity.json";
|
||||
#endif
|
||||
std::ifstream f(Path.c_str(), std::ios::binary);
|
||||
int Size = int(std::filesystem::file_size(Path));
|
||||
std::string vec(Size,0);
|
||||
|
||||
+141
-141
@@ -1,141 +1,141 @@
|
||||
// Copyright (c) 2019-present Anonymous275.
|
||||
// BeamMP Launcher code is not in the public domain and is not free software.
|
||||
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
|
||||
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
|
||||
///
|
||||
/// Created by Anonymous275 on 11/26/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Http.h"
|
||||
#include <filesystem>
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::string PublicKey;
|
||||
std::string PrivateKey;
|
||||
extern bool LoginAuth;
|
||||
extern std::string Username;
|
||||
extern std::string UserRole;
|
||||
|
||||
void UpdateKey(const char* newKey){
|
||||
if(newKey && std::isalnum(newKey[0])){
|
||||
PrivateKey = newKey;
|
||||
std::ofstream Key("key");
|
||||
if(Key.is_open()){
|
||||
Key << newKey;
|
||||
Key.close();
|
||||
}else fatal("Cannot write to disk!");
|
||||
}else if(fs::exists("key")){
|
||||
remove("key");
|
||||
}
|
||||
}
|
||||
|
||||
/// "username":"value","password":"value"
|
||||
/// "Guest":"Name"
|
||||
/// "pk":"private_key"
|
||||
|
||||
std::string GetFail(const std::string& R){
|
||||
std::string DRet = R"({"success":false,"message":)";
|
||||
DRet += "\""+R+"\"}";
|
||||
error(R);
|
||||
return DRet;
|
||||
}
|
||||
|
||||
std::string Login(const std::string& fields){
|
||||
if(fields == "LO"){
|
||||
Username = "";
|
||||
UserRole = "";
|
||||
LoginAuth = false;
|
||||
UpdateKey(nullptr);
|
||||
return "";
|
||||
}
|
||||
info("Attempting to authenticate...");
|
||||
try {
|
||||
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
|
||||
|
||||
if(Buffer == "-1"){
|
||||
return GetFail("Failed to communicate with the auth system!");
|
||||
}
|
||||
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
error(Buffer);
|
||||
return GetFail("Invalid answer from authentication servers, please try again later!");
|
||||
}
|
||||
if(d.contains("success") && d["success"].get<bool>()){
|
||||
LoginAuth = true;
|
||||
if (d.contains("username")) {
|
||||
Username = d["username"].get<std::string>();
|
||||
}
|
||||
if (d.contains("role")) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
if(d.contains("private_key")) {
|
||||
UpdateKey(d["private_key"].get<std::string>().c_str());
|
||||
}
|
||||
if(d.contains("public_key")){
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
}
|
||||
info("Authentication successful!");
|
||||
}else info("Authentication failed!");
|
||||
if(d.contains("message")){
|
||||
d.erase("private_key");
|
||||
d.erase("public_key");
|
||||
return d.dump();
|
||||
}
|
||||
return GetFail("Invalid message parsing!");
|
||||
} catch (const std::exception& e) {
|
||||
return GetFail(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void CheckLocalKey(){
|
||||
if(fs::exists("key") && fs::file_size("key") < 100){
|
||||
std::ifstream Key("key");
|
||||
if(Key.is_open()) {
|
||||
auto Size = fs::file_size("key");
|
||||
std::string Buffer(Size, 0);
|
||||
Key.read(&Buffer[0], Size);
|
||||
Key.close();
|
||||
|
||||
for (char& c : Buffer) {
|
||||
if (!std::isalnum(c) && c != '-') {
|
||||
UpdateKey(nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}");
|
||||
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer == "-1" || Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
error(Buffer);
|
||||
info("Invalid answer from authentication servers.");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
if(d["success"].get<bool>()){
|
||||
LoginAuth = true;
|
||||
UpdateKey(d["private_key"].get<std::string>().c_str());
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
if (d.contains("username")) {
|
||||
Username = d["username"].get<std::string>();
|
||||
}
|
||||
if (d.contains("role")) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
//info(Role);
|
||||
}else{
|
||||
info("Auto-Authentication unsuccessful please re-login!");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
}else{
|
||||
warn("Could not open saved key!");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
}else UpdateKey(nullptr);
|
||||
}
|
||||
// Copyright (c) 2019-present Anonymous275.
|
||||
// BeamMP Launcher code is not in the public domain and is not free software.
|
||||
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
|
||||
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
|
||||
///
|
||||
/// Created by Anonymous275 on 11/26/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Http.h"
|
||||
#include <filesystem>
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
std::string PublicKey;
|
||||
std::string PrivateKey;
|
||||
extern bool LoginAuth;
|
||||
extern std::string Username;
|
||||
extern std::string UserRole;
|
||||
|
||||
void UpdateKey(const char* newKey){
|
||||
if(newKey && std::isalnum(newKey[0])){
|
||||
PrivateKey = newKey;
|
||||
std::ofstream Key("key");
|
||||
if(Key.is_open()){
|
||||
Key << newKey;
|
||||
Key.close();
|
||||
}else fatal("Cannot write to disk!");
|
||||
}else if(fs::exists("key")){
|
||||
remove("key");
|
||||
}
|
||||
}
|
||||
|
||||
/// "username":"value","password":"value"
|
||||
/// "Guest":"Name"
|
||||
/// "pk":"private_key"
|
||||
|
||||
std::string GetFail(const std::string& R){
|
||||
std::string DRet = R"({"success":false,"message":)";
|
||||
DRet += "\""+R+"\"}";
|
||||
error(R);
|
||||
return DRet;
|
||||
}
|
||||
|
||||
std::string Login(const std::string& fields){
|
||||
if(fields == "LO"){
|
||||
Username = "";
|
||||
UserRole = "";
|
||||
LoginAuth = false;
|
||||
UpdateKey(nullptr);
|
||||
return "";
|
||||
}
|
||||
info("Attempting to authenticate...");
|
||||
try {
|
||||
std::string Buffer = HTTP::Post("https://auth.beammp.com/userlogin", fields);
|
||||
|
||||
if(Buffer == "-1"){
|
||||
return GetFail("Failed to communicate with the auth system!");
|
||||
}
|
||||
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
error(Buffer);
|
||||
return GetFail("Invalid answer from authentication servers, please try again later!");
|
||||
}
|
||||
if(d.contains("success") && d["success"].get<bool>()){
|
||||
LoginAuth = true;
|
||||
if (d.contains("username")) {
|
||||
Username = d["username"].get<std::string>();
|
||||
}
|
||||
if (d.contains("role")) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
if(d.contains("private_key")) {
|
||||
UpdateKey(d["private_key"].get<std::string>().c_str());
|
||||
}
|
||||
if(d.contains("public_key")){
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
}
|
||||
info("Authentication successful!");
|
||||
}else info("Authentication failed!");
|
||||
if(d.contains("message")){
|
||||
d.erase("private_key");
|
||||
d.erase("public_key");
|
||||
return d.dump();
|
||||
}
|
||||
return GetFail("Invalid message parsing!");
|
||||
} catch (const std::exception& e) {
|
||||
return GetFail(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void CheckLocalKey(){
|
||||
if(fs::exists("key") && fs::file_size("key") < 100){
|
||||
std::ifstream Key("key");
|
||||
if(Key.is_open()) {
|
||||
auto Size = fs::file_size("key");
|
||||
std::string Buffer(Size, 0);
|
||||
Key.read(&Buffer[0], Size);
|
||||
Key.close();
|
||||
|
||||
for (char& c : Buffer) {
|
||||
if (!std::isalnum(c) && c != '-') {
|
||||
UpdateKey(nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}");
|
||||
|
||||
nlohmann::json d = nlohmann::json::parse(Buffer, nullptr, false);
|
||||
|
||||
if (Buffer == "-1" || Buffer.at(0) != '{' || d.is_discarded()) {
|
||||
error(Buffer);
|
||||
info("Invalid answer from authentication servers.");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
if(d["success"].get<bool>()){
|
||||
LoginAuth = true;
|
||||
UpdateKey(d["private_key"].get<std::string>().c_str());
|
||||
PublicKey = d["public_key"].get<std::string>();
|
||||
if (d.contains("username")) {
|
||||
Username = d["username"].get<std::string>();
|
||||
}
|
||||
if (d.contains("role")) {
|
||||
UserRole = d["role"].get<std::string>();
|
||||
}
|
||||
//info(Role);
|
||||
}else{
|
||||
info("Auto-Authentication unsuccessful please re-login!");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
}else{
|
||||
warn("Could not open saved key!");
|
||||
UpdateKey(nullptr);
|
||||
}
|
||||
}else UpdateKey(nullptr);
|
||||
}
|
||||
|
||||
+384
-324
@@ -1,324 +1,384 @@
|
||||
// Copyright (c) 2019-present Anonymous275.
|
||||
// BeamMP Launcher code is not in the public domain and is not free software.
|
||||
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
|
||||
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
|
||||
///
|
||||
/// Created by Anonymous275 on 7/16/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <httplib.h>
|
||||
#include "zip_file.h"
|
||||
#include <windows.h>
|
||||
#include "Network/network.h"
|
||||
#include "Security/Init.h"
|
||||
#include <filesystem>
|
||||
#include "Startup.h"
|
||||
#include "hashpp.h"
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include "Http.h"
|
||||
|
||||
|
||||
extern int TraceBack;
|
||||
bool Dev = false;
|
||||
int ProxyPort = 0;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
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));
|
||||
split.emplace_back(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);
|
||||
}
|
||||
|
||||
|
||||
std::string GetEN(){
|
||||
return "BeamMP-Launcher.exe";
|
||||
}
|
||||
std::string GetVer(){
|
||||
return "2.0";
|
||||
}
|
||||
std::string GetPatch(){
|
||||
return ".85";
|
||||
}
|
||||
|
||||
std::string GetEP(char*P){
|
||||
static std::string Ret = [&](){
|
||||
std::string path(P);
|
||||
return path.substr(0, path.find_last_of("\\/") + 1);
|
||||
} ();
|
||||
return Ret;
|
||||
}
|
||||
void ReLaunch(int argc,char*args[]){
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
}
|
||||
system("cls");
|
||||
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[]){
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
}
|
||||
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);
|
||||
}
|
||||
void CheckName(int argc,char* args[]){
|
||||
std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('\\')+1);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
URelaunch(argc, args);
|
||||
} else info("Launcher version is up to date");
|
||||
TraceBack++;
|
||||
}
|
||||
|
||||
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){
|
||||
DEFAULT_PORT = std::stoi(Port);
|
||||
warn("Running on custom port : " + std::to_string(DEFAULT_PORT));
|
||||
}
|
||||
}
|
||||
if(argc > 2)Dev = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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){
|
||||
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){
|
||||
fatal(R"(failed to create the value "Name" under HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
|
||||
return;
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
|
||||
info("Patched!");
|
||||
}
|
||||
|
||||
void InitLauncher(int argc, char* argv[]) {
|
||||
system("cls");
|
||||
SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str());
|
||||
InitLog();
|
||||
CheckName(argc, argv);
|
||||
LinuxPatch();
|
||||
CheckLocalKey();
|
||||
ConfigInit();
|
||||
CustomPort(argc, argv);
|
||||
CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
|
||||
}
|
||||
|
||||
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;
|
||||
size_t c = DirCount(fs::path(Path));
|
||||
try {
|
||||
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());
|
||||
}
|
||||
}
|
||||
} 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(){
|
||||
std::string File(GetGamePath() + "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], 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
|
||||
return;
|
||||
}
|
||||
if(d.contains("mods") && d["mods"].contains("multiplayerbeammp")){
|
||||
d["mods"]["multiplayerbeammp"]["active"] = true;
|
||||
std::ofstream ofs(File);
|
||||
if(ofs.is_open()){
|
||||
ofs << d.dump();
|
||||
ofs.close();
|
||||
}else{
|
||||
error("Failed to write " + File);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreGame(const std::string& GamePath){
|
||||
std::string GameVer = CheckVer(GamePath);
|
||||
info("Game Version : " + GameVer);
|
||||
|
||||
CheckMP(GetGamePath() + "mods/multiplayer");
|
||||
|
||||
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());
|
||||
|
||||
try {
|
||||
if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
}
|
||||
EnableMP();
|
||||
}catch(std::exception&e){
|
||||
fatal(e.what());
|
||||
}
|
||||
|
||||
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::string Target(GetGamePath() + "mods/unpacked/beammp");
|
||||
|
||||
if(fs::is_directory(Target)) {
|
||||
fs::remove_all(Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_headers(httplib::Response& res) {
|
||||
res.set_header("Access-Control-Allow-Origin", "*");
|
||||
res.set_header("Access-Control-Request-Method", "POST, OPTIONS, GET");
|
||||
res.set_header("Access-Control-Request-Headers", "X-API-Version");
|
||||
}
|
||||
|
||||
void StartProxy() {
|
||||
std::thread proxy([&](){
|
||||
httplib::Server HTTPProxy;
|
||||
httplib::Headers headers = {
|
||||
{"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) {
|
||||
httplib::Client cli("https://backend.beammp.com");
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
headers.emplace("X-API-Version", req.get_header_value("X-API-Version"));
|
||||
}
|
||||
if (auto cli_res = cli.Get(req.path, headers); 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");
|
||||
}
|
||||
});
|
||||
|
||||
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")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
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) {
|
||||
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type"));
|
||||
} else {
|
||||
res.set_content(to_string(cli_res.error()), "text/plain");
|
||||
}
|
||||
});
|
||||
pattern += "/:any" + std::to_string(i);
|
||||
}
|
||||
ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0");
|
||||
HTTPProxy.listen_after_bind();
|
||||
});
|
||||
proxy.detach();
|
||||
}
|
||||
// Copyright (c) 2019-present Anonymous275.
|
||||
// BeamMP Launcher code is not in the public domain and is not free software.
|
||||
// One must be granted explicit permission by the copyright holder in order to modify or distribute any part of the source or binaries.
|
||||
// Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
|
||||
///
|
||||
/// Created by Anonymous275 on 7/16/2020
|
||||
///
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <httplib.h>
|
||||
#include "zip_file.h"
|
||||
#include <string>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "Network/network.hpp"
|
||||
#include "Security/Init.h"
|
||||
#include <filesystem>
|
||||
#include "Startup.h"
|
||||
#include "hashpp.h"
|
||||
#include "Logger.h"
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include "Http.h"
|
||||
|
||||
|
||||
extern int TraceBack;
|
||||
bool Dev = false;
|
||||
int ProxyPort = 0;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
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));
|
||||
split.emplace_back(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);
|
||||
}
|
||||
|
||||
std::string GetEN(){
|
||||
#if defined(_WIN32)
|
||||
return "BeamMP-Launcher.exe";
|
||||
#elif defined(__linux__)
|
||||
return "BeamMP-Launcher";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetVer(){
|
||||
return "2.0";
|
||||
}
|
||||
std::string GetPatch(){
|
||||
return ".85";
|
||||
}
|
||||
|
||||
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[]){
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
}
|
||||
system("cls");
|
||||
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[]){
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
}
|
||||
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[]){
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
Arg += " ";
|
||||
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[]){
|
||||
std::string Arg;
|
||||
for(int c = 2; c <= argc; c++){
|
||||
Arg += " ";
|
||||
Arg += args[c-1];
|
||||
}
|
||||
execl((GetEP() + GetEN()).c_str(), Arg.c_str(), NULL);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
exit(1);
|
||||
}
|
||||
#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);
|
||||
std::rename(FN.c_str(), DN.c_str());
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
URelaunch(argc, args);
|
||||
} else info("Launcher version is up to date");
|
||||
TraceBack++;
|
||||
}
|
||||
|
||||
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){
|
||||
DEFAULT_PORT = std::stoi(Port);
|
||||
warn("Running on custom port : " + std::to_string(DEFAULT_PORT));
|
||||
}
|
||||
}
|
||||
if(argc > 2)Dev = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
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;
|
||||
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){
|
||||
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){
|
||||
fatal(R"(failed to create the value "Name" under HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
|
||||
return;
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
|
||||
info("Patched!");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
void InitLauncher(int argc, char* argv[]) {
|
||||
system("cls");
|
||||
SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str());
|
||||
InitLog();
|
||||
CheckName(argc, argv);
|
||||
LinuxPatch();
|
||||
CheckLocalKey();
|
||||
ConfigInit();
|
||||
CustomPort(argc, argv);
|
||||
CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
void InitLauncher(int argc, char* argv[]) {
|
||||
system("clear");
|
||||
InitLog();
|
||||
CheckName(argc, argv);
|
||||
CheckLocalKey();
|
||||
ConfigInit();
|
||||
CustomPort(argc, argv);
|
||||
CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
size_t c = DirCount(fs::path(Path));
|
||||
try {
|
||||
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());
|
||||
}
|
||||
}
|
||||
} 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(){
|
||||
std::string File(GetGamePath() + "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], 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
|
||||
return;
|
||||
}
|
||||
if(d.contains("mods") && d["mods"].contains("multiplayerbeammp")){
|
||||
d["mods"]["multiplayerbeammp"]["active"] = true;
|
||||
std::ofstream ofs(File);
|
||||
if(ofs.is_open()){
|
||||
ofs << d.dump();
|
||||
ofs.close();
|
||||
}else{
|
||||
error("Failed to write " + File);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreGame(const std::string& GamePath){
|
||||
std::string GameVer = CheckVer(GamePath);
|
||||
info("Game Version : " + GameVer);
|
||||
|
||||
CheckMP(GetGamePath() + "mods/multiplayer");
|
||||
|
||||
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());
|
||||
|
||||
try {
|
||||
if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
|
||||
fs::create_directories(GetGamePath() + "mods/multiplayer");
|
||||
}
|
||||
EnableMP();
|
||||
}catch(std::exception&e){
|
||||
fatal(e.what());
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
|
||||
#elif defined(__linux__)
|
||||
// Linux version of the game cant handle mods with uppercase names
|
||||
std::string ZipPath(GetGamePath() + R"(mods/multiplayer/beammp.zip)");
|
||||
#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);
|
||||
}
|
||||
|
||||
std::string Target(GetGamePath() + "mods/unpacked/beammp");
|
||||
|
||||
if(fs::is_directory(Target)) {
|
||||
fs::remove_all(Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_headers(httplib::Response& res) {
|
||||
res.set_header("Access-Control-Allow-Origin", "*");
|
||||
res.set_header("Access-Control-Request-Method", "POST, OPTIONS, GET");
|
||||
res.set_header("Access-Control-Request-Headers", "X-API-Version");
|
||||
}
|
||||
|
||||
void StartProxy() {
|
||||
std::thread proxy([&](){
|
||||
httplib::Server HTTPProxy;
|
||||
httplib::Headers headers = {
|
||||
{"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) {
|
||||
httplib::Client cli("https://backend.beammp.com");
|
||||
set_headers(res);
|
||||
if (req.has_header("X-BMP-Authentication")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
headers.emplace("X-API-Version", req.get_header_value("X-API-Version"));
|
||||
}
|
||||
if (auto cli_res = cli.Get(req.path, headers); 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");
|
||||
}
|
||||
});
|
||||
|
||||
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")) {
|
||||
headers.emplace("X-BMP-Authentication", PrivateKey);
|
||||
}
|
||||
if (req.has_header("X-API-Version")) {
|
||||
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) {
|
||||
res.set_content(cli_res->body, cli_res->get_header_value("Content-Type"));
|
||||
} else {
|
||||
res.set_content(to_string(cli_res.error()), "text/plain");
|
||||
}
|
||||
});
|
||||
pattern += "/:any" + std::to_string(i);
|
||||
}
|
||||
ProxyPort = HTTPProxy.bind_to_any_port("0.0.0.0");
|
||||
HTTPProxy.listen_after_bind();
|
||||
});
|
||||
proxy.detach();
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/16/2020
|
||||
///
|
||||
#include "Network/network.h"
|
||||
#include "Network/network.hpp"
|
||||
#include "Security/Init.h"
|
||||
#include "Startup.h"
|
||||
#include <iostream>
|
||||
|
||||
Reference in New Issue
Block a user