#pragma once #include "IThreaded.h" #include "IterationDecision.h" #include "RWMutex.h" #include "TScopedTimer.h" #include #include #include #include #include #include #include "BoostAliases.h" class TClient; class TNetwork; class TPPSMonitor; // clang-format doesn't know how to deal with concepts // clang-format off template concept ForEachHandlerWithDecision = requires(FnT Fn, const std::shared_ptr& Ptr) { requires std::invocable&> ; { std::invoke(Fn, Ptr) } -> std::convertible_to; }; template concept ForEachHandler = requires(FnT Fn, const std::shared_ptr& Ptr) { requires std::invocable &> ; { std::invoke(Fn, Ptr) } -> std::same_as; }; // clang-format on class TServer final { public: using TClientSet = std::unordered_set>; TServer(const std::vector& Arguments); void InsertClient(const std::shared_ptr& Ptr); void RemoveClient(const std::weak_ptr&); // in Fn, return true to continue, return false to break [[deprecated("use ForEachClient instead")]] void ForEachClientWeak(const std::function)>& Fn); // in Fn, return Break or Continue template void ForEachClient(FnT Fn) { decltype(mClients) Clients; { ReadLock lock(mClientsMutex); Clients = mClients; } for (auto& Client : Clients) { IterationDecision Decision = std::invoke(Fn, Client); if (Decision == IterationDecision::Break) { break; } } } template void ForEachClient(FnT Fn) { decltype(mClients) Clients; { ReadLock lock(mClientsMutex); Clients = mClients; } for (auto& Client : Clients) { std::invoke(Fn, Client); } } size_t ClientCount() const; static void GlobalParser(const std::weak_ptr& Client, std::vector&& Packet, TNetwork& Network); static void HandleEvent(TClient& c, const std::string& Data); RWMutex& GetClientMutex() const { return mClientsMutex; } const TScopedTimer UptimeTimer; // asio io context io_context& IoCtx() { return mIoCtx; } private: io_context mIoCtx {}; 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); static bool HandlePosition(TClient& c, const std::string& PacketStr); static bool HandleVehicleUpdate(const std::string& PacketStr, const int playerID); }; struct BufferView { uint8_t* Data { nullptr }; size_t Size { 0 }; const uint8_t* data() const { return Data; } uint8_t* data() { return Data; } size_t size() const { return Size; } };