diff --git a/src/TConsole.cpp b/src/TConsole.cpp index caaefb6..dce3142 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -298,39 +298,37 @@ void TConsole::Command_Debug(const std::string&, const std::vector& connection and do not necessarily reflect the *current* data rate of that client. )")); - mLuaEngine->Server().ForEachClientWeak([&](std::weak_ptr Client) -> bool { - if (!Client.expired()) { - auto Locked = Client.lock(); - std::string State = ""; - if (Locked->IsSyncing()) { - State += "Syncing"; + mLuaEngine->Server().ForEachClient([&](const auto& Client) { + std::string State = ""; + if (Client->IsSyncing()) { + State += "Syncing"; + } + if (Client->IsSynced()) { + if (!State.empty()) { + State += " & "; } - if (Locked->IsSynced()) { - if (!State.empty()) { - State += " & "; - } - State += "Synced"; + State += "Synced"; + } + if (Client->IsConnected()) { + if (!State.empty()) { + State += " & "; } - if (Locked->IsConnected()) { - if (!State.empty()) { - State += " & "; - } - State += "Connected"; + State += "Connected"; + } + if (Client->IsDisconnected()) { + if (!State.empty()) { + State += " & "; } - if (Locked->IsDisconnected()) { - if (!State.empty()) { - State += " & "; - } - State += "Disconnected"; - } - auto Now = TimeType::now(); - auto Seconds = std::chrono::duration_cast(Now - Locked->ConnectionTime); - std::string ConnectedSince = fmt::format("{:%Y/%m/%d %H:%M:%S}, {:%H:%M:%S} ago ({} seconds)", - fmt::localtime(TimeType::to_time_t(Locked->ConnectionTime)), - Seconds, - Seconds.count()); - Application::Console().WriteRaw(fmt::format( - R"( {} ('{}'): + State += "Disconnected"; + } + auto Now = TimeType::now(); + auto Seconds = std::chrono::duration_cast(Now - Client->ConnectionTime); + std::string ConnectedSince = fmt::format("{:%Y/%m/%d %H:%M:%S}, {:%H:%M:%S} ago ({} seconds)", + fmt::localtime(TimeType::to_time_t(Client->ConnectionTime)), + Seconds, + Seconds.count()); + Application::Console().WriteRaw(fmt::format( + R"( {} ('{}'): Roles: {} Cars: {} Is guest: {} @@ -347,27 +345,23 @@ void TConsole::Command_Debug(const std::string&, const std::vector& Connected since: {} Average send: {}/s Average receive: {}/s)", - Locked->GetID(), Locked->GetName(), - Locked->GetRoles(), - Locked->GetCarCount(), - Locked->IsGuest() ? "yes" : "no", - Locked->GetUnicycleID() == -1 ? "no" : "yes", - Locked->GetTCPSock().remote_endpoint().address() == ip::address::from_string("0.0.0.0") ? "not connected" : "connected", Locked->GetTCPSock().remote_endpoint().port(), - Locked->GetUDPAddr().address() == ip::address::from_string("0.0.0.0") ? "NOT connected" : "connected", Locked->GetUDPAddr().port(), - ToHumanReadableSize(Locked->TcpSent), - ToHumanReadableSize(Locked->TcpReceived), - ToHumanReadableSize(Locked->UdpSent), Locked->UdpPacketsSent, - ToHumanReadableSize(Locked->UdpReceived), Locked->UdpPacketsReceived, - State.empty() ? "None (likely pre-sync)" : State, - Locked->MissedPacketQueueSize(), - Locked->SecondsSinceLastPing(), - ConnectedSince, - ToHumanReadableSize((Locked->TcpSent + Locked->UdpSent) / Seconds.count()), - ToHumanReadableSize((Locked->TcpReceived + Locked->UdpReceived) / Seconds.count()))); - } else { - Application::Console().WriteRaw(fmt::format(R"( )")); - } - return true; + Client->GetID(), Client->GetName(), + Client->GetRoles(), + Client->GetCarCount(), + Client->IsGuest() ? "yes" : "no", + Client->GetUnicycleID() == -1 ? "no" : "yes", + Client->GetTCPSock().remote_endpoint().address() == ip::address::from_string("0.0.0.0") ? "not connected" : "connected", Client->GetTCPSock().remote_endpoint().port(), + Client->GetUDPAddr().address() == ip::address::from_string("0.0.0.0") ? "NOT connected" : "connected", Client->GetUDPAddr().port(), + ToHumanReadableSize(Client->TcpSent), + ToHumanReadableSize(Client->TcpReceived), + ToHumanReadableSize(Client->UdpSent), Client->UdpPacketsSent, + ToHumanReadableSize(Client->UdpReceived), Client->UdpPacketsReceived, + State.empty() ? "None (likely pre-sync)" : State, + Client->MissedPacketQueueSize(), + Client->SecondsSinceLastPing(), + ConnectedSince, + ToHumanReadableSize((Client->TcpSent + Client->UdpSent) / Seconds.count()), + ToHumanReadableSize((Client->TcpReceived + Client->UdpReceived) / Seconds.count()))); }); } @@ -390,16 +384,13 @@ void TConsole::Command_Kick(const std::string&, const std::vector& beammp_trace("attempt to kick '" + Name + "' for '" + Reason + "'"); bool Kicked = false; - mLuaEngine->Server().ForEachClientWeak([&](std::weak_ptr Client) -> bool { - auto Locked = Client.lock(); - if (Locked) { - if (StringStartsWithLower(Locked->GetName(), Name)) { - mLuaEngine->Network().ClientKick(*Locked, Reason); - Kicked = true; - return false; - } + mLuaEngine->Server().ForEachClient([&](const auto& Client) -> IterationDecision { + if (StringStartsWithLower(Client->GetName(), Name)) { + mLuaEngine->Network().ClientKick(*Client, Reason); + Kicked = true; + return Break; } - return true; + return Continue; }); if (!Kicked) { Application::Console().WriteRaw("Error: No player with name matching '" + Name + "' was found."); @@ -552,14 +543,10 @@ void TConsole::Command_List(const std::string&, const std::vector& } 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 Client) -> bool { - if (!Client.expired()) { - auto locked = Client.lock(); - ss << std::left << std::setw(25) << locked->GetName() - << std::setw(6) << locked->GetID() - << std::setw(6) << locked->GetCarCount() << "\n"; - } - return true; + mLuaEngine->Server().ForEachClient([&](const auto& Client) { + ss << std::left << std::setw(25) << Client->GetName() + << std::setw(6) << Client->GetID() + << std::setw(6) << Client->GetCarCount() << "\n"; }); auto Str = ss.str(); Application::Console().WriteRaw(Str.substr(0, Str.size() - 1)); @@ -579,20 +566,16 @@ void TConsole::Command_Status(const std::string&, const std::vector size_t SyncingCount = 0; size_t MissedPacketQueueSum = 0; int LargestSecondsSinceLastPing = 0; - mLuaEngine->Server().ForEachClientWeak([&](std::weak_ptr Client) -> bool { - if (!Client.expired()) { - auto Locked = Client.lock(); - CarCount += Locked->GetCarCount(); - ConnectedCount += Locked->IsConnected() ? 1 : 0; - GuestCount += Locked->IsGuest() ? 1 : 0; - SyncedCount += Locked->IsSynced() ? 1 : 0; - SyncingCount += Locked->IsSyncing() ? 1 : 0; - MissedPacketQueueSum += Locked->MissedPacketQueueSize(); - if (Locked->SecondsSinceLastPing() < LargestSecondsSinceLastPing) { - LargestSecondsSinceLastPing = Locked->SecondsSinceLastPing(); - } + mLuaEngine->Server().ForEachClient([&](const auto& Client) { + CarCount += Client->GetCarCount(); + ConnectedCount += Client->IsConnected() ? 1 : 0; + GuestCount += Client->IsGuest() ? 1 : 0; + SyncedCount += Client->IsSynced() ? 1 : 0; + SyncingCount += Client->IsSyncing() ? 1 : 0; + MissedPacketQueueSum += Client->MissedPacketQueueSize(); + if (Client->SecondsSinceLastPing() < LargestSecondsSinceLastPing) { + LargestSecondsSinceLastPing = Client->SecondsSinceLastPing(); } - return true; }); size_t SystemsStarting = 0; @@ -680,14 +663,10 @@ void TConsole::Autocomplete_Lua(const std::string& stub, std::vector& suggestions) { std::string stub_lower = boost::algorithm::to_lower_copy(stub); - mLuaEngine->Server().ForEachClientWeak([&](std::weak_ptr Client) -> bool { - auto Locked = Client.lock(); - if (Locked) { - if (StringStartsWithLower(Locked->GetName(), stub_lower)) { - suggestions.push_back("kick " + Locked->GetName()); - } + mLuaEngine->Server().ForEachClient([&](const auto& Client) { + if (StringStartsWithLower(Client->GetName(), stub_lower)) { + suggestions.push_back("kick " + Client->GetName()); } - return true; }); } diff --git a/src/THeartbeatThread.cpp b/src/THeartbeatThread.cpp index 8672120..43ad7cb 100644 --- a/src/THeartbeatThread.cpp +++ b/src/THeartbeatThread.cpp @@ -167,12 +167,8 @@ THeartbeatThread::THeartbeatThread(TResourceManager& ResourceManager, TServer& S } std::string THeartbeatThread::GetPlayers() { std::string Return; - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - Return += ClientPtr.lock()->GetName() + ";"; - } - return true; + mServer.ForEachClient([&](const auto& Client) { + Return += Client->GetName() + ";"; }); return Return; } diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 5e7444c..5237e4f 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -1,6 +1,7 @@ #include "TNetwork.h" #include "Client.h" #include "Common.h" +#include "IterationDecision.h" #include "LuaAPI.h" #include "TLuaEngine.h" #include "nlohmann/json.hpp" @@ -52,11 +53,8 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R auto Futures = LuaAPI::MP::Engine->TriggerEvent("onShutdown", ""); TLuaEngine::WaitForAll(Futures, std::chrono::seconds(60)); beammp_debug("Kicking all players due to shutdown"); - Server.ForEachClientWeak([&](std::weak_ptr client) -> bool { - if (!client.expired()) { - ClientKick(*client.lock(), "Server shutdown"); - } - return true; + Server.ForEachClient([&](const auto& Client) { + ClientKick(*Client, "Server shutdown"); }); }); } @@ -212,15 +210,12 @@ void TNetwork::HandleDownload(TConnection&& Conn) { return; } auto ID = uint8_t(D); - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - auto c = ClientPtr.lock(); - if (c->GetID() == ID) { - c->SetDownSock(std::move(Conn.Socket)); - } + mServer.ForEachClient([&](const auto& Client) -> IterationDecision { + if (Client->GetID() == ID) { + Client->SetDownSock(std::move(Conn.Socket)); + return Break; } - return true; + return Continue; }); } @@ -297,21 +292,13 @@ std::shared_ptr TNetwork::Authentication(TConnection&& RawConnection) { } beammp_debug("Name -> " + Client->GetName() + ", Guest -> " + std::to_string(Client->IsGuest()) + ", Roles -> " + Client->GetRoles()); - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - std::shared_ptr Cl; - { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - Cl = ClientPtr.lock(); - } else - return true; + mServer.ForEachClient([&](const auto& ThisClient) -> IterationDecision { + // FIXME: This doesn't respect forum ID, and it should :^) + if (ThisClient->GetName() == Client->GetName() && ThisClient->IsGuest() == Client->IsGuest()) { + ThisClient->Disconnect("Stale Client (replaced by new client)"); + return Break; } - if (Cl->GetName() == Client->GetName() && Cl->IsGuest() == Client->IsGuest()) { - Cl->Disconnect("Stale Client (not a real player)"); - return false; - } - - return true; + return Continue; }); auto Futures = LuaAPI::MP::Engine->TriggerEvent("onPlayerAuth", "", Client->GetName(), Client->GetRoles(), Client->IsGuest(), Client->GetIdentifiers()); @@ -533,13 +520,8 @@ void TNetwork::TCPClient(const std::weak_ptr& c) { void TNetwork::UpdatePlayer(TClient& Client) { std::string Packet = ("Ss") + std::to_string(mServer.ClientCount()) + "/" + std::to_string(Application::GetSettingInt(StrMaxPlayers)) + ":"; - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - auto c = ClientPtr.lock(); - Packet += c->GetName() + ","; - } - return true; + mServer.ForEachClient([&](const auto& ThisClient) { + Packet += ThisClient->GetName() + ","; }); Packet = Packet.substr(0, Packet.length() - 1); Client.EnqueuePacket(StringToVector(Packet)); @@ -585,16 +567,11 @@ int TNetwork::OpenID() { bool found; do { found = true; - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - auto c = ClientPtr.lock(); - if (c->GetID() == ID) { - found = false; - ID++; - } + mServer.ForEachClient([&](const auto& Client) { + if (Client->GetID() == ID) { + found = false; + ID++; } - return true; }); } while (!found); return ID; @@ -855,32 +832,23 @@ bool TNetwork::SyncClient(const std::weak_ptr& c) { LockedClient->SetIsSyncing(true); bool Return = false; bool res = true; - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - std::shared_ptr client; - { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - client = ClientPtr.lock(); - } else - return true; - } + mServer.ForEachClient([&](const auto& Client) -> IterationDecision { TClient::TSetOfVehicleData VehicleData; { // Vehicle Data Lock Scope - auto LockedData = client->GetAllCars(); + auto LockedData = Client->GetAllCars(); VehicleData = *LockedData.VehicleData; } // End Vehicle Data Lock Scope - if (client != LockedClient) { + if (Client != LockedClient) { for (auto& v : VehicleData) { if (LockedClient->IsDisconnected()) { Return = true; res = false; - return false; + return Break; } res = Respond(*LockedClient, StringToVector(v.Data()), true, true); } } - - return true; + return Continue; }); LockedClient->SetIsSyncing(false); if (Return) { @@ -896,16 +864,7 @@ void TNetwork::SendToAll(TClient* c, const std::vector& Data, bool Self beammp_assert(c); char C = Data.at(0); bool ret = true; - mServer.ForEachClientWeak([&](std::weak_ptr ClientPtr) -> bool { - std::shared_ptr Client; - try { - ReadLock Lock(mServer.GetClientMutex()); - Client = ClientPtr.lock(); - } catch (const std::exception&) { - // continue - beammp_warn("Client expired, shouldn't happen - if a client disconnected recently, you can ignore this"); - return true; - } + mServer.ForEachClient([&](const auto& Client) { if (Self || Client.get() != c) { if (Client->IsSynced() || Client->IsSyncing()) { if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') { @@ -927,7 +886,6 @@ void TNetwork::SendToAll(TClient* c, const std::vector& Data, bool Self } } } - return true; }); if (!ret) { // TODO: handle diff --git a/src/TPPSMonitor.cpp b/src/TPPSMonitor.cpp index 3bc3902..7878d10 100644 --- a/src/TPPSMonitor.cpp +++ b/src/TPPSMonitor.cpp @@ -33,26 +33,16 @@ void TPPSMonitor::operator()() { Application::SetPPS("-"); continue; } - mServer.ForEachClientWeak([&](const std::weak_ptr& ClientPtr) -> bool { - std::shared_ptr c; - { - ReadLock Lock(mServer.GetClientMutex()); - if (!ClientPtr.expired()) { - c = ClientPtr.lock(); - } else - return true; - } - if (c->GetCarCount() > 0) { + mServer.ForEachClient([&](const auto& Client) { + if (Client->GetCarCount() > 0) { C++; - V += c->GetCarCount(); + V += Client->GetCarCount(); } // kick on "no ping" - if (c->SecondsSinceLastPing() > (20 * 60)) { - beammp_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); + if (Client->SecondsSinceLastPing() > (20 * 60)) { + beammp_debugf("Client {} ({}) timing out: {}s since last contact", Client->GetName(), Client->GetID(), Client->SecondsSinceLastPing()); + TimedOutClients.push_back(Client); } - - return true; }); for (auto& ClientToKick : TimedOutClients) { Network().ClientKick(*ClientToKick, "Timeout (no ping for way too long)");