From bfd603169b194a94cee2a14646bc8ae7906c66f5 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 7 Sep 2026 11:46:58 +0200 Subject: [PATCH] Fix `ENet` network driver to use 3 separate channels for different packet types --- .../Engine/Networking/Drivers/ENetDriver.cpp | 43 ++++++++++++++++--- Source/Engine/Networking/NetworkPeer.cpp | 2 +- Source/Engine/Networking/NetworkPeer.h | 6 --- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/Source/Engine/Networking/Drivers/ENetDriver.cpp b/Source/Engine/Networking/Drivers/ENetDriver.cpp index a89e1b83b..c5dc00681 100644 --- a/Source/Engine/Networking/Drivers/ENetDriver.cpp +++ b/Source/Engine/Networking/Drivers/ENetDriver.cpp @@ -10,6 +10,7 @@ #include "Engine/Networking/NetworkStats.h" #include "Engine/Core/Log.h" #include "Engine/Core/Collections/Array.h" +#include "Engine/Profiler/ProfilerCPU.h" #define ENET_IMPLEMENTATION #define _WINSOCK_DEPRECATED_NO_WARNINGS #include @@ -25,14 +26,34 @@ ENetPacketFlag ChannelTypeToPacketFlag(const NetworkChannelType channel) flag |= ENET_PACKET_FLAG_RELIABLE; // Use unsequenced flag when the flag is unreliable. We have to sequence all other packets. + // Note: ENet has no "unreliable ordered" channel type, so we have to use reliable for that. if (channel == NetworkChannelType::Unreliable) flag |= ENET_PACKET_FLAG_UNSEQUENCED; - // Note that all reliable channels are exactly the same. TODO: How to handle unordered reliable packets...? - return static_cast(flag); } +// Unreliable - 0 +// UnreliableOrdered - 1 +// Reliable/ReliableOrdered - 2 +#define ENET_CHANNEL_COUNT 3 + +enet_uint8 ChannelTypeToChannelIndex(const NetworkChannelType channel) +{ + switch (channel) + { + case NetworkChannelType::Unreliable: + return 0; + case NetworkChannelType::UnreliableOrdered: + return 1; + case NetworkChannelType::Reliable: + case NetworkChannelType::ReliableOrdered: + return 2; + default: + return 0; + } +} + void SendPacketToPeer(ENetPeer* peer, const NetworkChannelType channelType, const NetworkMessage& message) { // Covert our channel type to the internal ENet packet flags @@ -45,7 +66,7 @@ void SendPacketToPeer(ENetPeer* peer, const NetworkChannelType channelType, cons ENetPacket* packet = enet_packet_create(message.Buffer, message.Position, flag); // And send it! - enet_peer_send(peer, 0, packet); + enet_peer_send(peer, ChannelTypeToChannelIndex(channelType), packet); // TODO: To reduce latency, we can use `enet_host_flush` to flush all packets. Maybe some API, like NetworkManager::FlushQueues()? } @@ -57,6 +78,7 @@ ENetDriver::ENetDriver(const SpawnParams& params) bool ENetDriver::Initialize(NetworkPeer* host, const NetworkConfig& config) { + PROFILE_CPU(); _networkHost = host; _config = config; _peerMap.Clear(); @@ -73,6 +95,7 @@ bool ENetDriver::Initialize(NetworkPeer* host, const NetworkConfig& config) void ENetDriver::Dispose() { + PROFILE_CPU(); if (_peer) enet_peer_disconnect_now(_peer, 0); enet_host_destroy(_host); @@ -89,6 +112,7 @@ void ENetDriver::Dispose() bool ENetDriver::Listen() { + PROFILE_CPU(); ENetAddress address = { 0 }; address.port = _config.Port; address.host = ENET_HOST_ANY; @@ -98,7 +122,7 @@ bool ENetDriver::Listen() enet_address_set_host(&address, _config.Address.ToStringAnsi().GetText()); // Create ENet host - _host = enet_host_create(&address, _config.ConnectionsLimit, 1, 0, 0); + _host = enet_host_create(&address, _config.ConnectionsLimit, ENET_CHANNEL_COUNT, 0, 0); if (_host == nullptr) { LOG(Error, "Failed to initialize ENet host!"); @@ -111,6 +135,7 @@ bool ENetDriver::Listen() bool ENetDriver::Connect() { + PROFILE_CPU(); LOG(Info, "Connecting using ENet..."); ENetAddress address = { 0 }; @@ -118,7 +143,7 @@ bool ENetDriver::Connect() enet_address_set_host(&address, _config.Address.ToStringAnsi().GetText()); // Create ENet host - _host = enet_host_create(nullptr, 1, 1, 0, 0); + _host = enet_host_create(nullptr, 1, ENET_CHANNEL_COUNT, 0, 0); if (_host == nullptr) { LOG(Error, "Failed to initialize ENet host!"); @@ -126,7 +151,7 @@ bool ENetDriver::Connect() } // Create ENet peer/connect to the server - _peer = enet_host_connect(_host, &address, 1, 0); + _peer = enet_host_connect(_host, &address, ENET_CHANNEL_COUNT, 0); if (_peer == nullptr) { LOG(Error, "Failed to create ENet host!"); @@ -139,6 +164,7 @@ bool ENetDriver::Connect() void ENetDriver::Disconnect() { + PROFILE_CPU(); if (_peer) { enet_peer_disconnect_now(_peer, 0); @@ -149,6 +175,7 @@ void ENetDriver::Disconnect() void ENetDriver::Disconnect(const NetworkConnection& connection) { + PROFILE_CPU(); const int connectionId = connection.ConnectionId; ENetPeer* peer; if (_peerMap.TryGet(connectionId, peer)) @@ -164,6 +191,7 @@ void ENetDriver::Disconnect(const NetworkConnection& connection) bool ENetDriver::PopEvent(NetworkEvent& eventPtr) { + PROFILE_CPU(); ASSERT(_host); ENetEvent event; const int result = enet_host_service(_host, &event, 0); @@ -215,12 +243,14 @@ bool ENetDriver::PopEvent(NetworkEvent& eventPtr) void ENetDriver::SendMessage(const NetworkChannelType channelType, const NetworkMessage& message) { + PROFILE_CPU(); ASSERT(!IsServer()); SendPacketToPeer(_peer, channelType, message); } void ENetDriver::SendMessage(NetworkChannelType channelType, const NetworkMessage& message, NetworkConnection target) { + PROFILE_CPU(); ASSERT(IsServer()); ENetPeer* peer; if (_peerMap.TryGet(target.ConnectionId, peer) && peer && peer->state == ENET_PEER_STATE_CONNECTED) @@ -231,6 +261,7 @@ void ENetDriver::SendMessage(NetworkChannelType channelType, const NetworkMessag void ENetDriver::SendMessage(const NetworkChannelType channelType, const NetworkMessage& message, const Array& targets) { + PROFILE_CPU(); ASSERT(IsServer()); ENetPeer* peer; for (NetworkConnection target : targets) diff --git a/Source/Engine/Networking/NetworkPeer.cpp b/Source/Engine/Networking/NetworkPeer.cpp index 558ea6aa7..7033be1ef 100644 --- a/Source/Engine/Networking/NetworkPeer.cpp +++ b/Source/Engine/Networking/NetworkPeer.cpp @@ -141,7 +141,7 @@ NetworkMessage NetworkPeer::CreateMessage() { CHECK_RETURN(MessagePool.HasItems(), NetworkMessage()); const uint32 messageId = MessagePool.Pop(); - uint8* messageBuffer = GetMessageBuffer(messageId); + uint8* messageBuffer = (uint8*)MessageBuffer + Config.MessageSize * messageId; return NetworkMessage(messageBuffer, Config.MessageSize, messageId); } diff --git a/Source/Engine/Networking/NetworkPeer.h b/Source/Engine/Networking/NetworkPeer.h index ad64fe163..12fbab887 100644 --- a/Source/Engine/Networking/NetworkPeer.h +++ b/Source/Engine/Networking/NetworkPeer.h @@ -144,12 +144,6 @@ public: return NetworkDriver != nullptr && HostId >= 0; } - uint8* GetMessageBuffer(const uint32 messageId) const - { - // Calculate and return the buffer slice using previously calculated slice. - return MessageBuffer + Config.MessageSize * messageId; - } - public: FORCE_INLINE bool operator==(const NetworkPeer& other) const {