Compare commits

..

23 Commits

Author SHA1 Message Date
Lion Kortlepel 573bd77bbd v2.0.3 2021-04-06 12:50:39 +02:00
Lion Kortlepel 770e03e3c6 update lionkor/commandline to include build speedup 2021-04-06 11:25:16 +02:00
Lion Kortlepel 11d4522dc7 update lionkor/commandline to fix windows build 2021-04-05 23:27:32 +02:00
Lion Kortlepel 830bc47987 update lionkor/commandline
Fixes the 100% CPU spin issue when stdin was /dev/null or similar.
Thanks to @Worty for implementing this fix
2021-04-05 14:47:26 +02:00
Lion Kortlepel bec698fbdc temporary fix for timeout during sync 2021-04-04 02:57:25 +02:00
Lion Kortlepel 60cc835daf remove random 2 second sleep on every car sync (!) 2021-04-04 02:26:51 +02:00
Lion Kortlepel a85ce18589 Implement possible ghost player fix
coauthor @Anonymous-275
2021-04-04 01:44:40 +02:00
Lion Kortlepel 1228c2fabe fix release build to not include "Release" in the title, it leads to a
redundant <title>
2021-03-31 20:00:40 +02:00
Anonymous-275 3da0af37e4 V2.0.2 2021-03-31 20:56:08 +03:00
Anonymous-275 baa41dd65a Timeout set to 30 secs 2021-03-31 20:19:19 +03:00
Anonymous-275 534b457f48 Possible ghost connection ellimination 2021-03-31 20:15:42 +03:00
Anonymous-275 029cf94e68 UnicycleID reset 2021-03-31 19:58:02 +03:00
Anonymous-275 15f7a6ba85 Unicycle edit check 2021-03-31 19:49:52 +03:00
Anonymous-275 86b5d91579 Try to fix max car limit 2021-03-31 19:31:45 +03:00
Anonymous-275 31486bcb56 Car limit fix 2021-03-31 19:27:05 +03:00
Anonymous-275 08660d83dc Unicycle bypass vehicle limit 2021-03-31 19:18:32 +03:00
Anonymous-275 6d8f75a577 Queue on player list update 2021-03-31 17:51:38 +03:00
Lion Kortlepel 018246cea5 fix deadlock in GetCarData, SetCarData 2021-03-31 14:50:49 +02:00
Lion Kortlepel a584e25bf3 fix deadlock in DeleteCar 2021-03-31 14:44:50 +02:00
Lion Kortlepel d4d773b769 revert copy-fix, it broke mutex locked contexts 2021-03-31 12:15:26 +02:00
Lion Kortlepel 56a02f0215 fix vehicle copy on GetAllCars, TSetOfVehicleData is now vector<> 2021-03-31 12:12:01 +02:00
Anonymous-275 7231c69e10 Lock when accessing vehicles 2021-03-31 12:42:29 +03:00
Lion 3c68dfaeaf Update LICENSE 2021-03-31 01:31:06 +02:00
13 changed files with 128 additions and 68 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
body: |
+1 -1
View File
@@ -1 +1 @@
Copyright (c) 2019-present Anonymous275. BeamMP Server 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, the only permission that has been granted is to use the software in its compiled form as distributed from the BeamMP.com website. Anything else is prohibited. Modified works may not be published and have be upstreamed to the official repository.
Copyright (c) 2019-present Anonymous275 (@Anonymous-275), Lion Kortlepel (@lionkor). BeamMP-Server code is not in the public domain and is not free software. One must be granted explicit permission by the copyright holder(s) in order to modify or distribute any part of the source or binaries. Special permission to modify the source-code is implicitly granted only for the purpose of upstreaming those changes directly to github.com/BeamMP/BeamMP-Server via a GitHub pull-request.
+12 -6
View File
@@ -14,10 +14,10 @@ class TServer;
class TClient final {
public:
using TSetOfVehicleData = std::unordered_set<TVehicleData>;
using TSetOfVehicleData = std::vector<TVehicleData>;
struct TVehicleDataLockPair {
TSetOfVehicleData& VehicleData;
TSetOfVehicleData* VehicleData;
std::unique_lock<std::mutex> Lock;
};
@@ -36,6 +36,7 @@ public:
void SetDownSock(SOCKET CSock) { mSocket[1] = CSock; }
void SetTCPSock(SOCKET CSock) { mSocket[0] = CSock; }
void SetStatus(int Status) { mStatus = Status; }
// locks
void DeleteCar(int Ident);
[[nodiscard]] std::set<std::string> GetIdentifiers() const { return mIdentifiers; }
[[nodiscard]] sockaddr_in GetUDPAddr() const { return mUDPAddress; }
@@ -43,12 +44,14 @@ public:
[[nodiscard]] SOCKET GetTCPSock() const { return mSocket[0]; }
[[nodiscard]] std::string GetRoles() const { return mRole; }
[[nodiscard]] std::string GetName() const { return mName; }
void SetUnicycleID(int ID) { mUnicycleID = ID; }
void SetID(int ID) { mID = ID; }
[[nodiscard]] int GetOpenCarID() const;
[[nodiscard]] int GetCarCount() const;
void ClearCars();
[[nodiscard]] int GetStatus() const { return mStatus; }
[[nodiscard]] int GetID() const { return mID; }
[[nodiscard]] int GetUnicycleID() const { return mUnicycleID; }
[[nodiscard]] bool IsConnected() const { return mIsConnected; }
[[nodiscard]] bool IsSynced() const { return mIsSynced; }
[[nodiscard]] bool IsSyncing() const { return mIsSyncing; }
@@ -57,9 +60,9 @@ public:
void SetIsSynced(bool NewIsSynced) { mIsSynced = NewIsSynced; }
void SetIsSyncing(bool NewIsSyncing) { mIsSyncing = NewIsSyncing; }
void EnqueuePacket(const std::string& Packet);
[[nodiscard]] std::queue<std::string>& MissedPacketQueue() { return mMissedPacketsDuringSyncing; }
[[nodiscard]] const std::queue<std::string>& MissedPacketQueue() const { return mMissedPacketsDuringSyncing; }
[[nodiscard]] size_t MissedPacketQueueSize() const { return mMissedPacketsDuringSyncing.size(); }
[[nodiscard]] std::queue<std::string>& MissedPacketQueue() { return mPacketsSync; }
[[nodiscard]] const std::queue<std::string>& MissedPacketQueue() const { return mPacketsSync; }
[[nodiscard]] size_t MissedPacketQueueSize() const { return mPacketsSync.size(); }
[[nodiscard]] std::mutex& MissedPacketQueueMutex() const { return mMissedPacketsMutex; }
void SetIsConnected(bool NewIsConnected) { mIsConnected = NewIsConnected; }
[[nodiscard]] TServer& Server() const;
@@ -67,12 +70,14 @@ public:
int SecondsSinceLastPing();
private:
void InsertVehicle(int ID, const std::string& Data);
TServer& mServer;
bool mIsConnected = false;
bool mIsSynced = false;
bool mIsSyncing = false;
mutable std::mutex mMissedPacketsMutex;
std::queue<std::string> mMissedPacketsDuringSyncing;
std::queue<std::string> mPacketsSync;
std::set<std::string> mIdentifiers;
bool mIsGuest = false;
std::mutex mVehicleDataMutex;
@@ -80,6 +85,7 @@ private:
std::string mName = "Unknown Client";
SOCKET mSocket[2] { SOCKET(-1) };
sockaddr_in mUDPAddress {}; // is this initialization OK? yes it is
int mUnicycleID = -1;
std::string mRole;
std::string mDID;
int mStatus = 0;
+1 -1
View File
@@ -42,7 +42,7 @@ public:
// Causes all threads to finish up and exit gracefull gracefully
static void GracefullyShutdown();
static TConsole& Console() { return *mConsole; }
static std::string ServerVersion() { return "2.0.1"; }
static std::string ServerVersion() { return "2.0.3"; }
static std::string ClientVersion() { return "2.0"; }
static std::string PPS() { return mPPS; }
static void SetPPS(std::string NewPPS) { mPPS = NewPPS; }
+1 -1
View File
@@ -44,6 +44,6 @@ private:
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr, bool kicked);
void Parse(TClient& c, const std::string& Packet);
void SendFile(TClient& c, const std::string& Name);
static bool TCPSendRaw(SOCKET C, char* Data, int32_t Size);
static bool TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size);
static void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name);
};
+2
View File
@@ -31,5 +31,7 @@ private:
TClientSet mClients;
mutable RWMutex mClientsMutex;
static void ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network);
static bool ShouldSpawn(TClient& c, const std::string& CarJson, int ID);
static bool IsUnicycle(TClient& c, const std::string& CarJson);
static void Apply(TClient& c, int VID, const std::string& pckt);
};
+7 -2
View File
@@ -6,20 +6,25 @@ class TVehicleData final {
public:
TVehicleData(int ID, std::string Data);
~TVehicleData();
// We cannot delete this, since vector needs to be able to copy when it resizes.
// Deleting this causes some wacky template errors which are hard to decipher,
// and end up making no sense, so let's just leave the copy ctor.
// TVehicleData(const TVehicleData&) = delete;
[[nodiscard]] bool IsInvalid() const { return mID == -1; }
[[nodiscard]] int ID() const { return mID; }
[[nodiscard]] std::string Data() const { return mData; }
void SetData(const std::string& Data) const { mData = Data; }
void SetData(const std::string& Data) { mData = Data; }
bool operator==(const TVehicleData& v) const { return mID == v.mID; }
private:
int mID { -1 };
mutable std::string mData;
std::string mData;
};
// TODO: unused now, remove?
namespace std {
template <>
struct hash<TVehicleData> {
+28 -17
View File
@@ -6,15 +6,19 @@
// FIXME: add debug prints
void TClient::DeleteCar(int Ident) {
for (auto& v : mVehicleData) {
if (v.ID() == Ident) {
mVehicleData.erase(v);
break;
}
std::unique_lock lock(mVehicleDataMutex);
auto iter = std::find_if(mVehicleData.begin(), mVehicleData.end(), [&](auto& elem) {
return Ident == elem.ID();
});
if (iter != mVehicleData.end()) {
mVehicleData.erase(iter);
} else {
debug("tried to erase a vehicle that doesn't exist (not an error)");
}
}
void TClient::ClearCars() {
std::unique_lock lock(mVehicleDataMutex);
mVehicleData.clear();
}
@@ -34,30 +38,37 @@ int TClient::GetOpenCarID() const {
}
void TClient::AddNewCar(int Ident, const std::string& Data) {
mVehicleData.emplace(Ident, Data);
std::unique_lock lock(mVehicleDataMutex);
mVehicleData.emplace_back(Ident, Data);
}
TClient::TVehicleDataLockPair TClient::GetAllCars() {
return { mVehicleData, std::unique_lock(mVehicleDataMutex) };
return { &mVehicleData, std::unique_lock(mVehicleDataMutex) };
}
std::string TClient::GetCarData(int Ident) {
for (auto& v : mVehicleData) {
if (v.ID() == Ident) {
return v.Data();
{ // lock
std::unique_lock lock(mVehicleDataMutex);
for (auto& v : mVehicleData) {
if (v.ID() == Ident) {
return v.Data();
}
}
}
} // unlock
DeleteCar(Ident);
return "";
}
void TClient::SetCarData(int Ident, const std::string& Data) {
for (auto& v : mVehicleData) {
if (v.ID() == Ident) {
v.SetData(Data);
return;
{ // lock
std::unique_lock lock(mVehicleDataMutex);
for (auto& v : mVehicleData) {
if (v.ID() == Ident) {
v.SetData(Data);
return;
}
}
}
} // unlock
DeleteCar(Ident);
}
@@ -71,7 +82,7 @@ TServer& TClient::Server() const {
void TClient::EnqueuePacket(const std::string& Packet) {
std::unique_lock Lock(mMissedPacketsMutex);
mMissedPacketsDuringSyncing.push(Packet);
mPacketsSync.push(Packet);
}
TClient::TClient(TServer& Server)
+1 -1
View File
@@ -342,7 +342,7 @@ int lua_GetCars(lua_State* L) {
TClient::TSetOfVehicleData VehicleData;
{ // Vehicle Data Lock Scope
auto LockedData = Client->GetAllCars();
VehicleData = LockedData.VehicleData;
VehicleData = *LockedData.VehicleData;
} // End Vehicle Data Lock Scope
if (VehicleData.empty())
return 0;
+28 -24
View File
@@ -88,11 +88,11 @@ void TNetwork::UDPServerMain() {
ReadLock Lock(mServer.GetClientMutex());
if (!ClientPtr.expired()) {
Client = ClientPtr.lock();
}else return true;
} else
return true;
}
if (Client->GetID() == ID) {
Client->UpdatePingTime();
Client->SetUDPAddr(client);
Client->SetIsConnected(true);
TServer::GlobalParser(ClientPtr, Data.substr(2), mPPSMonitor, *this);
@@ -312,7 +312,8 @@ void TNetwork::Authentication(SOCKET TCPSock) {
ReadLock Lock(mServer.GetClientMutex());
if (!ClientPtr.expired()) {
Cl = ClientPtr.lock();
} else return true;
} else
return true;
}
info("Client Iteration: Name -> " + Cl->GetName() + ", Guest -> " + std::to_string(Cl->IsGuest()) + ", Roles -> " + Cl->GetRoles());
if (Cl->GetName() == Client->GetName() && Cl->IsGuest() == Client->IsGuest()) {
@@ -354,8 +355,7 @@ std::shared_ptr<TClient> TNetwork::CreateClient(SOCKET TCPSock) {
bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) {
if (!IsSync) {
if (c.IsSyncing()) {
//std::unique_lock Lock(c.MissedPacketQueueMutex());
if(!Data.empty()) {
if (!Data.empty()) {
if (Data.at(0) == 'O' || Data.at(0) == 'A' || Data.at(0) == 'C' || Data.at(0) == 'E') {
c.EnqueuePacket(Data);
}
@@ -364,7 +364,6 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) {
}
}
int32_t Size, Sent;
std::string Send(4, 0);
Size = int32_t(Data.size());
@@ -391,6 +390,7 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) {
return false;
}
Sent += Temp;
c.UpdatePingTime();
} while (Sent < Size);
return true;
}
@@ -488,8 +488,8 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) {
c.SetStatus(-2);
CloseSocketProper(c.GetTCPSock());
}
void TNetwork::Looper(const std::weak_ptr<TClient>& c){
while(!c.expired()) {
void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
while (!c.expired()) {
auto Client = c.lock();
if (Client->GetStatus() < 0) {
debug("client status < 0, breaking client loop");
@@ -521,7 +521,7 @@ void TNetwork::Looper(const std::weak_ptr<TClient>& c){
break;
}
}
}else{
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
@@ -535,7 +535,7 @@ void TNetwork::TCPClient(const std::weak_ptr<TClient>& c) {
OnConnect(c);
RegisterThread("(" + std::to_string(c.lock()->GetID()) + ") \"" + c.lock()->GetName() + "\"");
std::thread QueueSync(&TNetwork::Looper, this ,c);
std::thread QueueSync(&TNetwork::Looper, this, c);
while (true) {
if (c.expired())
@@ -553,7 +553,8 @@ void TNetwork::TCPClient(const std::weak_ptr<TClient>& c) {
}
TServer::GlobalParser(c, res, mPPSMonitor, *this);
}
if(QueueSync.joinable())QueueSync.join();
if (QueueSync.joinable())
QueueSync.join();
if (!c.expired()) {
auto Client = c.lock();
@@ -574,7 +575,8 @@ void TNetwork::UpdatePlayer(TClient& Client) {
return true;
});
Packet = Packet.substr(0, Packet.length() - 1);
(void)Respond(Client, Packet, true);
Client.EnqueuePacket(Packet);
//(void)Respond(Client, Packet, true);
}
void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr, bool kicked) {
@@ -586,7 +588,7 @@ void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr, bool kicked
TClient::TSetOfVehicleData VehicleData;
{ // Vehicle Data Lock Scope
auto LockedData = c.GetAllCars();
VehicleData = LockedData.VehicleData;
VehicleData = *LockedData.VehicleData;
} // End Vehicle Data Lock Scope
for (auto& v : VehicleData) {
Packet = "Od:" + std::to_string(c.GetID()) + "-" + std::to_string(v.ID());
@@ -755,7 +757,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
if (Diff > Split) {
f.seekg(Sent, std::ios_base::beg);
f.read(Data, Split);
if (!TCPSendRaw(TCPSock, Data, Split)) {
if (!TCPSendRaw(c, TCPSock, Data, Split)) {
if (c.GetStatus() > -1)
c.SetStatus(-1);
break;
@@ -764,7 +766,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
} else {
f.seekg(Sent, std::ios_base::beg);
f.read(Data, Diff);
if (!TCPSendRaw(TCPSock, Data, int32_t(Diff))) {
if (!TCPSendRaw(c, TCPSock, Data, int32_t(Diff))) {
if (c.GetStatus() > -1)
c.SetStatus(-1);
break;
@@ -776,16 +778,17 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
f.close();
}
bool TNetwork::TCPSendRaw(SOCKET C, char* Data, int32_t Size) {
bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) {
intmax_t Sent = 0;
do {
intmax_t Temp = send(C, &Data[Sent], int(Size - Sent), 0);
intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0);
if (Temp < 1) {
info("Socket Closed! " + std::to_string(C));
CloseSocketProper(C);
info("Socket Closed! " + std::to_string(socket));
CloseSocketProper(socket);
return false;
}
Sent += Temp;
C.UpdatePingTime();
} while (Sent < Size);
return true;
}
@@ -836,12 +839,13 @@ bool TNetwork::SyncClient(const std::weak_ptr<TClient>& c) {
ReadLock Lock(mServer.GetClientMutex());
if (!ClientPtr.expired()) {
client = ClientPtr.lock();
} else return true;
} else
return true;
}
TClient::TSetOfVehicleData VehicleData;
{ // Vehicle Data Lock Scope
auto LockedData = client->GetAllCars();
VehicleData = LockedData.VehicleData;
VehicleData = *LockedData.VehicleData;
} // End Vehicle Data Lock Scope
if (client != LockedClient) {
for (auto& v : VehicleData) {
@@ -851,7 +855,6 @@ bool TNetwork::SyncClient(const std::weak_ptr<TClient>& c) {
return false;
}
res = Respond(*LockedClient, v.Data(), true, true);
std::this_thread::sleep_for(std::chrono::seconds(2));
}
}
@@ -877,7 +880,8 @@ void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Re
ReadLock Lock(mServer.GetClientMutex());
if (!ClientPtr.expired()) {
Client = ClientPtr.lock();
}else return true;
} else
return true;
}
if (Self || Client.get() != c) {
if (Client->IsSynced() || Client->IsSyncing()) {
@@ -886,7 +890,7 @@ void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Re
if (Data.length() > 400) {
std::string CMP(Comp(Data));
Client->EnqueuePacket("ABG:" + CMP);
}else{
} else {
Client->EnqueuePacket(Data);
}
//ret = SendLarge(*Client, Data);
+4 -6
View File
@@ -36,17 +36,15 @@ void TPPSMonitor::operator()() {
ReadLock Lock(mServer.GetClientMutex());
if (!ClientPtr.expired()) {
c = ClientPtr.lock();
} else return true;
} else
return true;
}
if (c->GetCarCount() > 0) {
C++;
V += c->GetCarCount();
}
if (!c->IsSynced() || c->IsSyncing()) {
c->UpdatePingTime();
}
// kick on "no ping"
if (c->SecondsSinceLastPing() > 60 && c->IsSynced() && !c->IsSyncing()) {
if (c->SecondsSinceLastPing() > (5 * 60)) {
debug("client " + std::string("(") + std::to_string(c->GetID()) + ")" + c->GetName() + " timing out: " + std::to_string(c->SecondsSinceLastPing()) + ", pps: " + Application::PPS());
TimedOutClients.push_back(c);
}
@@ -54,7 +52,7 @@ void TPPSMonitor::operator()() {
return true;
});
for (auto& ClientToKick : TimedOutClients) {
Network().ClientKick(*ClientToKick, "Timeout (no ping for >60 seconds)");
Network().ClientKick(*ClientToKick, "Timeout (no ping for >5 min)");
}
TimedOutClients.clear();
if (C == 0 || mInternalPPS == 0) {
+41 -7
View File
@@ -108,7 +108,6 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::string Pac
} else {
Network.UpdatePlayer(*LockedClient);
}
LockedClient->UpdatePingTime();
return;
case 'O':
if (Packet.length() > 1000) {
@@ -164,6 +163,29 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) {
a++;
}
}
bool TServer::IsUnicycle(TClient &c, const std::string &CarJson) {
rapidjson::Document Car;
Car.Parse(CarJson.c_str(), CarJson.size());
if(Car.HasParseError()){
error("Failed to parse vehicle data -> " + CarJson);
} else if (Car["jbm"].IsString() && std::string(Car["jbm"].GetString()) == "unicycle") {
return true;
}
return false;
}
bool TServer::ShouldSpawn(TClient& c, const std::string& CarJson, int ID) {
if(c.GetUnicycleID() > -1 && (c.GetCarCount() - 1) < Application::Settings.MaxCars){
return true;
}
if(IsUnicycle(c,CarJson)){
c.SetUnicycleID(ID);
return true;
}
return Application::Settings.MaxCars > c.GetCarCount();
}
void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network) {
if (Pckt.length() < 4)
@@ -181,9 +203,15 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
if (Data.at(0) == '0') {
int CarID = c.GetOpenCarID();
debug(c.GetName() + (" created a car with ID ") + std::to_string(CarID));
Packet = "Os:" + c.GetRoles() + ":" + c.GetName() + ":" + std::to_string(c.GetID()) + "-" + std::to_string(CarID) + Packet.substr(4);
std::string CarJson = Packet.substr(5);
Packet = "Os:" + c.GetRoles() + ":" + c.GetName() + ":" + std::to_string(c.GetID()) + "-" + std::to_string(CarID) + ":" + CarJson;
auto Res = TriggerLuaEvent(("onVehicleSpawn"), false, nullptr, std::make_unique<TLuaArg>(TLuaArg { { c.GetID(), CarID, Packet.substr(3) } }), true);
if (c.GetCarCount() >= Application::Settings.MaxCars || std::any_cast<int>(Res)) {
if (ShouldSpawn(c, CarJson, CarID) && std::any_cast<int>(Res) == 0) {
c.AddNewCar(CarID, Packet);
Network.SendToAll(nullptr, Packet, true, true);
} else {
if (!Network.Respond(c, Packet, true)) {
// TODO: handle
}
@@ -192,9 +220,6 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
// TODO: handle
}
debug(c.GetName() + (" (force : car limit/lua) removed ID ") + std::to_string(CarID));
} else {
c.AddNewCar(CarID, Packet);
Network.SendToAll(nullptr, Packet, true, true);
}
}
return;
@@ -212,10 +237,15 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
auto Res = TriggerLuaEvent(("onVehicleEdited"), false, nullptr,
std::make_unique<TLuaArg>(TLuaArg { { c.GetID(), VID, Packet.substr(3) } }),
true);
if (!std::any_cast<int>(Res)) {
if ((c.GetUnicycleID() != VID || IsUnicycle(c,Packet.substr(Packet.find('{'))))
&& std::any_cast<int>(Res) == 0) {
Network.SendToAll(&c, Packet, false, true);
Apply(c, VID, Packet);
} else {
if(c.GetUnicycleID() == VID){
c.SetUnicycleID(-1);
}
std::string Destroy = "Od:" + std::to_string(c.GetID()) + "-" + std::to_string(VID);
if (!Network.Respond(c, Destroy, true)) {
// TODO: handle
@@ -235,6 +265,9 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
VID = stoi(vid);
}
if (PID != -1 && VID != -1 && PID == c.GetID()) {
if(c.GetUnicycleID() == VID){
c.SetUnicycleID(-1);
}
Network.SendToAll(nullptr, Packet, true, true);
TriggerLuaEvent(("onVehicleDeleted"), false, nullptr,
std::make_unique<TLuaArg>(TLuaArg { { c.GetID(), VID } }), false);
@@ -280,6 +313,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
void TServer::Apply(TClient& c, int VID, const std::string& pckt) {
std::string Packet = pckt.substr(pckt.find('{')), VD = c.GetCarData(VID);
std::string Header = VD.substr(0, VD.find('{'));
VD = VD.substr(VD.find('{'));
rapidjson::Document Veh, Pack;
Veh.Parse(VD.c_str());