mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2025-07-02 16:06:35 +00:00
Major rewrite, speed, and stability improvements
This commit is contained in:
parent
4a3235f445
commit
422e94f833
@ -21,8 +21,8 @@ extern bool TCPTerminate;
|
||||
extern bool MPDEV;
|
||||
|
||||
void StartSync(const std::string &Data){
|
||||
std::thread t1(ProxyThread,Data.substr(1,Data.find(':')-1),std::stoi(Data.substr(Data.find(':')+1)));
|
||||
//std::thread t1(ProxyThread,"127.0.0.1",30814);
|
||||
//std::thread t1(ProxyThread,Data.substr(1,Data.find(':')-1),std::stoi(Data.substr(Data.find(':')+1)));
|
||||
std::thread t1(ProxyThread,"127.0.0.1",30814);
|
||||
t1.detach();
|
||||
}
|
||||
|
||||
|
@ -26,17 +26,28 @@ void DeleteKey(){
|
||||
RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS, &hKey);
|
||||
RegDeleteValueA(hKey, TEXT("userpath_override"));
|
||||
}
|
||||
void RollBack(const std::string&Val){
|
||||
std::this_thread::sleep_for(std::chrono::seconds(7));
|
||||
void RollBack(const std::string&Val,int T){
|
||||
std::this_thread::sleep_for(std::chrono::seconds(T));
|
||||
if(!Val.empty())Write(Val);
|
||||
else DeleteKey();
|
||||
}
|
||||
void StartGame(const std::string&ExeDir,const std::string&Current){
|
||||
std::cout << "Game Launched!\n";
|
||||
std::thread RB(RollBack,Write(Current));
|
||||
RB.detach();
|
||||
SystemExec(ExeDir + " -nocrashreport");
|
||||
std::cout << "\nGame Closed! launcher closing in 5 secs\n";
|
||||
BOOL bSuccess = FALSE;
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si = {0};
|
||||
si.cb = sizeof(si);
|
||||
std::string BaseDir = ExeDir.substr(0,ExeDir.find_last_of('\\'));
|
||||
bSuccess = CreateProcessA(ExeDir.c_str(), nullptr, nullptr, nullptr, TRUE, 0, nullptr, BaseDir.c_str(), &si, &pi);
|
||||
if (bSuccess)
|
||||
{
|
||||
std::cout << "Game Launched!\n";
|
||||
DWORD dwPid = pi.dwProcessId; //Gets the PID
|
||||
std::thread RB(RollBack,Write(Current),7);
|
||||
RB.detach();
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
std::cout << "\nGame Closed! launcher closing in 5 secs\n";
|
||||
}else std::cout << "\nFailed to Launch the game! launcher closing in 5 secs\n";
|
||||
RollBack(Write(Current),0);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
exit(2);
|
||||
}
|
@ -12,7 +12,6 @@
|
||||
#include <vector>
|
||||
|
||||
int ClientID = -1;
|
||||
|
||||
extern int DEFAULT_PORT;
|
||||
std::chrono::time_point<std::chrono::steady_clock> PingStart,PingEnd;
|
||||
extern std::vector<std::string> GlobalInfo;
|
||||
@ -36,20 +35,19 @@ void GameSend(const std::string&Data){
|
||||
//std::cout << "(Launcher->Game) Bytes sent: " << iSendResult << " : " << Data << std::endl;
|
||||
}
|
||||
}
|
||||
void TCPSendLarge(const std::string&Data);
|
||||
void SendLarge(const std::string&Data);
|
||||
void TCPSend(const std::string&Data);
|
||||
void UDPSend(const std::string&Data);
|
||||
void ServerSend(const std::string&Data, bool Rel){
|
||||
if(Terminate || Data.empty())return;
|
||||
char C = 0;
|
||||
bool Ack = false;
|
||||
if(Data.length() > 3)C = Data.at(0);
|
||||
if (C == 'O' || C == 'T')Rel = true;
|
||||
|
||||
if(Rel){
|
||||
if(Data.length() > 1000 || Data.substr(0,2) == "Od")TCPSendLarge(Data);
|
||||
if (C == 'O' || C == 'T')Ack = true;
|
||||
if(Ack || Rel){
|
||||
if(Ack || Data.length() > 1000)SendLarge(Data);
|
||||
else TCPSend(Data);
|
||||
}
|
||||
else UDPSend(Data);
|
||||
}else UDPSend(Data);
|
||||
|
||||
if (MPDEV && Data.length() > 1000) {
|
||||
std::cout << "(Launcher->Server) Bytes sent: " << Data.length()
|
||||
|
@ -6,16 +6,29 @@
|
||||
#include <WS2tcpip.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <set>
|
||||
|
||||
extern bool Terminate;
|
||||
extern int ClientID;
|
||||
extern bool MPDEV;
|
||||
SOCKET UDPSock;
|
||||
sockaddr_in ToServer{};
|
||||
struct PacketData{
|
||||
int ID;
|
||||
std::string Data;
|
||||
int Tries;
|
||||
};
|
||||
|
||||
std::set<std::pair<int,std::string>> BigDataAcks;
|
||||
struct SplitData{
|
||||
int Total;
|
||||
int ID;
|
||||
std::set<std::pair<int,std::string>> Fragments;
|
||||
};
|
||||
|
||||
std::set<SplitData*> SplitPackets;
|
||||
std::set<PacketData*> BigDataAcks;
|
||||
void UDPSend(const std::string&Data){
|
||||
if(ClientID == -1 || UDPSock == INVALID_SOCKET)return;
|
||||
std::string Packet = char(ClientID+1) + std::string(":") + Data;
|
||||
@ -25,42 +38,132 @@ void UDPSend(const std::string&Data){
|
||||
|
||||
void LOOP(){
|
||||
while(UDPSock != -1) {
|
||||
for (const std::pair<int, std::string>& a : BigDataAcks) {
|
||||
UDPSend(a.second);
|
||||
for (PacketData* p : BigDataAcks) {
|
||||
if(p->Tries < 20){
|
||||
p->Tries++;
|
||||
UDPSend(p->Data);
|
||||
}else{
|
||||
BigDataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
|
||||
void AckID(int ID){
|
||||
for(const std::pair<int,std::string>& a : BigDataAcks){
|
||||
if(a.first == ID){
|
||||
BigDataAcks.erase(a);
|
||||
for(PacketData* p : BigDataAcks){
|
||||
if(p->ID == ID){
|
||||
BigDataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TCPSendLarge(const std::string&Data){
|
||||
static int ID = 0;
|
||||
std::string Header = "BD:" + std::to_string(ID) + ":";
|
||||
BigDataAcks.insert(std::make_pair(ID,Header+Data));
|
||||
if(ID > 483647)ID = 0;
|
||||
int PacktID(){
|
||||
static int ID = -1;
|
||||
if(ID > 999999)ID = 0;
|
||||
else ID++;
|
||||
return ID;
|
||||
}
|
||||
int SplitID(){
|
||||
static int SID = -1;
|
||||
if(SID > 999999)SID = 0;
|
||||
else SID++;
|
||||
return SID;
|
||||
}
|
||||
void SendLarge(const std::string&Data){
|
||||
int ID = PacktID();
|
||||
std::string Packet;
|
||||
if(Data.length() > 1000){
|
||||
std::string pckt = Data;
|
||||
int S = 1,Split = ceil(float(pckt.length()) / 1000);
|
||||
int SID = SplitID();
|
||||
while(pckt.length() > 1000){
|
||||
Packet = "SC"+std::to_string(S)+"/"+std::to_string(Split)+":"+std::to_string(ID)+"|"+
|
||||
std::to_string(SID)+":"+pckt.substr(0,1000);
|
||||
BigDataAcks.insert(new PacketData{ID,Packet,1});
|
||||
UDPSend(Packet);
|
||||
pckt = pckt.substr(1000);
|
||||
S++;
|
||||
ID = PacktID();
|
||||
}
|
||||
Packet = "SC"+std::to_string(S)+"/"+std::to_string(Split)+":"+
|
||||
std::to_string(ID)+"|"+std::to_string(SID)+":"+pckt;
|
||||
BigDataAcks.insert(new PacketData{ID,Packet,1});
|
||||
UDPSend(Packet);
|
||||
}else{
|
||||
Packet = "BD:" + std::to_string(ID) + ":" + Data;
|
||||
BigDataAcks.insert(new PacketData{ID,Packet,1});
|
||||
UDPSend(Packet);
|
||||
}
|
||||
}
|
||||
std::array<int, 50> HandledIDs;
|
||||
void IDReset(){
|
||||
for(int C = 0;C < 50;C++){
|
||||
HandledIDs.at(C) = -1;
|
||||
}
|
||||
}
|
||||
bool Handled(int ID){
|
||||
static int Pos = 0;
|
||||
for(int id : HandledIDs){
|
||||
if(id == ID)return true;
|
||||
}
|
||||
if(Pos > 49)Pos = 0;
|
||||
HandledIDs.at(Pos) = ID;
|
||||
Pos++;
|
||||
return false;
|
||||
}
|
||||
SplitData*GetSplit(int SplitID){
|
||||
for(SplitData* a : SplitPackets){
|
||||
if(a->ID == SplitID)return a;
|
||||
}
|
||||
SplitData* a = new SplitData();
|
||||
SplitPackets.insert(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
void ServerParser(const std::string& Data);
|
||||
void HandleChunk(const std::string&Data){
|
||||
int pos1 = Data.find(':')+1,pos2 = Data.find(':',pos1),pos3 = Data.find('/');
|
||||
int pos4 = Data.find('|');
|
||||
int Max = stoi(Data.substr(pos3+1,pos1-pos3-2));
|
||||
int Current = stoi(Data.substr(2,pos3-2));
|
||||
int ID = stoi(Data.substr(pos1,pos4-pos1));
|
||||
int SplitID = stoi(Data.substr(pos4+1,pos2-pos4-1));
|
||||
std::string ack = "ACK:" + Data.substr(pos1,pos4-pos1);
|
||||
UDPSend(ack);
|
||||
if(Handled(ID))return;
|
||||
SplitData* SData = GetSplit(SplitID);
|
||||
SData->Total = Max;
|
||||
SData->ID = SplitID;
|
||||
SData->Fragments.insert(std::make_pair(Current,Data.substr(pos2+1)));
|
||||
if(SData->Fragments.size() == SData->Total){
|
||||
std::string ToHandle;
|
||||
for(const std::pair<int,std::string>& a : SData->Fragments){
|
||||
ToHandle += a.second;
|
||||
}
|
||||
ServerParser(ToHandle);
|
||||
SplitPackets.erase(SData);
|
||||
}
|
||||
}
|
||||
void UDPParser(const std::string&Packet){
|
||||
if(Packet.substr(0,4) == "ACK:"){
|
||||
AckID(stoi(Packet.substr(4)));
|
||||
if(MPDEV)std::cout << "Got Ack for sending large data" << std::endl;
|
||||
if(MPDEV)std::cout << "Got Ack for data" << std::endl;
|
||||
return;
|
||||
}else if(Packet.substr(0,3) == "BD:"){
|
||||
int pos = Packet.find(':',4);
|
||||
std::string pckt = "ACK:" + Packet.substr(3,pos-3);
|
||||
int ID = stoi(Packet.substr(3,pos-3));
|
||||
std::string pckt = "ACK:" + std::to_string(ID);
|
||||
UDPSend(pckt);
|
||||
pckt = Packet.substr(pos+1);
|
||||
ServerParser(pckt);
|
||||
if(!Handled(ID)) {
|
||||
pckt = Packet.substr(pos + 1);
|
||||
ServerParser(pckt);
|
||||
}
|
||||
return;
|
||||
}else if(Packet.substr(0,2) == "SC"){
|
||||
HandleChunk(Packet);
|
||||
return;
|
||||
}
|
||||
ServerParser(Packet);
|
||||
@ -89,7 +192,6 @@ void UDPClientMain(const std::string& IP,int Port){
|
||||
std::cout << "Can't start Winsock! " << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ToServer.sin_family = AF_INET;
|
||||
ToServer.sin_port = htons(Port);
|
||||
inet_pton(AF_INET, IP.c_str(), &ToServer.sin_addr);
|
||||
@ -97,12 +199,10 @@ void UDPClientMain(const std::string& IP,int Port){
|
||||
BigDataAcks.clear();
|
||||
std::thread Ack(LOOP);
|
||||
Ack.detach();
|
||||
IDReset();
|
||||
TCPSend("P");
|
||||
UDPSend("p");
|
||||
while (!Terminate){
|
||||
UDPRcv();
|
||||
}
|
||||
|
||||
while(!Terminate)UDPRcv();
|
||||
closesocket(UDPSock);
|
||||
WSACleanup();
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <WS2tcpip.h>
|
||||
#include <thread>
|
||||
|
||||
@ -58,7 +57,7 @@ void TCPRcv(){
|
||||
ServerParser(std::string(buf));
|
||||
}
|
||||
|
||||
|
||||
void GameSend(const std::string&Data);
|
||||
void SyncResources(SOCKET TCPSock);
|
||||
void TCPClientMain(const std::string& IP,int Port){
|
||||
WSADATA wsaData;
|
||||
@ -89,11 +88,9 @@ void TCPClientMain(const std::string& IP,int Port){
|
||||
getsockname(TCPSock, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr));
|
||||
|
||||
SyncResources(TCPSock);
|
||||
while(!Terminate){
|
||||
TCPRcv();
|
||||
}
|
||||
|
||||
|
||||
while(!Terminate)TCPRcv();
|
||||
GameSend("T");
|
||||
////Game Send Terminate
|
||||
if( shutdown(TCPSock, SD_SEND) != 0 && MPDEV)
|
||||
std::cout << "(TCP) shutdown error code: " << WSAGetLastError() << std::endl;
|
||||
|
||||
|
@ -126,7 +126,7 @@ int main(int argc, char* argv[]){
|
||||
std::string GamePath = SData.at(2);
|
||||
if(MPDEV)std::cout << "You own BeamNG on this machine!" << std::endl;
|
||||
std::cout << "Game Version : " << CheckVer(GamePath) << std::endl;
|
||||
std::string ExeDir = "\""+GamePath.substr(0,GamePath.find_last_of('\\')) + R"(\Bin64\BeamNG.drive.x64.exe")";
|
||||
std::string ExeDir = GamePath.substr(0,GamePath.find_last_of('\\')) + R"(\Bin64\BeamNG.drive.x64.exe)";
|
||||
std::string Settings = Path + "\\settings\\uiapps-layouts.json";
|
||||
if(stat(Settings.c_str(),&info)!=0){
|
||||
link = "https://beamng-mp.com/client-data";
|
||||
|
Loading…
x
Reference in New Issue
Block a user