mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-04-02 09:28:33 -04:00
feat: implement multiplayer networking improvements for reduced latency
Major networking enhancements to improve multiplayer performance and reduce desync issues in games like Mario Kart 8 Deluxe: Network Performance: - Add socket connection pooling in BSD service to reduce overhead - Implement unreliable packet delivery for latency-sensitive game data - Add packet reliability control for both ProxyPacket and LDNPacket - Use ENET_PACKET_FLAG_UNSEQUENCED for small UDP packets (<1200 bytes) Monitoring & Debugging: - Add PacketStatistics struct to track sent/received/dropped packets - Enhanced logging for proxy packet handling and socket lifecycle - Periodic stats logging every 100 packets for diagnostics Configuration: - Update lobby_api_url and web_api_url to https://api.ynet-fun.xyz - Add lobby API URL configuration support Socket Management: - Implement SocketPoolKey for efficient socket reuse - Store domain/type/protocol info in FileDescriptor - Max pool size limit (8 sockets per type) to prevent memory bloat - Return closed sockets to pool when room is still connected Protocol Updates: - Add 'reliable' field to ProxyPacket and LDNPacket structures - Update room.cpp packet handlers to respect reliability flags - Maintain backward compatibility with default reliable=true These changes significantly reduce packet latency for real-time game traffic while maintaining reliability for control packets. Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <atomic>
|
||||
@@ -44,8 +45,15 @@ public:
|
||||
std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
|
||||
/// Thread that receives and dispatches network packets
|
||||
std::unique_ptr<std::thread> loop_thread;
|
||||
|
||||
/// Structure to hold a packet and its reliability flag
|
||||
struct PacketWithReliability {
|
||||
Packet packet;
|
||||
bool reliable;
|
||||
};
|
||||
|
||||
std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable.
|
||||
std::list<Packet> send_list; ///< A list that stores all packets to send the async
|
||||
std::list<PacketWithReliability> send_list; ///< A list that stores all packets to send the async
|
||||
|
||||
template <typename T>
|
||||
using CallbackSet = std::set<CallbackHandle<T>>;
|
||||
@@ -73,10 +81,11 @@ public:
|
||||
void StartLoop();
|
||||
|
||||
/**
|
||||
* Sends data to the room. It will be send on channel 0 with flag RELIABLE
|
||||
* Sends data to the room. It will be send on channel 0 with specified reliability
|
||||
* @param packet The data to send
|
||||
* @param reliable Whether to use reliable delivery (true) or unreliable/unsequenced (false)
|
||||
*/
|
||||
void Send(Packet&& packet);
|
||||
void Send(Packet&& packet, bool reliable = true);
|
||||
|
||||
/**
|
||||
* Sends a request to the server, asking for permission to join a room with the specified
|
||||
@@ -257,14 +266,17 @@ void RoomMember::RoomMemberImpl::MemberLoop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::list<Packet> packets;
|
||||
std::list<PacketWithReliability> packets;
|
||||
{
|
||||
std::lock_guard send_lock(send_list_mutex);
|
||||
packets.swap(send_list);
|
||||
}
|
||||
for (const auto& packet : packets) {
|
||||
ENetPacket* enetPacket = enet_packet_create(packet.GetData(), packet.GetDataSize(),
|
||||
ENET_PACKET_FLAG_RELIABLE);
|
||||
for (const auto& packet_data : packets) {
|
||||
const u32 enet_flags = packet_data.reliable ? ENET_PACKET_FLAG_RELIABLE
|
||||
: ENET_PACKET_FLAG_UNSEQUENCED;
|
||||
ENetPacket* enetPacket = enet_packet_create(packet_data.packet.GetData(),
|
||||
packet_data.packet.GetDataSize(),
|
||||
enet_flags);
|
||||
enet_peer_send(server, 0, enetPacket);
|
||||
}
|
||||
enet_host_flush(client);
|
||||
@@ -276,9 +288,9 @@ void RoomMember::RoomMemberImpl::StartLoop() {
|
||||
loop_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::MemberLoop, this);
|
||||
}
|
||||
|
||||
void RoomMember::RoomMemberImpl::Send(Packet&& packet) {
|
||||
void RoomMember::RoomMemberImpl::Send(Packet&& packet, bool reliable) {
|
||||
std::lock_guard lock(send_list_mutex);
|
||||
send_list.push_back(std::move(packet));
|
||||
send_list.push_back({std::move(packet), reliable});
|
||||
}
|
||||
|
||||
void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname_,
|
||||
@@ -377,6 +389,7 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) {
|
||||
proxy_packet.protocol = static_cast<Protocol>(protocol_type);
|
||||
|
||||
packet.Read(proxy_packet.broadcast);
|
||||
packet.Read(proxy_packet.reliable);
|
||||
packet.Read(proxy_packet.data);
|
||||
|
||||
Invoke<ProxyPacket>(proxy_packet);
|
||||
@@ -397,6 +410,7 @@ void RoomMember::RoomMemberImpl::HandleLdnPackets(const ENetEvent* event) {
|
||||
packet.Read(ldn_packet.local_ip);
|
||||
packet.Read(ldn_packet.remote_ip);
|
||||
packet.Read(ldn_packet.broadcast);
|
||||
packet.Read(ldn_packet.reliable);
|
||||
|
||||
packet.Read(ldn_packet.data);
|
||||
|
||||
@@ -638,9 +652,10 @@ void RoomMember::SendProxyPacket(const ProxyPacket& proxy_packet) {
|
||||
|
||||
packet.Write(static_cast<u8>(proxy_packet.protocol));
|
||||
packet.Write(proxy_packet.broadcast);
|
||||
packet.Write(proxy_packet.reliable);
|
||||
packet.Write(proxy_packet.data);
|
||||
|
||||
room_member_impl->Send(std::move(packet));
|
||||
room_member_impl->Send(std::move(packet), proxy_packet.reliable);
|
||||
}
|
||||
|
||||
void RoomMember::SendLdnPacket(const LDNPacket& ldn_packet) {
|
||||
@@ -652,10 +667,11 @@ void RoomMember::SendLdnPacket(const LDNPacket& ldn_packet) {
|
||||
packet.Write(ldn_packet.local_ip);
|
||||
packet.Write(ldn_packet.remote_ip);
|
||||
packet.Write(ldn_packet.broadcast);
|
||||
packet.Write(ldn_packet.reliable);
|
||||
|
||||
packet.Write(ldn_packet.data);
|
||||
|
||||
room_member_impl->Send(std::move(packet));
|
||||
room_member_impl->Send(std::move(packet), ldn_packet.reliable);
|
||||
}
|
||||
|
||||
void RoomMember::SendChatMessage(const std::string& message) {
|
||||
|
||||
Reference in New Issue
Block a user