From 8719cee849a6786e097e1b79650b9287f608b1b4 Mon Sep 17 00:00:00 2001 From: "GuillaumeG." Date: Tue, 13 Jan 2026 21:39:10 +0100 Subject: [PATCH 1/6] Fix and cleanup on the counter aspects of client --- .../client/main.cpp | 12 +- includes/FastEngine/network/C_client.hpp | 31 ++++-- includes/FastEngine/network/C_protocol.hpp | 23 ++-- includes/FastEngine/network/C_protocol.inl | 12 +- includes/FastEngine/network/C_server.hpp | 5 +- sources/network/C_client.cpp | 103 +++++++++++------- sources/network/C_netClient.cpp | 55 ++++++---- sources/network/C_netCommand.cpp | 13 +-- sources/network/C_protocol.cpp | 91 ++++++++++------ sources/network/C_server.cpp | 85 +++++++++------ 10 files changed, 260 insertions(+), 170 deletions(-) diff --git a/examples/clientServerLifeSimulator_004/client/main.cpp b/examples/clientServerLifeSimulator_004/client/main.cpp index 4509d893..1e10054c 100644 --- a/examples/clientServerLifeSimulator_004/client/main.cpp +++ b/examples/clientServerLifeSimulator_004/client/main.cpp @@ -369,9 +369,15 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) << '\n' << "Update count: " << mainScene->getUpdateCount() << '\n' << "Lost packets: " << server._client.getLostPacketCount() << '\n' - << "Realm: " << static_cast(server._client.getCurrentRealm()) - << ", CurrentCounter: " << server._client.getCurrentPacketCounter() - << ", ClientCounter: " << server._client.getClientPacketCounter(); + << "Realm: " << static_cast(server._client.getCurrentRealm()) << '\n' + << "Peer counter: " + << server._client.getPacketCounter(fge::net::Client::Targets::PEER) + << ", Peer reorderedCounter: " + << server._client.getReorderedPacketCounter(fge::net::Client::Targets::PEER) << '\n' + << "Host counter: " + << server._client.getPacketCounter(fge::net::Client::Targets::HOST) + << ", Host reorderedCounter: " + << server._client.getReorderedPacketCounter(fge::net::Client::Targets::HOST); latencyText->setString(tiny_utf8::string(latencyTextStream.str())); diff --git a/includes/FastEngine/network/C_client.hpp b/includes/FastEngine/network/C_client.hpp index 89436bd7..5ab68ef5 100644 --- a/includes/FastEngine/network/C_client.hpp +++ b/includes/FastEngine/network/C_client.hpp @@ -240,6 +240,13 @@ class FGE_API Client public: Client(); ~Client(); + + enum class Targets + { + PEER, + HOST + }; + /** * \brief Constructor with default latencies * @@ -392,15 +399,15 @@ class FGE_API Client void setCurrentRealm(ProtocolPacket::RealmType realm); ProtocolPacket::RealmType advanceCurrentRealm(); - [[nodiscard]] ProtocolPacket::CounterType getCurrentPacketCounter() const; - ProtocolPacket::CounterType advanceCurrentPacketCounter(); - void setCurrentPacketCounter(ProtocolPacket::CounterType counter); + [[nodiscard]] ProtocolPacket::CounterType getPacketCounter(Targets target) const; + ProtocolPacket::CounterType advancePacketCounter(Targets target); + void setPacketCounter(Targets target, ProtocolPacket::CounterType count); + + [[nodiscard]] ProtocolPacket::CounterType getReorderedPacketCounter(Targets target) const; + ProtocolPacket::CounterType advanceReorderedPacketCounter(Targets target); + void setReorderedPacketCounter(Targets target, ProtocolPacket::CounterType count); - [[nodiscard]] ProtocolPacket::CounterType getClientPacketCounter() const; - ProtocolPacket::CounterType advanceClientPacketCounter(); - void setClientPacketCounter(ProtocolPacket::CounterType counter); - void resetLastReorderedPacketCounter(); - [[nodiscard]] ProtocolPacket::CounterType getLastReorderedPacketCounter() const; + void resetAllCounters(); void acknowledgeReception(ReceivedPacketPtr const& packet); [[nodiscard]] std::unordered_set const& getAcknowledgedList() const; @@ -443,9 +450,11 @@ class FGE_API Client std::chrono::steady_clock::time_point g_lastRealmChangeTimePoint; ProtocolPacket::RealmType g_currentRealm{FGE_NET_DEFAULT_REALM}; - ProtocolPacket::CounterType g_currentPacketCounter{0}; - ProtocolPacket::CounterType g_lastReorderedPacketCounter{0}; - ProtocolPacket::CounterType g_clientPacketCounter{0}; + + ProtocolPacket::CounterType g_hostPacketCounter{0}; + ProtocolPacket::CounterType g_hostReorderedPacketCounter{0}; + ProtocolPacket::CounterType g_peerPacketCounter{0}; + ProtocolPacket::CounterType g_peerReorderedPacketCounter{0}; std::unordered_set g_acknowledgedPackets; uint32_t g_lostPacketCount{0}; diff --git a/includes/FastEngine/network/C_protocol.hpp b/includes/FastEngine/network/C_protocol.hpp index 756e6ece..0c535037 100644 --- a/includes/FastEngine/network/C_protocol.hpp +++ b/includes/FastEngine/network/C_protocol.hpp @@ -122,7 +122,7 @@ class FGE_API ProtocolPacket : public Packet, public std::enable_shared_from_thi constexpr static std::size_t IdPosition = 0; constexpr static std::size_t RealmPosition = sizeof(IdType); constexpr static std::size_t CounterPosition = sizeof(IdType) + sizeof(RealmType); - constexpr static std::size_t LastCounterPosition = sizeof(IdType) + sizeof(RealmType) + sizeof(CounterType); + constexpr static std::size_t ReorderedCounterPosition = sizeof(IdType) + sizeof(RealmType) + sizeof(CounterType); inline ProtocolPacket(Packet const& pck, Identity const& id, @@ -152,7 +152,7 @@ class FGE_API ProtocolPacket : public Packet, public std::enable_shared_from_thi [[nodiscard]] inline std::optional retrieveFullHeaderId() const; [[nodiscard]] inline std::optional retrieveRealm() const; [[nodiscard]] inline std::optional retrieveCounter() const; - [[nodiscard]] inline std::optional retrieveLastCounter() const; + [[nodiscard]] inline std::optional retrieveReorderedCounter() const; [[nodiscard]] inline std::optional
retrieveHeader() const; [[nodiscard]] inline bool isFragmented() const; @@ -170,7 +170,7 @@ class FGE_API ProtocolPacket : public Packet, public std::enable_shared_from_thi inline ProtocolPacket& setRealm(RealmType realm); inline ProtocolPacket& setCounter(CounterType counter); - inline ProtocolPacket& setLastReorderedPacketCounter(CounterType counter); + inline ProtocolPacket& setReorderedCounter(CounterType counter); inline void setTimestamp(Timestamp timestamp); [[nodiscard]] inline Timestamp getTimeStamp() const; @@ -358,11 +358,13 @@ class FGE_API PacketReorderer void push(ReceivedPacketPtr&& packet); [[nodiscard]] static Stats checkStat(ReceivedPacketPtr const& packet, - ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType currentRealm); + ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType peerRealm); [[nodiscard]] bool isForced() const; - [[nodiscard]] std::optional checkStat(ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType currentRealm) const; + [[nodiscard]] std::optional checkStat(ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType peerRealm) const; [[nodiscard]] ReceivedPacketPtr pop(); [[nodiscard]] bool isEmpty() const; @@ -381,12 +383,13 @@ class FGE_API PacketReorderer Data& operator=(Data const& r) = delete; Data& operator=(Data&& r) noexcept; - [[nodiscard]] Stats checkStat(ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType currentRealm) const; + [[nodiscard]] Stats checkStat(ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType peerRealm) const; ReceivedPacketPtr _packet; ProtocolPacket::CounterType _counter; - ProtocolPacket::CounterType _lastCounter; + ProtocolPacket::CounterType _reorderedCounter; ProtocolPacket::RealmType _realm; struct Compare diff --git a/includes/FastEngine/network/C_protocol.inl b/includes/FastEngine/network/C_protocol.inl index 31964bb5..891e8ecf 100644 --- a/includes/FastEngine/network/C_protocol.inl +++ b/includes/FastEngine/network/C_protocol.inl @@ -152,12 +152,12 @@ inline std::optional ProtocolPacket::retrieveCounte } return std::nullopt; } -inline std::optional ProtocolPacket::retrieveLastCounter() const +inline std::optional ProtocolPacket::retrieveReorderedCounter() const { if (this->haveCorrectHeaderSize()) { CounterType counter; - this->unpack(LastCounterPosition, &counter, sizeof(CounterType)); + this->unpack(ReorderedCounterPosition, &counter, sizeof(CounterType)); return counter; } return std::nullopt; @@ -170,7 +170,7 @@ inline std::optional ProtocolPacket::retrieveHeader() co this->unpack(IdPosition, &header._id, sizeof(IdType)); this->unpack(RealmPosition, &header._realm, sizeof(RealmType)); this->unpack(CounterPosition, &header._counter, sizeof(CounterType)); - this->unpack(LastCounterPosition, &header._lastCounter, sizeof(CounterType)); + this->unpack(ReorderedCounterPosition, &header._lastCounter, sizeof(CounterType)); return header; } return std::nullopt; @@ -190,7 +190,7 @@ inline ProtocolPacket& ProtocolPacket::setHeader(Header const& header) this->pack(IdPosition, &header._id, sizeof(IdType)); this->pack(RealmPosition, &header._realm, sizeof(RealmType)); this->pack(CounterPosition, &header._counter, sizeof(CounterType)); - this->pack(LastCounterPosition, &header._lastCounter, sizeof(CounterType)); + this->pack(ReorderedCounterPosition, &header._lastCounter, sizeof(CounterType)); return *this; } inline ProtocolPacket& ProtocolPacket::setHeaderId(IdType id) @@ -271,9 +271,9 @@ inline ProtocolPacket& ProtocolPacket::setCounter(CounterType counter) this->pack(CounterPosition, &counter, sizeof(CounterType)); return *this; } -inline ProtocolPacket& ProtocolPacket::setLastReorderedPacketCounter(CounterType counter) +inline ProtocolPacket& ProtocolPacket::setReorderedCounter(CounterType counter) { - this->pack(LastCounterPosition, &counter, sizeof(CounterType)); + this->pack(ReorderedCounterPosition, &counter, sizeof(CounterType)); return *this; } diff --git a/includes/FastEngine/network/C_server.hpp b/includes/FastEngine/network/C_server.hpp index a702739e..abb0f2ae 100644 --- a/includes/FastEngine/network/C_server.hpp +++ b/includes/FastEngine/network/C_server.hpp @@ -135,8 +135,9 @@ class FGE_API NetFluxUdp void forcePushPacketFront(ReceivedPacketPtr fluxPck); [[nodiscard]] FluxProcessResults processReorder(PacketReorderer& reorderer, ReceivedPacketPtr& packet, - ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType clientRealm, + ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType realm, bool ignoreRealm); mutable std::mutex _g_mutexFlux; diff --git a/sources/network/C_client.cpp b/sources/network/C_client.cpp index 150eaed6..1922b9e6 100644 --- a/sources/network/C_client.cpp +++ b/sources/network/C_client.cpp @@ -19,6 +19,8 @@ #include "private/fge_crypt.hpp" #include +#include "private/fge_debug.hpp" + namespace fge::net { @@ -225,6 +227,12 @@ void Client::clearPackets() } void Client::pushPacket(TransmitPacketPtr pck) { + if (pck == nullptr) + { + FGE_DEBUG_PRINT("Client::pushPacket tried to push a nullptr packet"); + return; + } + if (this->g_status.isDisconnected()) { return; @@ -232,19 +240,12 @@ void Client::pushPacket(TransmitPacketPtr pck) std::scoped_lock const lck(this->g_mutex); -#ifdef FGE_DEF_SERVER - pck->setCounter(this->advanceCurrentPacketCounter()); -#else - pck->setCounter(this->advanceClientPacketCounter()); -#endif - pck->setRealm(this->getCurrentRealm()); - - pck->setLastReorderedPacketCounter(this->getLastReorderedPacketCounter()); + pck->setCounter(this->advancePacketCounter(Targets::HOST)); if (!pck->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG)) { - this->resetLastReorderedPacketCounter(); + pck->setReorderedCounter(this->advanceReorderedPacketCounter(Targets::HOST)); } if (this->g_status.isInEncryptedState()) @@ -255,6 +256,12 @@ void Client::pushPacket(TransmitPacketPtr pck) } void Client::pushForcedFrontPacket(TransmitPacketPtr pck) { + if (pck == nullptr) + { + FGE_DEBUG_PRINT("Client::pushForcedFrontPacket tried to push a nullptr packet"); + return; + } + std::scoped_lock const lck(this->g_mutex); this->g_pendingTransmitPackets.push_front(std::move(pck)); } @@ -302,7 +309,8 @@ void Client::setCurrentRealm(ProtocolPacket::RealmType realm) std::scoped_lock const lck(this->g_mutex); if (this->g_currentRealm != realm) { - this->g_currentPacketCounter = 0; + this->g_hostPacketCounter = 0; + this->g_peerPacketCounter = 0; this->g_lastRealmChangeTimePoint = std::chrono::steady_clock::now(); this->g_currentRealm = realm; } @@ -310,62 +318,77 @@ void Client::setCurrentRealm(ProtocolPacket::RealmType realm) ProtocolPacket::RealmType Client::advanceCurrentRealm() { std::scoped_lock const lck(this->g_mutex); - this->g_currentPacketCounter = 0; + this->g_hostPacketCounter = 0; + this->g_peerPacketCounter = 0; this->g_lastRealmChangeTimePoint = std::chrono::steady_clock::now(); return ++this->g_currentRealm; } -ProtocolPacket::CounterType Client::getCurrentPacketCounter() const +ProtocolPacket::CounterType Client::getPacketCounter(Targets target) const { std::scoped_lock const lck(this->g_mutex); - return this->g_currentPacketCounter; + if (target == Targets::HOST) + { + return this->g_hostPacketCounter; + } + return this->g_peerPacketCounter; } -ProtocolPacket::CounterType Client::advanceCurrentPacketCounter() +ProtocolPacket::CounterType Client::advancePacketCounter(Targets target) { std::scoped_lock const lck(this->g_mutex); - return ++this->g_currentPacketCounter; + if (target == Targets::HOST) + { + return ++this->g_hostPacketCounter; + } + return ++this->g_peerPacketCounter; } -void Client::setCurrentPacketCounter(ProtocolPacket::CounterType counter) +void Client::setPacketCounter(Targets target, ProtocolPacket::CounterType count) { std::scoped_lock const lck(this->g_mutex); - this->g_currentPacketCounter = counter; -#ifdef FGE_DEF_SERVER - this->g_lastReorderedPacketCounter = counter; -#endif + if (target == Targets::HOST) + { + this->g_hostPacketCounter = count; + return; + } + this->g_peerPacketCounter = count; } -ProtocolPacket::CounterType Client::getClientPacketCounter() const +ProtocolPacket::CounterType Client::getReorderedPacketCounter(Targets target) const { std::scoped_lock const lck(this->g_mutex); - return this->g_clientPacketCounter; + if (target == Targets::HOST) + { + return this->g_hostReorderedPacketCounter; + } + return this->g_peerReorderedPacketCounter; } -ProtocolPacket::CounterType Client::advanceClientPacketCounter() +ProtocolPacket::CounterType Client::advanceReorderedPacketCounter(Targets target) { std::scoped_lock const lck(this->g_mutex); - return this->g_clientPacketCounter++; + if (target == Targets::HOST) + { + return ++this->g_hostReorderedPacketCounter; + } + return ++this->g_peerReorderedPacketCounter; } -void Client::setClientPacketCounter(ProtocolPacket::CounterType countId) +void Client::setReorderedPacketCounter(Targets target, ProtocolPacket::CounterType count) { std::scoped_lock const lck(this->g_mutex); - this->g_clientPacketCounter = countId; -#ifndef FGE_DEF_SERVER - this->g_lastReorderedPacketCounter = countId; -#endif + if (target == Targets::HOST) + { + this->g_hostReorderedPacketCounter = count; + return; + } + this->g_peerReorderedPacketCounter = count; } -void Client::resetLastReorderedPacketCounter() -{ - std::scoped_lock const lck(this->g_mutex); -#ifdef FGE_DEF_SERVER - this->g_lastReorderedPacketCounter = this->g_currentPacketCounter; -#else - this->g_lastReorderedPacketCounter = this->g_clientPacketCounter; -#endif -} -ProtocolPacket::CounterType Client::getLastReorderedPacketCounter() const +void Client::resetAllCounters() { std::scoped_lock const lck(this->g_mutex); - return this->g_lastReorderedPacketCounter; + this->g_hostPacketCounter = 0; + this->g_peerPacketCounter = 0; + this->g_hostReorderedPacketCounter = 0; + this->g_peerReorderedPacketCounter = 0; } void Client::acknowledgeReception(ReceivedPacketPtr const& packet) diff --git a/sources/network/C_netClient.cpp b/sources/network/C_netClient.cpp index f22b09fb..646fd756 100644 --- a/sources/network/C_netClient.cpp +++ b/sources/network/C_netClient.cpp @@ -118,9 +118,8 @@ void ClientSideNetUdp::stop() //Clear client this->_client.clearPackets(); this->_client.clearLostPacketCount(); - this->_client.setClientPacketCounter(0); + this->_client.resetAllCounters(); this->_client.setCurrentRealm(FGE_NET_DEFAULT_REALM); - this->_client.setCurrentPacketCounter(0); CryptClientDestroy(this->_client.getCryptInfo()); CryptUninit(this->g_crypt_ctx); @@ -209,7 +208,6 @@ ClientContext& ClientSideNetUdp::getClientContext() FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) { - ///TODO: no lock ? packet.reset(); if (this->_client.getStatus().isDisconnected()) @@ -261,31 +259,38 @@ FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) this->_client.acknowledgeReception(packet); } - auto const stat = PacketReorderer::checkStat(packet, this->_client.getCurrentPacketCounter(), + auto const stat = PacketReorderer::checkStat(packet, this->_client.getPacketCounter(Client::Targets::PEER), + this->_client.getReorderedPacketCounter(Client::Targets::PEER), this->_client.getCurrentRealm()); - if (!packet->checkFlags(FGE_NET_HEADER_DO_NOT_DISCARD_FLAG)) + bool const doNotDiscard = packet->checkFlags(FGE_NET_HEADER_DO_NOT_DISCARD_FLAG); + bool const doNotReorder = packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); + + if (!doNotDiscard) { if (stat == PacketReorderer::Stats::OLD_REALM || stat == PacketReorderer::Stats::OLD_COUNTER) { #ifdef FGE_DEF_DEBUG - auto const packetCounter = packet->retrieveCounter().value(); auto const packetRealm = packet->retrieveRealm().value(); - auto const currentCounter = this->_client.getCurrentPacketCounter(); + auto const packetCounter = packet->retrieveCounter().value(); + auto const packetReorderedCounter = packet->retrieveReorderedCounter().value(); + auto const peerCounter = this->_client.getPacketCounter(Client::Targets::PEER); + auto const peerReorderedCounter = this->_client.getReorderedPacketCounter(Client::Targets::PEER); #endif - FGE_DEBUG_PRINT("Packet is old, discarding it packetCounter: {}, packetRealm: {}, currentCounter: {}", - packetCounter, packetRealm, currentCounter); + FGE_DEBUG_PRINT("Packet is old, discarding it. Packet realm: {}, counter: {}, reorderedCounter: {}. Peer " + "counter: {}, reorderedCounter: {}", + packetRealm, packetCounter, packetReorderedCounter, peerCounter, peerReorderedCounter); this->_client.advanceLostPacketCount(); return FluxProcessResults::INTERNALLY_DISCARDED; } } - bool const doNotReorder = packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); if (!doNotReorder && !packet->isMarkedAsLocallyReordered()) { - auto reorderResult = - this->processReorder(this->g_clientContext._reorderer, packet, this->_client.getCurrentPacketCounter(), - this->_client.getCurrentRealm(), false); + auto reorderResult = this->processReorder( + this->g_clientContext._reorderer, packet, this->_client.getPacketCounter(Client::Targets::PEER), + this->_client.getReorderedPacketCounter(Client::Targets::PEER), this->_client.getCurrentRealm(), false); + if (reorderResult != FluxProcessResults::USER_RETRIEVABLE) { return reorderResult; @@ -304,22 +309,24 @@ FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) if (stat == PacketReorderer::Stats::WAITING_NEXT_REALM || stat == PacketReorderer::Stats::WAITING_NEXT_COUNTER) { #ifdef FGE_DEF_DEBUG - auto const packetCounter = packet->retrieveCounter().value(); auto const packetRealm = packet->retrieveRealm().value(); - auto const currentCounter = this->_client.getCurrentPacketCounter(); + auto const packetCounter = packet->retrieveCounter().value(); + auto const packetReorderedCounter = packet->retrieveReorderedCounter().value(); + auto const peerCounter = this->_client.getPacketCounter(Client::Targets::PEER); + auto const peerReorderedCounter = this->_client.getReorderedPacketCounter(Client::Targets::PEER); #endif - FGE_DEBUG_PRINT("We lose a packet packetCounter: {}, packetRealm: {}, currentCounter: {}", packetCounter, - packetRealm, currentCounter); + FGE_DEBUG_PRINT("We lose a packet. Packet realm: {}, counter: {}, reorderedCounter: {}. Peer counter: {}, " + "reorderedCounter: {}", + packetRealm, packetCounter, packetReorderedCounter, peerCounter, peerReorderedCounter); this->_client.advanceLostPacketCount(); //We are missing a packet } - if (!doNotReorder) - { - auto const serverCountId = packet->retrieveCounter().value(); - this->_client.setCurrentPacketCounter(serverCountId); - } - auto const serverRealm = packet->retrieveRealm().value(); - this->_client.setCurrentRealm(serverRealm); + auto const peerRealm = packet->retrieveRealm().value(); + this->_client.setCurrentRealm(peerRealm); + auto const peerCounter = packet->retrieveCounter().value(); + this->_client.setPacketCounter(Client::Targets::PEER, peerCounter); + auto const peerReorderedCounter = packet->retrieveReorderedCounter().value(); + this->_client.setReorderedPacketCounter(Client::Targets::PEER, peerReorderedCounter); return FluxProcessResults::USER_RETRIEVABLE; } diff --git a/sources/network/C_netCommand.cpp b/sources/network/C_netCommand.cpp index 406dc7e1..4eab7c10 100644 --- a/sources/network/C_netCommand.cpp +++ b/sources/network/C_netCommand.cpp @@ -372,8 +372,7 @@ void NetConnectCommand::internalUpdate(TransmitPacketPtr& buffPacket, FGE_DEBUG_PRINT("TX CONNECTED"); client.getStatus().setNetworkStatus(ClientStatus::NetworkStatus::CONNECTED); client.getStatus().setTimeout(FGE_NET_STATUS_DEFAULT_CONNECTED_TIMEOUT); - client.setClientPacketCounter(0); - client.setCurrentPacketCounter(0); + client.resetAllCounters(); this->g_promise.set_value(true); this->g_state = States::CONNECTED; this->markAsSucceeded(); @@ -434,8 +433,7 @@ void NetConnectCommand::internalUpdate(TransmitPacketPtr& buffPacket, FGE_DEBUG_PRINT("CONNECTED"); client.getStatus().setNetworkStatus(ClientStatus::NetworkStatus::CONNECTED); client.getStatus().setTimeout(FGE_NET_STATUS_DEFAULT_CONNECTED_TIMEOUT); - client.setClientPacketCounter(0); - client.setCurrentPacketCounter(0); + client.resetAllCounters(); this->g_promise.set_value(true); this->markAsSucceeded(); } @@ -599,8 +597,7 @@ void NetConnectHandlerCommand::internalUpdate(TransmitPacketPtr& buffPacket, FGE_DEBUG_PRINT("TX CONNECTED"); client.getStatus().setNetworkStatus(ClientStatus::NetworkStatus::CONNECTED); client.getStatus().setTimeout(FGE_NET_STATUS_DEFAULT_CONNECTED_TIMEOUT); - client.setClientPacketCounter(0); - client.setCurrentPacketCounter(0); + client.resetAllCounters(); this->g_promise.set_value(true); this->g_state = States::CONNECTED; this->markAsSucceeded(); @@ -661,9 +658,9 @@ void NetConnectHandlerCommand::internalUpdate(TransmitPacketPtr& buffPacket, FGE_DEBUG_PRINT("CONNECTED"); client.getStatus().setNetworkStatus(ClientStatus::NetworkStatus::CONNECTED); client.getStatus().setTimeout(FGE_NET_STATUS_DEFAULT_CONNECTED_TIMEOUT); - client.setClientPacketCounter(0); - client.setCurrentPacketCounter(0); + client.resetAllCounters(); this->g_promise.set_value(true); + this->g_state = States::CONNECTED; this->markAsSucceeded(); } break; diff --git a/sources/network/C_protocol.cpp b/sources/network/C_protocol.cpp index eb0cdad6..6cd8ee9d 100644 --- a/sources/network/C_protocol.cpp +++ b/sources/network/C_protocol.cpp @@ -270,32 +270,42 @@ void PacketReorderer::push(ReceivedPacketPtr&& packet) } } PacketReorderer::Stats PacketReorderer::checkStat(ReceivedPacketPtr const& packet, - ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType currentRealm) + ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType peerRealm) { - auto const lastCounter = packet->retrieveLastCounter().value(); - auto counter = packet->retrieveCounter().value(); - - counter = (counter == lastCounter) ? counter : (lastCounter + 1); - + auto const reorderedCounter = packet->retrieveReorderedCounter().value(); + auto const counter = packet->retrieveCounter().value(); auto const realm = packet->retrieveRealm().value(); - if (realm < currentRealm && currentRealm + 1 != 0) + auto const doNotReorderFlag = packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); + + if (realm < peerRealm && peerRealm + 1 != 0) { return Stats::OLD_REALM; } - if (currentRealm != realm && counter != 0) + if (peerRealm != realm && counter != 0) { //Different realm, we can switch to the new realm only if the counter is 0 (first packet of the new realm) return Stats::WAITING_NEXT_REALM; } - if (counter == currentCounter + 1) + if (doNotReorderFlag) + { + if (counter < peerCounter) + { //We are missing a packet + //TODO: we do not handle case where there is a overflow + return Stats::OLD_COUNTER; + } + return Stats::RETRIEVABLE; + } + + if (reorderedCounter == peerReorderedCounter + 1) { //Same realm, we can switch to the next counter return Stats::RETRIEVABLE; } - if (counter < currentCounter) + if (reorderedCounter < peerReorderedCounter) { //We are missing a packet return Stats::OLD_COUNTER; } @@ -307,15 +317,16 @@ bool PacketReorderer::isForced() const { return this->g_forceRetrieve; } -std::optional PacketReorderer::checkStat(ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType currentRealm) const +std::optional PacketReorderer::checkStat(ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType peerRealm) const { if (this->g_cache.empty()) { return std::nullopt; } - return this->g_cache.top().checkStat(currentCounter, currentRealm); + return this->g_cache.top().checkStat(peerCounter, peerReorderedCounter, peerRealm); } ReceivedPacketPtr PacketReorderer::pop() { @@ -353,13 +364,13 @@ std::size_t PacketReorderer::getMaximumSize() const PacketReorderer::Data::Data(ReceivedPacketPtr&& packet) : _packet(std::move(packet)), _counter(_packet->retrieveCounter().value()), - _lastCounter(_packet->retrieveLastCounter().value()), + _reorderedCounter(_packet->retrieveReorderedCounter().value()), _realm(_packet->retrieveRealm().value()) {} PacketReorderer::Data::Data(Data&& r) noexcept : _packet(std::move(r._packet)), _counter(r._counter), - _lastCounter(r._lastCounter), + _reorderedCounter(r._reorderedCounter), _realm(r._realm) {} PacketReorderer::Data::~Data() = default; @@ -368,43 +379,61 @@ PacketReorderer::Data& PacketReorderer::Data::operator=(Data&& r) noexcept { this->_packet = std::move(r._packet); this->_counter = r._counter; - this->_lastCounter = r._lastCounter; + this->_reorderedCounter = r._reorderedCounter; this->_realm = r._realm; return *this; } -PacketReorderer::Stats PacketReorderer::Data::checkStat(ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType currentRealm) const +PacketReorderer::Stats PacketReorderer::Data::checkStat(ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType peerRealm) const { - FGE_DEBUG_PRINT("PacketReorderer: currentCounter {}, currentRealm {}, packetCounter {}->{}, packetRealm {}", - currentCounter, currentRealm, this->_lastCounter, this->_counter, this->_realm); + FGE_DEBUG_PRINT("PacketReorderer::Data: Peer counters[{}/{}], realm {}. Packet counters[{}/{}], realm {}", + peerCounter, peerReorderedCounter, peerRealm, this->_counter, this->_reorderedCounter, + this->_realm); + + auto const doNotReorderFlag = this->_packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); - if (this->_realm < currentRealm && currentRealm + 1 != 0) + if (this->_realm < peerRealm && peerRealm + 1 != 0) { - FGE_DEBUG_PRINT("\tPacketReorderer: Old realm"); + FGE_DEBUG_PRINT("\tPacketReorderer::Data: Old realm"); return Stats::OLD_REALM; } - if (currentRealm != this->_realm && this->_counter != 0) + if (peerRealm != this->_realm && this->_counter != 0) { //Different realm, we can switch to the new realm only if the counter is 0 (first packet of the new realm) - FGE_DEBUG_PRINT("\tPacketReorderer: Different realm, we can switch to the new realm only if the counter is 0 " - "(first packet of the new realm)"); + FGE_DEBUG_PRINT( + "\tPacketReorderer::Data: Different realm, we can switch to the new realm only if the counter is 0 " + "(first packet of the new realm)"); return Stats::WAITING_NEXT_REALM; } - if (this->_lastCounter == currentCounter) + if (doNotReorderFlag) + { + if (this->_counter < peerCounter) + { //We are missing a packet + //TODO: we do not handle case where there is a overflow + FGE_DEBUG_PRINT("\tPacketReorderer::Data: [DNR] We are missing a packet"); + return Stats::OLD_COUNTER; + } + FGE_DEBUG_PRINT("\tPacketReorderer::Data: [DNR] Same realm, correct counter, retrievable"); + return Stats::RETRIEVABLE; + } + + if (this->_reorderedCounter == peerReorderedCounter + 1) { //Same realm, we can switch to the next counter - FGE_DEBUG_PRINT("\tPacketReorderer: Same realm, correct counter, retrievable"); + FGE_DEBUG_PRINT("\tPacketReorderer::Data: Same realm, correct counter, retrievable"); return Stats::RETRIEVABLE; } - if (this->_lastCounter < currentCounter) + if (this->_reorderedCounter < peerReorderedCounter) { //We are missing a packet - FGE_DEBUG_PRINT("\tPacketReorderer: We are missing a packet"); + FGE_DEBUG_PRINT("\tPacketReorderer::Data: We are missing a packet"); return Stats::OLD_COUNTER; } - FGE_DEBUG_PRINT("\tPacketReorderer: We can't switch to the next counter, we wait for the correct packet to arrive"); + FGE_DEBUG_PRINT( + "\tPacketReorderer::Data: We can't switch to the next counter, we wait for the correct packet to arrive"); //We can't switch to the next counter, we wait for the correct packet to arrive return Stats::WAITING_NEXT_COUNTER; } diff --git a/sources/network/C_server.cpp b/sources/network/C_server.cpp index 4297cb55..19f17095 100644 --- a/sources/network/C_server.cpp +++ b/sources/network/C_server.cpp @@ -189,15 +189,18 @@ void NetFluxUdp::forcePushPacketFront(ReceivedPacketPtr fluxPck) FluxProcessResults NetFluxUdp::processReorder(PacketReorderer& reorderer, ReceivedPacketPtr& packet, - ProtocolPacket::CounterType currentCounter, - ProtocolPacket::RealmType clientRealm, + ProtocolPacket::CounterType peerCounter, + ProtocolPacket::CounterType peerReorderedCounter, + ProtocolPacket::RealmType realm, bool ignoreRealm) { - auto currentRealm = ignoreRealm ? packet->retrieveRealm().value() : clientRealm; + //At this point, the packet must not have the DO_NOT_REORDER flag + + auto currentRealm = ignoreRealm ? packet->retrieveRealm().value() : realm; if (reorderer.isEmpty()) { - auto const stat = PacketReorderer::checkStat(packet, currentCounter, currentRealm); + auto const stat = PacketReorderer::checkStat(packet, peerCounter, peerReorderedCounter, currentRealm); if (stat == PacketReorderer::Stats::RETRIEVABLE) { @@ -215,7 +218,7 @@ FluxProcessResults NetFluxUdp::processReorder(PacketReorderer& reorderer, //At this point we are sure that the reorderer contains at least 2 packets bool forced = reorderer.isForced(); - auto const stat = reorderer.checkStat(currentCounter, currentRealm).value(); + auto const stat = reorderer.checkStat(peerCounter, peerReorderedCounter, currentRealm).value(); if (!forced && stat != PacketReorderer::Stats::RETRIEVABLE) { return FluxProcessResults::INTERNALLY_HANDLED; @@ -223,15 +226,16 @@ FluxProcessResults NetFluxUdp::processReorder(PacketReorderer& reorderer, packet = reorderer.pop(); packet->markAsLocallyReordered(); - currentCounter = packet->retrieveCounter().value(); + peerCounter = packet->retrieveCounter().value(); + peerReorderedCounter = packet->retrieveReorderedCounter().value(); currentRealm = packet->retrieveRealm().value(); auto const packerReordererMaxSize = reorderer.getMaximumSize(); - std::size_t containerInversedSize = 0; - auto* containerInversed = FGE_ALLOCA_T(ReceivedPacketPtr, packerReordererMaxSize); - FGE_PLACE_CONSTRUCT(ReceivedPacketPtr, packerReordererMaxSize, containerInversed); + std::size_t containerInvertedSize = 0; + auto* containerInverted = FGE_ALLOCA_T(ReceivedPacketPtr, packerReordererMaxSize); + FGE_PLACE_CONSTRUCT(ReceivedPacketPtr, packerReordererMaxSize, containerInverted); - while (auto const stat = reorderer.checkStat(currentCounter, currentRealm)) + while (auto const stat = reorderer.checkStat(peerCounter, peerReorderedCounter, currentRealm)) { if (!(stat == PacketReorderer::Stats::RETRIEVABLE || forced)) { @@ -243,21 +247,22 @@ FluxProcessResults NetFluxUdp::processReorder(PacketReorderer& reorderer, //Mark them as reordered reorderedPacket->markAsLocallyReordered(); - currentCounter = reorderedPacket->retrieveCounter().value(); + peerCounter = reorderedPacket->retrieveCounter().value(); + peerReorderedCounter = reorderedPacket->retrieveReorderedCounter().value(); currentRealm = reorderedPacket->retrieveRealm().value(); //Add it to the container (we are going to push in front of the flux queue, so we need to inverse the order) - containerInversed[containerInversedSize++] = std::move(reorderedPacket); + containerInverted[containerInvertedSize++] = std::move(reorderedPacket); } //Now we push the packets (until the last one) in the correct order in the flux queue - for (std::size_t i = containerInversedSize; i != 0; --i) + for (std::size_t i = containerInvertedSize; i != 0; --i) { - this->forcePushPacketFront(std::move(containerInversed[i - 1])); + this->forcePushPacketFront(std::move(containerInverted[i - 1])); ++this->_g_remainingPackets; } - FGE_PLACE_DESTRUCT(ReceivedPacketPtr, packerReordererMaxSize, containerInversed); + FGE_PLACE_DESTRUCT(ReceivedPacketPtr, packerReordererMaxSize, containerInverted); return FluxProcessResults::USER_RETRIEVABLE; } @@ -495,31 +500,37 @@ FluxProcessResults ServerNetFluxUdp::process(ClientSharedPtr& refClient, Receive return FluxProcessResults::INTERNALLY_DISCARDED; } - auto const stat = - PacketReorderer::checkStat(packet, refClient->getClientPacketCounter(), refClient->getCurrentRealm()); + auto const stat = PacketReorderer::checkStat(packet, refClient->getPacketCounter(Client::Targets::PEER), + refClient->getReorderedPacketCounter(Client::Targets::PEER), + refClient->getCurrentRealm()); + + bool const doNotDiscard = packet->checkFlags(FGE_NET_HEADER_DO_NOT_DISCARD_FLAG); + bool const doNotReorder = packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); - if (!packet->checkFlags(FGE_NET_HEADER_DO_NOT_DISCARD_FLAG)) + if (!doNotDiscard) { if (stat == PacketReorderer::Stats::OLD_COUNTER) { #ifdef FGE_DEF_DEBUG - auto const packetCounter = packet->retrieveCounter().value(); auto const packetRealm = packet->retrieveRealm().value(); - auto const currentCounter = refClient->getClientPacketCounter(); + auto const packetCounter = packet->retrieveCounter().value(); + auto const packetReorderedCounter = packet->retrieveReorderedCounter().value(); + auto const peerCounter = refClient->getPacketCounter(Client::Targets::PEER); + auto const peerReorderedCounter = refClient->getReorderedPacketCounter(Client::Targets::PEER); #endif - FGE_DEBUG_PRINT("Packet is old, discarding it packetCounter: {}, packetRealm: {}, currentCounter: {}", - packetCounter, packetRealm, currentCounter); + FGE_DEBUG_PRINT("Packet is old, discarding it. Packet realm: {}, counter: {}, reorderedCounter: {}. Peer " + "counter: {}, reorderedCounter: {}", + packetRealm, packetCounter, packetReorderedCounter, peerCounter, peerReorderedCounter); refClient->advanceLostPacketCount(); return FluxProcessResults::INTERNALLY_DISCARDED; } } - bool const doNotReorder = packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); if (!doNotReorder && !packet->isMarkedAsLocallyReordered()) { - auto reorderResult = - this->processReorder(refClient->_context._reorderer, packet, refClient->getClientPacketCounter(), - refClient->getCurrentRealm(), true); + auto reorderResult = this->processReorder( + refClient->_context._reorderer, packet, refClient->getPacketCounter(Client::Targets::PEER), + refClient->getReorderedPacketCounter(Client::Targets::PEER), refClient->getCurrentRealm(), true); if (reorderResult != FluxProcessResults::USER_RETRIEVABLE) { return reorderResult; @@ -536,20 +547,24 @@ FluxProcessResults ServerNetFluxUdp::process(ClientSharedPtr& refClient, Receive if (stat == PacketReorderer::Stats::WAITING_NEXT_REALM || stat == PacketReorderer::Stats::WAITING_NEXT_COUNTER) { #ifdef FGE_DEF_DEBUG - auto const packetCounter = packet->retrieveCounter().value(); auto const packetRealm = packet->retrieveRealm().value(); - auto const currentCounter = refClient->getClientPacketCounter(); + auto const packetCounter = packet->retrieveCounter().value(); + auto const packetReorderedCounter = packet->retrieveReorderedCounter().value(); + auto const peerCounter = refClient->getPacketCounter(Client::Targets::PEER); + auto const peerReorderedCounter = refClient->getReorderedPacketCounter(Client::Targets::PEER); #endif - FGE_DEBUG_PRINT("We lose a packet packetCounter: {}, packetRealm: {}, currentCounter: {}", packetCounter, - packetRealm, currentCounter); + FGE_DEBUG_PRINT("We lose a packet. Packet realm: {}, counter: {}, reorderedCounter: {}. Peer counter: {}, " + "reorderedCounter: {}", + packetRealm, packetCounter, packetReorderedCounter, peerCounter, peerReorderedCounter); refClient->advanceLostPacketCount(); //We are missing a packet } - if (!doNotReorder) - { - auto const countId = packet->retrieveCounter().value(); - refClient->setClientPacketCounter(countId); - } + auto const peerRealm = packet->retrieveRealm().value(); + refClient->setCurrentRealm(peerRealm); + auto const peerCounter = packet->retrieveCounter().value(); + refClient->setPacketCounter(Client::Targets::PEER, peerCounter); + auto const peerReorderedCounter = packet->retrieveReorderedCounter().value(); + refClient->setReorderedPacketCounter(Client::Targets::PEER, peerReorderedCounter); //Check if the packet is a return packet, and if so, handle it if (this->handleReturnPacket(refClient, refClient->_context, packet).has_value() || packet == nullptr) From eafcf2d17a5d105a737827e80ec90e8fccb189cd Mon Sep 17 00:00:00 2001 From: "GuillaumeG." Date: Mon, 19 Jan 2026 18:29:09 +0100 Subject: [PATCH 2/6] add process() options, add FGE_ENABLE_PACKET_DEBUG_VERBOSE, fixing --- CMakeLists.txt | 9 ++ includes/FastEngine/network/C_protocol.hpp | 9 +- includes/FastEngine/network/C_server.hpp | 12 +- sources/network/C_netClient.cpp | 131 +++++++++++++++------ sources/network/C_netServer.cpp | 11 +- sources/network/C_server.cpp | 15 ++- 6 files changed, 137 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 771e864c..e1aecf59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ option(FGE_BUILD_TESTS "Build tests" ON) option(FGE_ENABLE_SERVER_NETWORK_RANDOM_LOST "enable/disable random packet lost for server" OFF) option(FGE_ENABLE_CLIENT_NETWORK_RANDOM_LOST "enable/disable random packet lost for client" OFF) +option(FGE_ENABLE_PACKET_DEBUG_VERBOSE "enable/disable verbose packet debug printing" OFF) #Check if Doxygen is installed if (FGE_BUILD_DOC) @@ -184,6 +185,14 @@ if (${FGE_ENABLE_CLIENT_NETWORK_RANDOM_LOST}) endif() endif() +if (${FGE_ENABLE_PACKET_DEBUG_VERBOSE}) + target_compile_definitions(${FGE_LIB_NAME} PUBLIC FGE_ENABLE_PACKET_DEBUG_VERBOSE) + target_compile_definitions(${FGE_SERVER_LIB_NAME} PUBLIC FGE_ENABLE_PACKET_DEBUG_VERBOSE) + if (NOT ${FGE_DEBUG}) + message(WARNING "FGE_ENABLE_PACKET_DEBUG_VERBOSE is enabled, but FGE_DEBUG is disabled") + endif() +endif() + target_compile_definitions(${FGE_SERVER_LIB_NAME} PUBLIC FGE_DEF_SERVER) #Includes path diff --git a/includes/FastEngine/network/C_protocol.hpp b/includes/FastEngine/network/C_protocol.hpp index 0c535037..376d138e 100644 --- a/includes/FastEngine/network/C_protocol.hpp +++ b/includes/FastEngine/network/C_protocol.hpp @@ -42,14 +42,17 @@ #define FGE_NET_BAD_ID 0 -#define FGE_NET_PACKET_CACHE_DELAY_FACTOR 1.2f +#define FGE_NET_PACKET_CACHE_DELAY_FACTOR 2.2f #define FGE_NET_PACKET_CACHE_MAX 100 #define FGE_NET_PACKET_CACHE_MIN_LATENCY_MS 10 #define FGE_NET_DEFAULT_REALM 0 #define FGE_NET_DEFAULT_PACKET_REORDERER_CACHE_SIZE 5 #define FGE_NET_PACKET_REORDERER_CACHE_COMPUTE(_clientReturnRate, _serverTickRate) \ - (((_clientReturnRate) * FGE_NET_PACKET_CACHE_DELAY_FACTOR / (_serverTickRate) + 1) * 2) + ((static_cast(static_cast(_clientReturnRate) * FGE_NET_PACKET_CACHE_DELAY_FACTOR / \ + static_cast(_serverTickRate)) + \ + 1) * \ + 2) #define FGE_NET_HANDSHAKE_STRING "FGE:HANDSHAKE:AZCgMVg4d4Sl2xYvZcqXqljIOqSrKX6H" @@ -398,7 +401,7 @@ class FGE_API PacketReorderer { if (l._realm == r._realm) { - return l._counter > r._counter; + return l._reorderedCounter > r._reorderedCounter; } return l._realm > r._realm; } diff --git a/includes/FastEngine/network/C_server.hpp b/includes/FastEngine/network/C_server.hpp index abb0f2ae..280c6f71 100644 --- a/includes/FastEngine/network/C_server.hpp +++ b/includes/FastEngine/network/C_server.hpp @@ -19,10 +19,10 @@ #include "FastEngine/fge_extern.hpp" #include "C_socket.hpp" +#include "FastEngine/C_flag.hpp" #include "FastEngine/network/C_clientList.hpp" #include "FastEngine/network/C_netCommand.hpp" #include "FastEngine/network/C_packet.hpp" -#include "FastEngine/network/C_packetLZ4.hpp" #include "FastEngine/network/C_protocol.hpp" #include #include @@ -31,6 +31,7 @@ #include #include + #if defined(FGE_ENABLE_SERVER_NETWORK_RANDOM_LOST) || defined(FGE_ENABLE_CLIENT_NETWORK_RANDOM_LOST) #include "FastEngine/C_random.hpp" #endif @@ -328,7 +329,14 @@ class FGE_API ClientSideNetUdp : public NetFluxUdp template void sendTo(TransmitPacketPtr& pck, Identity const& id); - [[nodiscard]] FluxProcessResults process(ReceivedPacketPtr& packet); + enum ProcessOptions : uint32_t + { + OPTION_NONE = 0, + OPTION_NO_TIMEOUT = 1 << 0, + OPTION_ONE_SHOT = 1 << 1 + }; + [[nodiscard]] FluxProcessResults process(ReceivedPacketPtr& packet, + EnumFlags options = OPTION_NONE); void resetReturnPacket(); TransmitPacketPtr& startReturnEvent(ReturnEvents event); diff --git a/sources/network/C_netClient.cpp b/sources/network/C_netClient.cpp index 646fd756..6c0fa0d9 100644 --- a/sources/network/C_netClient.cpp +++ b/sources/network/C_netClient.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "FastEngine/C_compressorLZ4.hpp" #include "FastEngine/manager/network_manager.hpp" #include "FastEngine/network/C_server.hpp" #include "private/fge_crypt.hpp" @@ -206,7 +207,7 @@ ClientContext& ClientSideNetUdp::getClientContext() return this->g_clientContext; } -FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) +FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet, EnumFlags options) { packet.reset(); @@ -216,46 +217,74 @@ FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) return FluxProcessResults::NONE_AVAILABLE; } - //Checking timeout - if (this->_client.getStatus().isTimeout()) + if (options.has(OPTION_ONE_SHOT)) { - this->_client.getStatus().setNetworkStatus(ClientStatus::NetworkStatus::TIMEOUT); - this->_g_remainingPackets = 0; - this->clearPackets(); - this->_onClientTimeout.call(*this); - return FluxProcessResults::NONE_AVAILABLE; + options.set(OPTION_NO_TIMEOUT); } - //Checking return packet - if (this->isReturnPacketEnabled()) + //Checking timeout + if (!options.has(OPTION_NO_TIMEOUT)) { - auto const now = std::chrono::steady_clock::now(); - if (now - this->g_returnPacketTimePoint >= this->_client.getPacketReturnRate()) + if (this->_client.getStatus().isTimeout()) { - this->g_returnPacketTimePoint = now; - auto returnPacket = this->prepareAndRetrieveReturnPacket(); - this->_onTransmitReturnPacket.call(*this, returnPacket); - this->_client.pushPacket(std::move(returnPacket)); + this->_client.getStatus().setNetworkStatus(ClientStatus::NetworkStatus::TIMEOUT); + this->_g_remainingPackets = 0; + this->clearPackets(); + this->_onClientTimeout.call(*this); + return FluxProcessResults::NONE_AVAILABLE; } } - if (this->_g_remainingPackets == 0) + //Checking return packet + if (!options.has(OPTION_ONE_SHOT)) { - this->_g_remainingPackets = this->getPacketsSize(); - return FluxProcessResults::NONE_AVAILABLE; - } + if (this->isReturnPacketEnabled()) + { + auto const now = std::chrono::steady_clock::now(); + if (now - this->g_returnPacketTimePoint >= this->_client.getPacketReturnRate()) + { + this->g_returnPacketTimePoint = now; + auto returnPacket = this->prepareAndRetrieveReturnPacket(); + this->_onTransmitReturnPacket.call(*this, returnPacket); + this->_client.pushPacket(std::move(returnPacket)); + } + } - //Popping the next packet - packet = this->popNextPacket(); - if (!packet) + if (this->_g_remainingPackets == 0) + { + this->_g_remainingPackets = this->getPacketsSize(); + return FluxProcessResults::NONE_AVAILABLE; + } + + //Popping the next packet + packet = this->popNextPacket(); + if (!packet) + { + this->_g_remainingPackets = this->getPacketsSize(); + return FluxProcessResults::NONE_AVAILABLE; + } + --this->_g_remainingPackets; + } + else { - this->_g_remainingPackets = this->getPacketsSize(); - return FluxProcessResults::NONE_AVAILABLE; + packet = this->popNextPacket(); + if (!packet) + { + return FluxProcessResults::NONE_AVAILABLE; + } } - --this->_g_remainingPackets; + +#ifdef FGE_ENABLE_PACKET_DEBUG_VERBOSE + auto const counter = packet->retrieveCounter().value(); + auto const reorderedCounter = packet->retrieveReorderedCounter().value(); + FGE_DEBUG_PRINT("Checking packet [{}/{}]", counter, reorderedCounter); +#endif if (!packet->isMarkedAsLocallyReordered()) { +#ifdef FGE_ENABLE_PACKET_DEBUG_VERBOSE + FGE_DEBUG_PRINT("Acknowledging reception of packet [{}/{}]", counter, reorderedCounter); +#endif this->_client.acknowledgeReception(packet); } @@ -266,6 +295,10 @@ FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) bool const doNotDiscard = packet->checkFlags(FGE_NET_HEADER_DO_NOT_DISCARD_FLAG); bool const doNotReorder = packet->checkFlags(FGE_NET_HEADER_DO_NOT_REORDER_FLAG); +#ifdef FGE_ENABLE_PACKET_DEBUG_VERBOSE + FGE_DEBUG_PRINT("Packet is doNotDiscard {} and doNotReorder {}", doNotDiscard, doNotReorder); +#endif + if (!doNotDiscard) { if (stat == PacketReorderer::Stats::OLD_REALM || stat == PacketReorderer::Stats::OLD_COUNTER) @@ -287,13 +320,22 @@ FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) if (!doNotReorder && !packet->isMarkedAsLocallyReordered()) { - auto reorderResult = this->processReorder( - this->g_clientContext._reorderer, packet, this->_client.getPacketCounter(Client::Targets::PEER), - this->_client.getReorderedPacketCounter(Client::Targets::PEER), this->_client.getCurrentRealm(), false); - - if (reorderResult != FluxProcessResults::USER_RETRIEVABLE) + if (!(doNotDiscard && + (stat == PacketReorderer::Stats::OLD_REALM || stat == PacketReorderer::Stats::OLD_COUNTER))) { - return reorderResult; + auto reorderResult = this->processReorder(this->g_clientContext._reorderer, packet, + this->_client.getPacketCounter(Client::Targets::PEER), + this->_client.getReorderedPacketCounter(Client::Targets::PEER), + this->_client.getCurrentRealm(), false); + + if (reorderResult != FluxProcessResults::USER_RETRIEVABLE) + { +#ifdef FGE_ENABLE_PACKET_DEBUG_VERBOSE + auto const re = static_cast(reorderResult); + FGE_DEBUG_PRINT("Packet goes into the reorderer, result: {}", re); +#endif + return reorderResult; + } } } @@ -321,12 +363,25 @@ FluxProcessResults ClientSideNetUdp::process(ReceivedPacketPtr& packet) this->_client.advanceLostPacketCount(); //We are missing a packet } - auto const peerRealm = packet->retrieveRealm().value(); - this->_client.setCurrentRealm(peerRealm); - auto const peerCounter = packet->retrieveCounter().value(); - this->_client.setPacketCounter(Client::Targets::PEER, peerCounter); - auto const peerReorderedCounter = packet->retrieveReorderedCounter().value(); - this->_client.setReorderedPacketCounter(Client::Targets::PEER, peerReorderedCounter); + if (stat != PacketReorderer::Stats::OLD_REALM && stat != PacketReorderer::Stats::OLD_COUNTER) + { +#ifdef FGE_ENABLE_PACKET_DEBUG_VERBOSE + auto const wasRealm = this->_client.getCurrentRealm(); + auto const wasCounter = this->_client.getPacketCounter(Client::Targets::PEER); + auto const wasReorderedCounter = this->_client.getReorderedPacketCounter(Client::Targets::PEER); + FGE_DEBUG_PRINT("Was : realm {}, counter {}, reorderedCounter {}", wasRealm, wasCounter, wasReorderedCounter); +#endif + auto const peerRealm = packet->retrieveRealm().value(); + this->_client.setCurrentRealm(peerRealm); + auto const peerCounter = packet->retrieveCounter().value(); + this->_client.setPacketCounter(Client::Targets::PEER, peerCounter); + auto const peerReorderedCounter = packet->retrieveReorderedCounter().value(); + this->_client.setReorderedPacketCounter(Client::Targets::PEER, peerReorderedCounter); +#ifdef FGE_ENABLE_PACKET_DEBUG_VERBOSE + FGE_DEBUG_PRINT("Updating peer state to realm {}, counter {}, reorderedCounter {}", peerRealm, peerCounter, + peerReorderedCounter); +#endif + } return FluxProcessResults::USER_RETRIEVABLE; } diff --git a/sources/network/C_netServer.cpp b/sources/network/C_netServer.cpp index 099efba5..a47b9a16 100644 --- a/sources/network/C_netServer.cpp +++ b/sources/network/C_netServer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "FastEngine/C_compressorLZ4.hpp" #include "FastEngine/manager/network_manager.hpp" #include "FastEngine/network/C_server.hpp" #include "private/fge_crypt.hpp" @@ -378,8 +379,16 @@ void ServerSideNetUdp::threadTransmission() while (client->_context._cache.check( timePoint, std::chrono::duration_cast(clientLatency))) { - FGE_DEBUG_PRINT("re-transmit packet as client didn't acknowledge it"); +#ifdef FGE_DEF_DEBUG + auto packet = client->_context._cache.pop(); + auto const counter = packet->retrieveCounter().value(); + auto const reorderedCounter = packet->retrieveReorderedCounter().value(); + FGE_DEBUG_PRINT("re-transmit packet [{}/{}] as client didn't acknowledge it", counter, + reorderedCounter); + client->pushForcedFrontPacket(std::move(packet)); +#else client->pushForcedFrontPacket(client->_context._cache.pop()); +#endif } } diff --git a/sources/network/C_server.cpp b/sources/network/C_server.cpp index 19f17095..414f6930 100644 --- a/sources/network/C_server.cpp +++ b/sources/network/C_server.cpp @@ -559,12 +559,15 @@ FluxProcessResults ServerNetFluxUdp::process(ClientSharedPtr& refClient, Receive refClient->advanceLostPacketCount(); //We are missing a packet } - auto const peerRealm = packet->retrieveRealm().value(); - refClient->setCurrentRealm(peerRealm); - auto const peerCounter = packet->retrieveCounter().value(); - refClient->setPacketCounter(Client::Targets::PEER, peerCounter); - auto const peerReorderedCounter = packet->retrieveReorderedCounter().value(); - refClient->setReorderedPacketCounter(Client::Targets::PEER, peerReorderedCounter); + if (stat != PacketReorderer::Stats::OLD_REALM && stat != PacketReorderer::Stats::OLD_COUNTER) + { + auto const peerRealm = packet->retrieveRealm().value(); + refClient->setCurrentRealm(peerRealm); + auto const peerCounter = packet->retrieveCounter().value(); + refClient->setPacketCounter(Client::Targets::PEER, peerCounter); + auto const peerReorderedCounter = packet->retrieveReorderedCounter().value(); + refClient->setReorderedPacketCounter(Client::Targets::PEER, peerReorderedCounter); + } //Check if the packet is a return packet, and if so, handle it if (this->handleReturnPacket(refClient, refClient->_context, packet).has_value() || packet == nullptr) From a6b45fa403c45fc88120075b08d06fae1cc52816 Mon Sep 17 00:00:00 2001 From: "GuillaumeG." Date: Tue, 20 Jan 2026 21:40:07 +0100 Subject: [PATCH 3/6] WIP: change PacketCache to pause transmission when packet can't be sent - Not an circular buffer anymore - Add a try count to packets inside the cache - Currently there is now a problem with the client reorder WIP - Client: add isReadyToAcceptMorePendingPackets() it should now be used instead of isPendingPacketsEmpty() --- .../server/main.cpp | 2 +- includes/FastEngine/network/C_client.hpp | 4 + includes/FastEngine/network/C_protocol.hpp | 14 +- sources/network/C_client.cpp | 11 ++ sources/network/C_netServer.cpp | 21 +-- sources/network/C_protocol.cpp | 162 +++++++++--------- 6 files changed, 105 insertions(+), 109 deletions(-) diff --git a/examples/clientServerLifeSimulator_004/server/main.cpp b/examples/clientServerLifeSimulator_004/server/main.cpp index 5e5d0dcb..b7324819 100644 --- a/examples/clientServerLifeSimulator_004/server/main.cpp +++ b/examples/clientServerLifeSimulator_004/server/main.cpp @@ -343,7 +343,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) } //Make sure that the client is not busy with another packet - if (!it->second->isPendingPacketsEmpty()) + if (!it->second->isReadyToAcceptMorePendingPackets()) { continue; } diff --git a/includes/FastEngine/network/C_client.hpp b/includes/FastEngine/network/C_client.hpp index 5ab68ef5..d45cf8d7 100644 --- a/includes/FastEngine/network/C_client.hpp +++ b/includes/FastEngine/network/C_client.hpp @@ -379,6 +379,7 @@ class FGE_API Client */ void pushPacket(TransmitPacketPtr pck); void pushForcedFrontPacket(TransmitPacketPtr pck); + [[nodiscard]] bool isReadyToAcceptMorePendingPackets() const; /** * \brief Pop a packet from the queue * @@ -391,6 +392,7 @@ class FGE_API Client * \return True if the queue is empty, false otherwise */ bool isPendingPacketsEmpty() const; + void allowMorePendingPackets(bool allow); void disconnect(bool pushDisconnectPacket = true); @@ -466,6 +468,8 @@ class FGE_API Client ClientStatus g_status; CryptInfo g_cryptInfo; + + bool g_allowMorePackets{true}; }; /** diff --git a/includes/FastEngine/network/C_protocol.hpp b/includes/FastEngine/network/C_protocol.hpp index 376d138e..d8433c23 100644 --- a/includes/FastEngine/network/C_protocol.hpp +++ b/includes/FastEngine/network/C_protocol.hpp @@ -444,7 +444,7 @@ class FGE_API PacketCache }; }; - PacketCache() = default; + PacketCache(); PacketCache(PacketCache const& r) = delete; PacketCache(PacketCache&& r) noexcept; ~PacketCache() = default; @@ -455,6 +455,7 @@ class FGE_API PacketCache void clear(); [[nodiscard]] bool isEmpty() const; [[nodiscard]] bool isEnabled() const; + [[nodiscard]] bool isAlarmed() const; void enable(bool enable); //Transmit @@ -464,9 +465,7 @@ class FGE_API PacketCache void acknowledgeReception(std::span