mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-03 08:15:35 +00:00
Major rewrite, speed, and stability improvements
This commit is contained in:
parent
ff2d5d74ae
commit
80c3280e4e
@ -23,20 +23,21 @@ int OpenID(){
|
||||
}while (!found);
|
||||
return ID;
|
||||
}
|
||||
void TCPSendLarge(Client*c,const std::string&Data);
|
||||
void SendLarge(Client*c,const std::string&Data);
|
||||
void Respond(Client*c, const std::string& MSG, bool Rel){
|
||||
char C = MSG.at(0);
|
||||
if(Rel){
|
||||
if(MSG.length() > 1000)TCPSendLarge(c,MSG);
|
||||
if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG);
|
||||
else TCPSend(c,MSG);
|
||||
}
|
||||
else UDPSend(c,MSG);
|
||||
}else UDPSend(c,MSG);
|
||||
}
|
||||
|
||||
void SendToAll(Client*c, const std::string& Data, bool Self, bool Rel){
|
||||
char C = Data.at(0);
|
||||
for(Client*client : Clients){
|
||||
if(Self || client != c){
|
||||
if(Rel){
|
||||
if(Data.length() > 1000 || Data.substr(0,2) == "Od")TCPSendLarge(client,Data);
|
||||
if(C == 'O' || C == 'T' || Data.length() > 1000)SendLarge(client,Data);
|
||||
else TCPSend(client,Data);
|
||||
}
|
||||
else UDPSend(client,Data);
|
||||
@ -55,17 +56,15 @@ void UpdatePlayers(){
|
||||
|
||||
void OnDisconnect(Client*c,bool kicked){
|
||||
std::string Packet;
|
||||
|
||||
for(const std::pair<int,std::string>&a : c->GetAllCars()){
|
||||
Packet = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(a.first);
|
||||
SendToAll(c, Packet,false,true);
|
||||
}
|
||||
|
||||
if(kicked)Packet = "L"+c->GetName()+" was kicked!";
|
||||
Packet = "L"+c->GetName()+" Left the server!";
|
||||
SendToAll(c, Packet,false,true);
|
||||
Packet.clear();
|
||||
Clients.erase(c); ///Removes the Client from the existence
|
||||
Clients.erase(c); ///Removes the Client from existence
|
||||
}
|
||||
int TriggerLuaEvent(const std::string& Event,bool local,Lua*Caller);
|
||||
void OnConnect(Client*c){
|
||||
|
@ -14,17 +14,6 @@ void Respond(Client*c, const std::string& MSG, bool Rel);
|
||||
void UpdatePlayers();
|
||||
|
||||
|
||||
|
||||
/*void FindAndSync(Client*c,int ClientID){
|
||||
for (Client*client : Clients) {
|
||||
if (client != c){
|
||||
if(client->GetID() == ClientID){ /////mark
|
||||
Respond(client,c->GetCarData(ClientID),true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
int TriggerLuaEvent(const std::string& Event,bool local,Lua*Caller);
|
||||
void VehicleParser(Client*c, std::string Packet){
|
||||
char Code = Packet.at(1);
|
||||
@ -62,12 +51,6 @@ void VehicleParser(Client*c, std::string Packet){
|
||||
break;
|
||||
case 'm':
|
||||
break;
|
||||
/*case 'n':
|
||||
if(Packet.substr(3).find_first_not_of("0123456789") == std::string::npos){
|
||||
PID = stoi(Packet.substr(3));
|
||||
}
|
||||
FindAndSync(c,PID); //ACK System
|
||||
break;*/
|
||||
case 'r':
|
||||
SendToAll(c,Packet,false,true);
|
||||
break;
|
||||
|
@ -6,13 +6,25 @@
|
||||
#include "Client.hpp"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include "../logger.h"
|
||||
#include "../Settings.hpp"
|
||||
|
||||
SOCKET UDPSock;
|
||||
struct PacketData{
|
||||
int ID;
|
||||
Client* Client;
|
||||
std::string Data;
|
||||
int Tries;
|
||||
};
|
||||
struct SplitData{
|
||||
int Total;
|
||||
int ID;
|
||||
std::set<std::pair<int,std::string>> Fragments;
|
||||
};
|
||||
|
||||
std::set<std::tuple<int,Client*,std::string>> BigDataAcks;
|
||||
SOCKET UDPSock;
|
||||
std::set<PacketData*> DataAcks;
|
||||
std::set<SplitData*> SplitPackets;
|
||||
void UDPSend(Client*c,const std::string&Data){
|
||||
if(!c->isConnected())return;
|
||||
sockaddr_in Addr = c->GetUDPAddr();
|
||||
@ -22,22 +34,103 @@ void UDPSend(Client*c,const std::string&Data){
|
||||
}
|
||||
|
||||
void AckID(int ID){
|
||||
for(std::tuple<int,Client*,std::string> a : BigDataAcks){
|
||||
if(get<0>(a) == ID){
|
||||
BigDataAcks.erase(a);
|
||||
for(PacketData* p : DataAcks){
|
||||
if(p->ID == ID){
|
||||
DataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TCPSendLarge(Client*c,const std::string&Data){
|
||||
static int ID = 0;
|
||||
std::string Header = "BD:" + std::to_string(ID) + ":";
|
||||
BigDataAcks.insert(std::make_tuple(ID,c,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(Client*c,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);
|
||||
DataAcks.insert(new PacketData{ID,c,Packet,1});
|
||||
UDPSend(c,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;
|
||||
DataAcks.insert(new PacketData{ID,c,Packet,1});
|
||||
UDPSend(c,Packet);
|
||||
}else{
|
||||
Packet = "BD:" + std::to_string(ID) + ":" + Data;
|
||||
DataAcks.insert(new PacketData{ID,c,Packet,1});
|
||||
UDPSend(c,Packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct HandledC{
|
||||
int Pos = 0;
|
||||
Client *c;
|
||||
std::array<int, 50> HandledIDs;
|
||||
};
|
||||
std::set<HandledC*> HandledIDs;
|
||||
|
||||
void ResetIDs(HandledC*H){
|
||||
for(int C = 0;C < 50;C++){
|
||||
H->HandledIDs.at(C) = -1;
|
||||
}
|
||||
}
|
||||
HandledC*GetHandled(Client*c){
|
||||
for(HandledC*h : HandledIDs){
|
||||
if(h->c == c){
|
||||
return h;
|
||||
}
|
||||
}
|
||||
return new HandledC();
|
||||
}
|
||||
bool Handled(Client*c,int ID){
|
||||
bool handle = false;
|
||||
for(HandledC*h : HandledIDs){
|
||||
if(h->c == c){
|
||||
for(int id : h->HandledIDs){
|
||||
if(id == ID)return true;
|
||||
}
|
||||
if(h->Pos > 49)h->Pos = 0;
|
||||
h->HandledIDs.at(h->Pos) = ID;
|
||||
h->Pos++;
|
||||
handle = true;
|
||||
}
|
||||
}
|
||||
for(HandledC*h : HandledIDs){
|
||||
if(h->c == nullptr || !h->c->isConnected()){
|
||||
HandledIDs.erase(h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!handle) {
|
||||
HandledC *h = GetHandled(c);
|
||||
ResetIDs(h);
|
||||
if (h->Pos > 49)h->Pos = 0;
|
||||
h->HandledIDs.at(h->Pos) = ID;
|
||||
h->Pos++;
|
||||
h->c = c;
|
||||
HandledIDs.insert(h);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string UDPRcvFromClient(sockaddr_in& client){
|
||||
char buf[10240];
|
||||
int clientLength = sizeof(client);
|
||||
@ -52,7 +145,39 @@ std::string UDPRcvFromClient(sockaddr_in& client){
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
SplitData*GetSplit(int SplitID){
|
||||
for(SplitData* a : SplitPackets){
|
||||
if(a->ID == SplitID)return a;
|
||||
}
|
||||
SplitData* a = new SplitData();
|
||||
SplitPackets.insert(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
void GlobalParser(Client*c, const std::string&Packet);
|
||||
void HandleChunk(Client*c,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(c,ack);
|
||||
if(Handled(c,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(std::pair<int,std::string> a : SData->Fragments){
|
||||
ToHandle += a.second;
|
||||
}
|
||||
GlobalParser(c,ToHandle);
|
||||
SplitPackets.erase(SData);
|
||||
}
|
||||
}
|
||||
|
||||
void UDPParser(Client*c, const std::string&Packet){
|
||||
if(Packet.substr(0,4) == "ACK:"){
|
||||
@ -61,10 +186,16 @@ void UDPParser(Client*c, const std::string&Packet){
|
||||
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(c,pckt);
|
||||
pckt = Packet.substr(pos+1);
|
||||
GlobalParser(c,pckt);
|
||||
if(!Handled(c,ID)) {
|
||||
pckt = Packet.substr(pos + 1);
|
||||
GlobalParser(c, pckt);
|
||||
}
|
||||
return;
|
||||
}else if(Packet.substr(0,2) == "SC"){
|
||||
HandleChunk(c,Packet);
|
||||
return;
|
||||
}
|
||||
GlobalParser(c,Packet);
|
||||
@ -96,7 +227,7 @@ void StartLoop();
|
||||
//return;
|
||||
}
|
||||
|
||||
BigDataAcks.clear();
|
||||
DataAcks.clear();
|
||||
StartLoop();
|
||||
|
||||
info("Vehicle data network online on port "+std::to_string(Port)+" with a Max of "+std::to_string(MaxPlayers)+" Clients");
|
||||
@ -109,7 +240,6 @@ void StartLoop();
|
||||
/*char clientIp[256];
|
||||
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
|
||||
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/
|
||||
|
||||
uint8_t ID = Data.at(0)-1;
|
||||
for(Client*c : Clients){
|
||||
if(c->GetID() == ID){
|
||||
@ -127,14 +257,20 @@ void StartLoop();
|
||||
#include <thread>
|
||||
void LOOP(){
|
||||
while(UDPSock != -1) {
|
||||
for (std::tuple<int, Client *, std::string> a : BigDataAcks) {
|
||||
if (get<1>(a)->GetTCPSock() == -1) {
|
||||
BigDataAcks.erase(a);
|
||||
for (PacketData* p : DataAcks){
|
||||
if (p->Client == nullptr || p->Client->GetTCPSock() == -1) {
|
||||
DataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
UDPSend(get<1>(a), get<2>(a));
|
||||
if(p->Tries < 20){
|
||||
UDPSend(p->Client,p->Data);
|
||||
p->Tries++;
|
||||
}else{
|
||||
DataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
void StartLoop(){
|
||||
|
@ -15,3 +15,4 @@ extern std::string ClientVersion;
|
||||
extern std::string FileList;
|
||||
extern std::string FileSizes;
|
||||
extern std::string Key;
|
||||
extern std::string CustomIP;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "logger.h"
|
||||
using namespace std; //nameSpace STD
|
||||
|
||||
void GenerateConfig();
|
||||
string RemoveComments(const string& Line);
|
||||
void SetValues(const string& Line, int Index);
|
||||
|
@ -9,8 +9,6 @@
|
||||
#include "Settings.hpp"
|
||||
#include "Network 2.0/Client.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string HTTP_REQUEST(const std::string&,int);
|
||||
std::string PostHTTP(const std::string& IP,const std::string& Fields);
|
||||
std::string HTA(const std::string& hex)
|
||||
@ -34,6 +32,7 @@ void Heartbeat()
|
||||
R = "uuid="+Key+"&players="+to_string(Clients.size())+"&maxplayers="+to_string(MaxPlayers)+"&port="
|
||||
+ to_string(Port) + "&map=" + MapName + "&private="+State+"&version="+ServerVersion+
|
||||
"&clientversion="+ClientVersion+"&name="+ServerName;
|
||||
if(!CustomIP.empty())R+="&ip="+CustomIP;
|
||||
// https://beamng-mp.com/heartbeatv2
|
||||
R = PostHTTP(HTA("68747470733a2f2f6265616d6e672d6d702e636f6d2f6865617274626561747632"),R);
|
||||
if(R.find_first_not_of("20") != std::string::npos){
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include "curl/curl.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
@ -42,6 +40,7 @@ std::string PostHTTP(const std::string& IP,const std::string& Fields){
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
18
src/main.cpp
18
src/main.cpp
@ -8,22 +8,32 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "logger.h"
|
||||
#include <algorithm>
|
||||
#include "Settings.hpp"
|
||||
|
||||
using namespace std;
|
||||
void DebugData();
|
||||
void LogInit();
|
||||
void ParseConfig();
|
||||
void addToLog(const string& Data);
|
||||
//void ServerMain(int Port, int MaxClients);
|
||||
void HeartbeatInit();
|
||||
string ServerVersion = "0.2";
|
||||
string ClientVersion = "1.1+";
|
||||
std::string ServerVersion = "0.2";
|
||||
std::string ClientVersion = "1.1+";
|
||||
std::string CustomIP;
|
||||
void HandleResources(std::string path);
|
||||
//void TCPMain(int Port);
|
||||
void NetMain();
|
||||
//Entry
|
||||
int main() {
|
||||
int main(int argc, char* argv[]) {
|
||||
if(argc > 1){
|
||||
CustomIP = argv[1];
|
||||
size_t n = std::count(CustomIP.begin(), CustomIP.end(), '.');
|
||||
int p = CustomIP.find_first_not_of(".0123456789");
|
||||
if(p != std::string::npos || n != 3 || CustomIP.substr(0,3) == "127"){
|
||||
CustomIP.clear();
|
||||
warn("IP Specified is invalid!");
|
||||
}else info("Started with custom ip : " + CustomIP);
|
||||
}
|
||||
LogInit();
|
||||
ParseConfig();
|
||||
info("BeamMP Server Running version " + ServerVersion);
|
||||
|
Loading…
x
Reference in New Issue
Block a user