mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-03 16:25:35 +00:00
refactor client disconnect, client interation
anywhere a client is disconnected, TNetwork::Disconnect is called now. Nothing else is valid. ForEachClientWeak() was fully removed.
This commit is contained in:
parent
aa29d04b60
commit
130e1acdb3
@ -44,7 +44,6 @@ public:
|
||||
void SetIdentifier(const std::string& key, const std::string& value);
|
||||
std::string GetCarData(int Ident);
|
||||
std::string GetCarPositionRaw(int Ident);
|
||||
void Disconnect(std::string_view Reason);
|
||||
bool IsDisconnected() const { return !TCPSocket->is_open(); }
|
||||
// locks
|
||||
void DeleteCar(int Ident);
|
||||
@ -75,7 +74,12 @@ public:
|
||||
Sync<std::queue<std::vector<uint8_t>>> MissedPacketsQueue;
|
||||
Sync<std::chrono::time_point<std::chrono::high_resolution_clock>> LastPingTime;
|
||||
|
||||
friend class TNetwork;
|
||||
|
||||
private:
|
||||
/// ONLY call after the client has been cleaned up, all cars deleted, etc.
|
||||
void CloseSockets(std::string_view Reason);
|
||||
|
||||
void InsertVehicle(int ID, const std::string& Data);
|
||||
|
||||
TServer& mServer;
|
||||
|
@ -19,6 +19,9 @@ public:
|
||||
std::shared_ptr<TClient> CreateClient(ip::tcp::socket&& TCPSock);
|
||||
std::vector<uint8_t> TCPRcv(TClient& c);
|
||||
void ClientKick(TClient& c, const std::string& R);
|
||||
void Disconnect(const std::shared_ptr<TClient>& ClientPtr);
|
||||
void Disconnect(const std::weak_ptr<TClient>& ClientPtr);
|
||||
void Disconnect(TClient& Client);
|
||||
[[nodiscard]] bool SyncClient(const std::weak_ptr<TClient>& c);
|
||||
void Identify(TConnection&& client);
|
||||
std::shared_ptr<TClient> Authentication(TConnection&& ClientConnection);
|
||||
@ -43,14 +46,11 @@ private:
|
||||
void OnConnect(const std::weak_ptr<TClient>& c);
|
||||
void TCPClient(const std::weak_ptr<TClient>& c);
|
||||
void Looper(const std::weak_ptr<TClient>& c);
|
||||
void OnDisconnect(const std::shared_ptr<TClient>& ClientPtr);
|
||||
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr);
|
||||
void OnDisconnect(TClient& Client);
|
||||
void Parse(TClient& c, const std::vector<uint8_t>& Packet);
|
||||
void SendFile(TClient& c, const std::string& Name);
|
||||
static bool TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size);
|
||||
static void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name);
|
||||
static const uint8_t* SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size);
|
||||
bool TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size);
|
||||
void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name);
|
||||
const uint8_t* SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size);
|
||||
};
|
||||
|
||||
std::string HashPassword(const std::string& str);
|
||||
|
@ -24,7 +24,6 @@ public:
|
||||
void RemoveClient(const std::weak_ptr<TClient>&);
|
||||
void RemoveClient(TClient&);
|
||||
// in Fn, return true to continue, return false to break
|
||||
[[deprecated("Use ForEachClient instead")]] void ForEachClientWeak(const std::function<bool(std::weak_ptr<TClient>)>& Fn);
|
||||
void ForEachClient(const std::function<bool(const std::shared_ptr<TClient>&)> Fn);
|
||||
size_t ClientCount() const;
|
||||
|
||||
|
@ -51,17 +51,25 @@ std::string TClient::GetCarPositionRaw(int Ident) {
|
||||
}
|
||||
}
|
||||
|
||||
void TClient::Disconnect(std::string_view Reason) {
|
||||
void TClient::CloseSockets(std::string_view Reason) {
|
||||
auto LockedSocket = TCPSocket.synchronize();
|
||||
beammp_debugf("Disconnecting client {} for reason: {}", int(ID), Reason);
|
||||
boost::system::error_code ec;
|
||||
LockedSocket->shutdown(socket_base::shutdown_both, ec);
|
||||
if (ec) {
|
||||
beammp_debugf("Failed to shutdown client socket: {}", ec.message());
|
||||
beammp_debugf("Failed to shutdown client socket of client {}: {}", ID.get(), ec.message());
|
||||
}
|
||||
LockedSocket->close(ec);
|
||||
if (ec) {
|
||||
beammp_debugf("Failed to close client socket: {}", ec.message());
|
||||
beammp_debugf("Failed to close client socket of client {}: {}", ID.get(), ec.message());
|
||||
}
|
||||
DownSocket->shutdown(socket_base::shutdown_both, ec);
|
||||
if (ec) {
|
||||
beammp_debugf("Failed to shutdown client download socket of client {}: {}", ID.get(), ec.message());
|
||||
}
|
||||
DownSocket->close(ec);
|
||||
if (ec) {
|
||||
beammp_debugf("Failed to close client download socket of client {}: {}", ID.get(), ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ static inline std::pair<bool, std::string> InternalTriggerClientEvent(int Player
|
||||
auto c = MaybeClient.value();
|
||||
if (!LuaAPI::MP::Engine->Network().Respond(*c, StringToVector(Packet), true)) {
|
||||
beammp_lua_errorf("Respond failed, dropping client {}", PlayerID);
|
||||
LuaAPI::MP::Engine->Network().ClientKick(*c, "Disconnected after failing to receive packets");
|
||||
LuaAPI::MP::Engine->Network().Disconnect(*c);
|
||||
return { false, "Respond failed, dropping client" };
|
||||
}
|
||||
return { true, "" };
|
||||
@ -169,7 +169,8 @@ std::pair<bool, std::string> LuaAPI::MP::SendChatMessage(int ID, const std::stri
|
||||
LogChatMessage("<Server> (to \"" + c->Name.get() + "\")", -1, Message);
|
||||
if (!Engine->Network().Respond(*c, StringToVector(Packet), true)) {
|
||||
beammp_errorf("Failed to send chat message back to sender (id {}) - did the sender disconnect?", ID);
|
||||
// TODO: should we return an error here?
|
||||
beammp_infof("Disconnecting client {} for failure to receive a chat message (TCP disconnect)", c->Name.get());
|
||||
Engine->Network().Disconnect(c);
|
||||
}
|
||||
Result.first = true;
|
||||
} else {
|
||||
|
@ -266,15 +266,12 @@ void TConsole::Command_Kick(const std::string&, const std::vector<std::string>&
|
||||
std::for_each(Name2.begin(), Name2.end(), [](char& c) { c = char(std::tolower(char(c))); });
|
||||
return StringStartsWith(Name1, Name2) || StringStartsWith(Name2, Name1);
|
||||
};
|
||||
mLuaEngine->Server().ForEachClientWeak([&](std::weak_ptr<TClient> Client) -> bool {
|
||||
if (!Client.expired()) {
|
||||
auto locked = Client.lock();
|
||||
if (NameCompare(locked->Name.get(), Name)) {
|
||||
mLuaEngine->Network().ClientKick(*locked, Reason);
|
||||
mLuaEngine->Server().ForEachClient([&](const std::shared_ptr<TClient>& Client) -> bool {
|
||||
if (NameCompare(Client->Name.get(), Name)) {
|
||||
mLuaEngine->Network().ClientKick(*Client, Reason);
|
||||
Kicked = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!Kicked) {
|
||||
@ -364,13 +361,10 @@ void TConsole::Command_List(const std::string&, const std::vector<std::string>&
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << std::left << std::setw(25) << "Name" << std::setw(6) << "ID" << std::setw(6) << "Cars" << std::endl;
|
||||
mLuaEngine->Server().ForEachClientWeak([&](std::weak_ptr<TClient> Client) -> bool {
|
||||
if (!Client.expired()) {
|
||||
auto locked = Client.lock();
|
||||
ss << std::left << std::setw(25) << locked->Name.get()
|
||||
<< std::setw(6) << locked->ID.get()
|
||||
<< std::setw(6) << locked->GetCarCount() << "\n";
|
||||
}
|
||||
mLuaEngine->Server().ForEachClient([&](const std::shared_ptr<TClient>& Client) -> bool {
|
||||
ss << std::left << std::setw(25) << Client->Name.get()
|
||||
<< std::setw(6) << Client->ID.get()
|
||||
<< std::setw(6) << Client->GetCarCount() << "\n";
|
||||
return true;
|
||||
});
|
||||
auto Str = ss.str();
|
||||
|
@ -497,11 +497,8 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayerIdentifiers(int ID) {
|
||||
|
||||
sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() {
|
||||
sol::table Result = mStateView.create_table();
|
||||
mEngine->Server().ForEachClientWeak([&](std::weak_ptr<TClient> Client) -> bool {
|
||||
if (!Client.expired()) {
|
||||
auto locked = Client.lock();
|
||||
Result[locked->ID.get()] = locked->Name.get();
|
||||
}
|
||||
mEngine->Server().ForEachClient([&](const std::shared_ptr<TClient>& Client) -> bool {
|
||||
Result[Client->ID.get()] = Client->Name.get();
|
||||
return true;
|
||||
});
|
||||
return Result;
|
||||
@ -509,14 +506,11 @@ sol::table TLuaEngine::StateThreadData::Lua_GetPlayers() {
|
||||
|
||||
int TLuaEngine::StateThreadData::Lua_GetPlayerIDByName(const std::string& Name) {
|
||||
int Id = -1;
|
||||
mEngine->mServer->ForEachClientWeak([&Id, &Name](std::weak_ptr<TClient> Client) -> bool {
|
||||
if (!Client.expired()) {
|
||||
auto locked = Client.lock();
|
||||
if (locked->Name.get() == Name) {
|
||||
Id = locked->ID.get();
|
||||
mEngine->mServer->ForEachClient([&Id, &Name](const std::shared_ptr<TClient>& Client) -> bool {
|
||||
if (Client->Name.get() == Name) {
|
||||
Id = Client->ID.get();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return Id;
|
||||
|
@ -246,7 +246,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
|
||||
}
|
||||
|
||||
if (!TCPSend(*Client, StringToVector("A"))) { // changed to A for Accepted version
|
||||
OnDisconnect(Client);
|
||||
Disconnect(Client);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -304,7 +304,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
|
||||
|
||||
if (!Application::Settings.Password.empty()) { // ask password
|
||||
if (!TCPSend(*Client, StringToVector("S"))) {
|
||||
OnDisconnect(Client);
|
||||
Disconnect(Client);
|
||||
return {};
|
||||
}
|
||||
beammp_info("Waiting for password");
|
||||
@ -320,20 +320,11 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
|
||||
}
|
||||
|
||||
beammp_debug("Name-> " + Client->Name.get() + ", Guest-> " + std::to_string(Client->IsGuest.get()) + ", Roles-> " + Client->Role.get());
|
||||
mServer.ForEachClientWeak([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
||||
std::shared_ptr<TClient> Cl;
|
||||
{
|
||||
ReadLock Lock(mServer.GetClientMutex());
|
||||
if (!ClientPtr.expired()) {
|
||||
Cl = ClientPtr.lock();
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
mServer.ForEachClient([&](const std::shared_ptr<TClient>& Cl) -> bool {
|
||||
if (Cl->Name.get() == Client->Name.get() && Cl->IsGuest == Client->IsGuest) {
|
||||
Cl->Disconnect("Stale Client (not a real player)");
|
||||
Disconnect(Cl);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -368,7 +359,7 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
|
||||
TCPClient(Client);
|
||||
} catch (const std::exception& e) {
|
||||
beammp_infof("Client {} disconnected: {}", Client->ID.get(), e.what());
|
||||
OnDisconnect(Client);
|
||||
Disconnect(Client);
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
@ -412,7 +403,7 @@ bool TNetwork::TCPSend(TClient& c, const std::vector<uint8_t>& Data, bool IsSync
|
||||
write(*c.TCPSocket.synchronize(), buffer(ToSend), ec);
|
||||
if (ec) {
|
||||
beammp_debugf("write(): {}", ec.message());
|
||||
c.Disconnect("write() failed");
|
||||
Disconnect(c);
|
||||
return false;
|
||||
}
|
||||
c.UpdatePingTime();
|
||||
@ -477,7 +468,7 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) {
|
||||
if (!TCPSend(c, StringToVector("K" + R))) {
|
||||
beammp_debugf("tried to kick player '{}' (id {}), but was already disconnected", c.Name.get(), c.ID.get());
|
||||
}
|
||||
c.Disconnect("Kicked");
|
||||
Disconnect(c);
|
||||
}
|
||||
|
||||
void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
|
||||
@ -502,7 +493,7 @@ void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
|
||||
} // end locked context
|
||||
// beammp_debug("sending a missed packet: " + QData);
|
||||
if (!TCPSend(*Client, QData, true)) {
|
||||
Client->Disconnect("Failed to TCPSend while clearing the missed packet queue");
|
||||
Disconnect(Client);
|
||||
auto Lock = Client->MissedPacketsQueue;
|
||||
while (!Lock->empty()) {
|
||||
Lock->pop();
|
||||
@ -539,7 +530,7 @@ void TNetwork::TCPClient(const std::weak_ptr<TClient>& c) {
|
||||
auto res = TCPRcv(*Client);
|
||||
if (res.empty()) {
|
||||
beammp_debug("TCPRcv empty");
|
||||
Client->Disconnect("TCPRcv failed");
|
||||
Disconnect(Client);
|
||||
break;
|
||||
}
|
||||
mServer.GlobalParser(c, std::move(res), mPPSMonitor, *this);
|
||||
@ -550,7 +541,7 @@ void TNetwork::TCPClient(const std::weak_ptr<TClient>& c) {
|
||||
|
||||
if (!c.expired()) {
|
||||
auto Client = c.lock();
|
||||
OnDisconnect(c);
|
||||
Disconnect(c);
|
||||
return;
|
||||
} else {
|
||||
beammp_warn("client expired in TCPClient, should never happen");
|
||||
@ -569,7 +560,7 @@ void TNetwork::UpdatePlayer(TClient& Client) {
|
||||
//(void)Respond(Client, Packet, true);
|
||||
}
|
||||
|
||||
void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr) {
|
||||
void TNetwork::Disconnect(const std::weak_ptr<TClient>& ClientPtr) {
|
||||
// this is how one checks that the ClientPtr is not empty (as opposed to expired)
|
||||
if (ClientPtr.owner_before(std::weak_ptr<TClient> {})) {
|
||||
return;
|
||||
@ -578,37 +569,37 @@ void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr) {
|
||||
try {
|
||||
LockedClientPtr = ClientPtr.lock();
|
||||
} catch (const std::exception&) {
|
||||
beammp_warn("Client expired in OnDisconnect, this is unexpected");
|
||||
beammp_warn("Client expired in CloseSockets, this is unexpected");
|
||||
return;
|
||||
}
|
||||
beammp_assert(LockedClientPtr != nullptr);
|
||||
TClient& c = *LockedClientPtr;
|
||||
OnDisconnect(c);
|
||||
Disconnect(c);
|
||||
}
|
||||
void TNetwork::OnDisconnect(TClient& c) {
|
||||
beammp_info(c.Name.get() + (" Connection Terminated"));
|
||||
void TNetwork::Disconnect(TClient& Client) {
|
||||
beammp_info(Client.Name.get() + (" Connection Terminated"));
|
||||
std::string Packet;
|
||||
{
|
||||
auto Locked = c.VehicleData.synchronize();
|
||||
auto Locked = Client.VehicleData.synchronize();
|
||||
for (auto& v : *Locked) {
|
||||
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", c.ID.get(), v.ID()));
|
||||
Packet = "Od:" + std::to_string(c.ID.get()) + "-" + std::to_string(v.ID());
|
||||
SendToAll(&c, StringToVector(Packet), false, true);
|
||||
LuaAPI::MP::Engine->ReportErrors(LuaAPI::MP::Engine->TriggerEvent("onVehicleDeleted", "", Client.ID.get(), v.ID()));
|
||||
Packet = "Od:" + std::to_string(Client.ID.get()) + "-" + std::to_string(v.ID());
|
||||
SendToAll(&Client, StringToVector(Packet), false, true);
|
||||
}
|
||||
}
|
||||
Packet = ("L") + c.Name.get() + (" left the server!");
|
||||
SendToAll(&c, StringToVector(Packet), false, true);
|
||||
Packet = ("L") + Client.Name.get() + (" left the server!");
|
||||
SendToAll(&Client, StringToVector(Packet), false, true);
|
||||
Packet.clear();
|
||||
auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", c.ID.get());
|
||||
auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerDisconnect", "", Client.ID.get());
|
||||
TLuaEngine::WaitForAll(Futures);
|
||||
c.Disconnect("Already Disconnected (OnDisconnect)");
|
||||
mServer.RemoveClient(c);
|
||||
Client.CloseSockets("Normal disconnect");
|
||||
mServer.RemoveClient(Client);
|
||||
}
|
||||
void TNetwork::OnDisconnect(const std::shared_ptr<TClient>& ClientPtr) {
|
||||
void TNetwork::Disconnect(const std::shared_ptr<TClient>& ClientPtr) {
|
||||
if (ClientPtr == nullptr) {
|
||||
return;
|
||||
}
|
||||
OnDisconnect(*ClientPtr);
|
||||
Disconnect(*ClientPtr);
|
||||
}
|
||||
|
||||
void TNetwork::OnConnect(const std::weak_ptr<TClient>& c) {
|
||||
@ -674,7 +665,8 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
||||
|
||||
if (!fs::path(UnsafeName).has_filename()) {
|
||||
if (!TCPSend(c, StringToVector("CO"))) {
|
||||
OnDisconnect(c);
|
||||
Disconnect(c);
|
||||
return;
|
||||
}
|
||||
beammp_warn("File " + UnsafeName + " is not a file!");
|
||||
return;
|
||||
@ -684,14 +676,16 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
||||
|
||||
if (!std::filesystem::exists(FileName)) {
|
||||
if (!TCPSend(c, StringToVector("CO"))) {
|
||||
OnDisconnect(c);
|
||||
Disconnect(c);
|
||||
return;
|
||||
}
|
||||
beammp_warn("File " + UnsafeName + " could not be accessed!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TCPSend(c, StringToVector("AG"))) {
|
||||
OnDisconnect(c);
|
||||
Disconnect(c);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Wait for connections
|
||||
@ -704,7 +698,7 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
||||
if (!c.DownSocket->is_open()) {
|
||||
beammp_error("Client doesn't have a download socket!");
|
||||
if (!c.IsDisconnected())
|
||||
c.Disconnect("Missing download socket");
|
||||
Disconnect(c);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -794,7 +788,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
f.read(reinterpret_cast<char*>(Data.data()), Split);
|
||||
if (!TCPSendRaw(c, *TCPSock, Data.data(), Split)) {
|
||||
if (!c.IsDisconnected())
|
||||
c.Disconnect("TCPSendRaw failed in mod download (1)");
|
||||
Disconnect(c);
|
||||
break;
|
||||
}
|
||||
Sent += Split;
|
||||
@ -803,7 +797,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
f.read(reinterpret_cast<char*>(Data.data()), Diff);
|
||||
if (!TCPSendRaw(c, *TCPSock, Data.data(), int32_t(Diff))) {
|
||||
if (!c.IsDisconnected())
|
||||
c.Disconnect("TCPSendRaw failed in mod download (2)");
|
||||
Disconnect(c);
|
||||
break;
|
||||
}
|
||||
Sent += Diff;
|
||||
@ -818,7 +812,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
f.read(reinterpret_cast<char*>(Data.data()), Split);
|
||||
if (!TCPSendRaw(c, *TCPSock, Data.data(), Split)) {
|
||||
if (!c.IsDisconnected())
|
||||
c.Disconnect("TCPSendRaw failed in mod download (1)");
|
||||
Disconnect(c);
|
||||
break;
|
||||
}
|
||||
Sent += Split;
|
||||
@ -827,7 +821,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
f.read(reinterpret_cast<char*>(Data.data()), Diff);
|
||||
if (!TCPSendRaw(c, *TCPSock, Data.data(), int32_t(Diff))) {
|
||||
if (!c.IsDisconnected())
|
||||
c.Disconnect("TCPSendRaw failed in mod download (2)");
|
||||
Disconnect(c);
|
||||
break;
|
||||
}
|
||||
Sent += Diff;
|
||||
@ -931,7 +925,7 @@ void TNetwork::SendToAll(TClient* c, const std::vector<uint8_t>& Data, bool Self
|
||||
}
|
||||
} else {
|
||||
if (!UDPSend(*Client, Data)) {
|
||||
OnDisconnect(Client);
|
||||
Disconnect(Client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -957,7 +951,7 @@ bool TNetwork::UDPSend(TClient& Client, std::vector<uint8_t> Data) {
|
||||
if (ec) {
|
||||
beammp_debugf("UDP sendto() failed: {}", ec.message());
|
||||
if (!Client.IsDisconnected())
|
||||
Client.Disconnect("UDP send failed");
|
||||
Disconnect(Client);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -33,15 +33,7 @@ void TPPSMonitor::operator()() {
|
||||
Application::SetPPS("-");
|
||||
continue;
|
||||
}
|
||||
mServer.ForEachClientWeak([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
||||
std::shared_ptr<TClient> c;
|
||||
{
|
||||
ReadLock Lock(mServer.GetClientMutex());
|
||||
if (!ClientPtr.expired()) {
|
||||
c = ClientPtr.lock();
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
mServer.ForEachClient([&](const std::shared_ptr<TClient>& c) -> bool {
|
||||
if (c->GetCarCount() > 0) {
|
||||
C++;
|
||||
V += c->GetCarCount();
|
||||
|
@ -171,19 +171,6 @@ void TServer::ForEachClient(const std::function<bool(const std::shared_ptr<TClie
|
||||
}
|
||||
}
|
||||
|
||||
void TServer::ForEachClientWeak(const std::function<bool(std::weak_ptr<TClient>)>& Fn) {
|
||||
decltype(mClients) Clients;
|
||||
{
|
||||
ReadLock lock(mClientsMutex);
|
||||
Clients = mClients;
|
||||
}
|
||||
for (auto& Client : Clients) {
|
||||
if (!Fn(Client)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t TServer::ClientCount() const {
|
||||
ReadLock Lock(mClientsMutex);
|
||||
return mClients.size();
|
||||
@ -224,7 +211,7 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::vector<uin
|
||||
case 'p':
|
||||
if (!Network.Respond(*LockedClient, StringToVector("p"), false)) {
|
||||
// failed to send
|
||||
LockedClient->Disconnect("Failed to send ping");
|
||||
Disconnect(LockedClient);
|
||||
} else {
|
||||
Network.UpdatePlayer(*LockedClient);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user