From 1d338abe3b2536656d68a62747c04cb24f972b26 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 7 May 2023 17:39:38 +1000 Subject: [PATCH] Netplay: Use enet for disconnections --- dep/ggpo-x/include/ggponet.h | 7 +- dep/ggpo-x/src/backends/p2p.cpp | 67 +----------------- dep/ggpo-x/src/backends/p2p.h | 4 -- dep/ggpo-x/src/backends/spectator.cpp | 19 ----- dep/ggpo-x/src/network/udp_msg.h | 9 +-- dep/ggpo-x/src/network/udp_proto.cpp | 99 ++++----------------------- dep/ggpo-x/src/network/udp_proto.h | 11 --- src/core/netplay.cpp | 17 ++--- 8 files changed, 23 insertions(+), 210 deletions(-) diff --git a/dep/ggpo-x/include/ggponet.h b/dep/ggpo-x/include/ggponet.h index 6da527395..88b99346c 100644 --- a/dep/ggpo-x/include/ggponet.h +++ b/dep/ggpo-x/include/ggponet.h @@ -150,11 +150,8 @@ typedef enum { GGPO_EVENTCODE_SYNCHRONIZING_WITH_PEER = 1001, GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER = 1002, GGPO_EVENTCODE_RUNNING = 1003, - GGPO_EVENTCODE_DISCONNECTED_FROM_PEER = 1004, - GGPO_EVENTCODE_TIMESYNC = 1005, - GGPO_EVENTCODE_CONNECTION_INTERRUPTED = 1006, - GGPO_EVENTCODE_CONNECTION_RESUMED = 1007, - GGPO_EVENTCODE_DESYNC = 1008 + GGPO_EVENTCODE_TIMESYNC = 1004, + GGPO_EVENTCODE_DESYNC = 1006 } GGPOEventCode; /* diff --git a/dep/ggpo-x/src/backends/p2p.cpp b/dep/ggpo-x/src/backends/p2p.cpp index dbffe9d67..ae3a3e3b0 100644 --- a/dep/ggpo-x/src/backends/p2p.cpp +++ b/dep/ggpo-x/src/backends/p2p.cpp @@ -8,8 +8,6 @@ #include "p2p.h" static const int RECOMMENDATION_INTERVAL = 120; -static const int DEFAULT_DISCONNECT_TIMEOUT = 5000; -static const int DEFAULT_DISCONNECT_NOTIFY_START = 750; Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, const char *gamename, @@ -19,8 +17,6 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, _num_players(num_players), _input_size(input_size), _sync(_local_connect_status, nframes), - _disconnect_timeout(DEFAULT_DISCONNECT_TIMEOUT), - _disconnect_notify_start(DEFAULT_DISCONNECT_NOTIFY_START), _num_spectators(0), _next_spectator_frame(0) { @@ -63,8 +59,6 @@ Peer2PeerBackend::AddRemotePlayer(ENetPeer* peer, int queue) _synchronizing = true; _endpoints[queue].Init(peer, queue, _local_connect_status); - _endpoints[queue].SetDisconnectTimeout(_disconnect_timeout); - _endpoints[queue].SetDisconnectNotifyStart(_disconnect_notify_start); _endpoints[queue].Synchronize(); } @@ -82,8 +76,6 @@ GGPOErrorCode Peer2PeerBackend::AddSpectator(ENetPeer* peer) int queue = _num_spectators++; _spectators[queue].Init(peer, queue + 1000, _local_connect_status); - _spectators[queue].SetDisconnectTimeout(_disconnect_timeout); - _spectators[queue].SetDisconnectNotifyStart(_disconnect_notify_start); _spectators[queue].Synchronize(); return GGPO_OK; @@ -538,10 +530,6 @@ Peer2PeerBackend::OnUdpProtocolPeerEvent(UdpProtocol::Event &evt, int queue) } } break; - - case UdpProtocol::Event::Disconnected: - DisconnectPlayer(QueueToPlayerHandle(queue)); - break; } } @@ -551,19 +539,6 @@ Peer2PeerBackend::OnUdpProtocolSpectatorEvent(UdpProtocol::Event &evt, int queue { GGPOPlayerHandle handle = QueueToSpectatorHandle(queue); OnUdpProtocolEvent(evt, handle); - - GGPOEvent info; - - switch (evt.type) { - case UdpProtocol::Event::Disconnected: - _spectators[queue].Disconnect(); - - info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER; - info.u.disconnected.player = handle; - _callbacks.on_event(_callbacks.context, &info); - - break; - } } void @@ -591,19 +566,6 @@ Peer2PeerBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt, GGPOPlayerHandle h CheckInitialSync(); break; - - case UdpProtocol::Event::NetworkInterrupted: - info.code = GGPO_EVENTCODE_CONNECTION_INTERRUPTED; - info.u.connection_interrupted.player = handle; - info.u.connection_interrupted.disconnect_timeout = evt.u.network_interrupted.disconnect_timeout; - _callbacks.on_event(_callbacks.context, &info); - break; - - case UdpProtocol::Event::NetworkResumed: - info.code = GGPO_EVENTCODE_CONNECTION_RESUMED; - info.u.connection_resumed.player = handle; - _callbacks.on_event(_callbacks.context, &info); - break; } } @@ -650,6 +612,7 @@ Peer2PeerBackend::DisconnectPlayerQueue(int queue, int syncto) GGPOEvent info; int framecount = _sync.GetFrameCount(); + // TODO: Where does the endpoint actually get removed? I can't see it anywhere... _endpoints[queue].Disconnect(); Log("Changing queue %d local connect status for last frame from %d to %d on disconnect request (current: %d).\n", @@ -664,10 +627,6 @@ Peer2PeerBackend::DisconnectPlayerQueue(int queue, int syncto) Log("finished adjusting simulation.\n"); }*/ - info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER; - info.u.disconnected.player = QueueToPlayerHandle(queue); - _callbacks.on_event(_callbacks.context, &info); - CheckInitialSync(); } @@ -710,30 +669,6 @@ Peer2PeerBackend::SetFrameDelay(GGPOPlayerHandle player, int delay) return GGPO_OK; } -GGPOErrorCode -Peer2PeerBackend::SetDisconnectTimeout(int timeout) -{ - _disconnect_timeout = timeout; - for (int i = 0; i < _num_players; i++) { - if (_endpoints[i].IsInitialized()) { - _endpoints[i].SetDisconnectTimeout(_disconnect_timeout); - } - } - return GGPO_OK; -} - -GGPOErrorCode -Peer2PeerBackend::SetDisconnectNotifyStart(int timeout) -{ - _disconnect_notify_start = timeout; - for (int i = 0; i < _num_players; i++) { - if (_endpoints[i].IsInitialized()) { - _endpoints[i].SetDisconnectNotifyStart(_disconnect_notify_start); - } - } - return GGPO_OK; -} - GGPOErrorCode Peer2PeerBackend::PlayerHandleToQueue(GGPOPlayerHandle player, int *queue) { diff --git a/dep/ggpo-x/src/backends/p2p.h b/dep/ggpo-x/src/backends/p2p.h index 3e3220a6b..70964deeb 100644 --- a/dep/ggpo-x/src/backends/p2p.h +++ b/dep/ggpo-x/src/backends/p2p.h @@ -30,8 +30,6 @@ public: virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) override; virtual GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) override; virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) override; - virtual GGPOErrorCode SetDisconnectTimeout(int timeout) override; - virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) override; virtual GGPOErrorCode CurrentFrame(int& current) override; virtual GGPOErrorCode OnPacket(ENetPeer* peer, const ENetPacket* pkt) override; @@ -65,8 +63,6 @@ protected: int _next_recommended_sleep; int _next_spectator_frame; - int _disconnect_timeout; - int _disconnect_notify_start; UdpMsg::connect_status _local_connect_status[UDP_MSG_MAX_PLAYERS]; struct ChecksumEntry { diff --git a/dep/ggpo-x/src/backends/spectator.cpp b/dep/ggpo-x/src/backends/spectator.cpp index c8c667c3f..82580a6eb 100644 --- a/dep/ggpo-x/src/backends/spectator.cpp +++ b/dep/ggpo-x/src/backends/spectator.cpp @@ -143,25 +143,6 @@ SpectatorBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt) } break; - case UdpProtocol::Event::NetworkInterrupted: - info.code = GGPO_EVENTCODE_CONNECTION_INTERRUPTED; - info.u.connection_interrupted.player = 0; - info.u.connection_interrupted.disconnect_timeout = evt.u.network_interrupted.disconnect_timeout; - _callbacks.on_event(_callbacks.context, &info); - break; - - case UdpProtocol::Event::NetworkResumed: - info.code = GGPO_EVENTCODE_CONNECTION_RESUMED; - info.u.connection_resumed.player = 0; - _callbacks.on_event(_callbacks.context, &info); - break; - - case UdpProtocol::Event::Disconnected: - info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER; - info.u.disconnected.player = 0; - _callbacks.on_event(_callbacks.context, &info); - break; - case UdpProtocol::Event::Input: GameInput& input = evt.u.input.input; diff --git a/dep/ggpo-x/src/network/udp_msg.h b/dep/ggpo-x/src/network/udp_msg.h index d8ac6f349..ad01d6a9d 100644 --- a/dep/ggpo-x/src/network/udp_msg.h +++ b/dep/ggpo-x/src/network/udp_msg.h @@ -21,8 +21,7 @@ struct UdpMsg Input = 3, QualityReport = 4, QualityReply = 5, - KeepAlive = 6, - InputAck = 7, + InputAck = 6, }; struct connect_status { @@ -61,8 +60,7 @@ struct UdpMsg uint32 start_frame; - int disconnect_requested:1; - int ack_frame:31; + int ack_frame; uint16 num_bits; uint32 checksum32; @@ -71,7 +69,7 @@ struct UdpMsg } input; struct { - int ack_frame:31; + int ack_frame; } input_ack; } u; @@ -89,7 +87,6 @@ public: case QualityReport: return sizeof(u.quality_report); case QualityReply: return sizeof(u.quality_reply); case InputAck: return sizeof(u.input_ack); - case KeepAlive: return 0; case Input: size = (int)((char *)&u.input.bits - (char *)&u.input); size += (u.input.num_bits + 7) / 8; diff --git a/dep/ggpo-x/src/network/udp_proto.cpp b/dep/ggpo-x/src/network/udp_proto.cpp index faecdbdff..be3a4967e 100644 --- a/dep/ggpo-x/src/network/udp_proto.cpp +++ b/dep/ggpo-x/src/network/udp_proto.cpp @@ -15,10 +15,8 @@ static const int NUM_SYNC_PACKETS = 5; static const int SYNC_RETRY_INTERVAL = 2000; static const int SYNC_FIRST_RETRY_INTERVAL = 500; static const int RUNNING_RETRY_INTERVAL = 200; -static const int KEEP_ALIVE_INTERVAL = 200; static const int QUALITY_REPORT_INTERVAL = 333; static const int NETWORK_STATS_INTERVAL = 500; -static const int UDP_SHUTDOWN_TIMER = 5000; static const int MAX_SEQ_DISTANCE = (1 << 15); static const uint8_t ENET_CHANNEL_ID = 1; @@ -33,11 +31,6 @@ UdpProtocol::UdpProtocol() : _bytes_sent(0), _stats_start_time(0), _last_send_time(0), - _shutdown_timeout(0), - _disconnect_timeout(0), - _disconnect_notify_start(0), - _disconnect_notify_sent(false), - _disconnect_event_sent(false), _connected(false), _next_send_seq(0), _next_recv_seq(0), @@ -143,7 +136,6 @@ UdpProtocol::SendPendingOutput() msg->u.input.ack_frame = _last_received_input.frame; msg->u.input.num_bits = (uint16)offset; - msg->u.input.disconnect_requested = _current_state == Disconnected; if (_local_connect_status) { memcpy(msg->u.input.peer_connect_status, _local_connect_status, sizeof(UdpMsg::connect_status) * UDP_MSG_MAX_PLAYERS); } else { @@ -235,38 +227,10 @@ UdpProtocol::OnLoopPoll() _state.running.last_network_stats_interval = now; } - // TODO: needed with enet? - if (_last_send_time && _last_send_time + KEEP_ALIVE_INTERVAL < now) { - Log("Sending keep alive packet\n"); - SendMsg(new UdpMsg(UdpMsg::KeepAlive)); - } - - // These can be dropped.. - if (_disconnect_timeout && _disconnect_notify_start && - !_disconnect_notify_sent && (_last_recv_time + _disconnect_notify_start < now)) { - Log("Endpoint has stopped receiving packets for %d ms. Sending notification.\n", _disconnect_notify_start); - Event e(Event::NetworkInterrupted); - e.u.network_interrupted.disconnect_timeout = _disconnect_timeout - _disconnect_notify_start; - QueueEvent(e); - _disconnect_notify_sent = true; - } - - if (_disconnect_timeout && (_last_recv_time + _disconnect_timeout < now)) { - if (!_disconnect_event_sent) { - Log("Endpoint has stopped receiving packets for %d ms. Disconnecting.\n", _disconnect_timeout); - QueueEvent(Event(Event::Disconnected)); - _disconnect_event_sent = true; - } - } break; case Disconnected: - if (_shutdown_timeout < now) { - Log("Shutting down udp connection.\n"); - abort(); - _peer = NULL; - _shutdown_timeout = 0; - } + break; } @@ -278,7 +242,7 @@ void UdpProtocol::Disconnect() { _current_state = Disconnected; - _shutdown_timeout = Platform::GetCurrentTimeMS() + UDP_SHUTDOWN_TIMER; + _peer = nullptr; } void @@ -323,7 +287,6 @@ UdpProtocol::OnMsg(UdpMsg *msg, int len) &UdpProtocol::OnInput, /* Input */ &UdpProtocol::OnQualityReport, /* QualityReport */ &UdpProtocol::OnQualityReply, /* QualityReply */ - &UdpProtocol::OnKeepAlive, /* KeepAlive */ &UdpProtocol::OnInputAck, /* InputAck */ }; @@ -354,10 +317,6 @@ UdpProtocol::OnMsg(UdpMsg *msg, int len) } if (handled) { _last_recv_time = Platform::GetCurrentTimeMS(); - if (_disconnect_notify_sent && _current_state == Running) { - QueueEvent(Event(Event::NetworkResumed)); - _disconnect_notify_sent = false; - } } } @@ -445,9 +404,6 @@ UdpProtocol::LogMsg(const char *prefix, UdpMsg *msg) case UdpMsg::QualityReply: Log("%s quality reply.\n", prefix); break; - case UdpMsg::KeepAlive: - Log("%s keep alive.\n", prefix); - break; case UdpMsg::Input: Log("%s game-compressed-input %d (+ %d bits).\n", prefix, msg->u.input.start_frame, msg->u.input.num_bits); break; @@ -531,28 +487,16 @@ UdpProtocol::OnSyncReply(UdpMsg *msg, int len) bool UdpProtocol::OnInput(UdpMsg *msg, int len) { - /* - * If a disconnect is requested, go ahead and disconnect now. - */ - bool disconnect_requested = msg->u.input.disconnect_requested; - if (disconnect_requested) { - if (_current_state != Disconnected && !_disconnect_event_sent) { - Log("Disconnecting endpoint on remote request.\n"); - QueueEvent(Event(Event::Disconnected)); - _disconnect_event_sent = true; - } - } else { - /* - * Update the peer connection status if this peer is still considered to be part - * of the network. - */ - UdpMsg::connect_status* remote_status = msg->u.input.peer_connect_status; - for (int i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { - ASSERT(remote_status[i].last_frame >= _peer_connect_status[i].last_frame); - _peer_connect_status[i].disconnected = _peer_connect_status[i].disconnected || remote_status[i].disconnected; - _peer_connect_status[i].last_frame = MAX(_peer_connect_status[i].last_frame, remote_status[i].last_frame); - } - } + /* + * Update the peer connection status if this peer is still considered to be part + * of the network. + */ + UdpMsg::connect_status* remote_status = msg->u.input.peer_connect_status; + for (int i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) { + ASSERT(remote_status[i].last_frame >= _peer_connect_status[i].last_frame); + _peer_connect_status[i].disconnected = _peer_connect_status[i].disconnected || remote_status[i].disconnected; + _peer_connect_status[i].last_frame = MAX(_peer_connect_status[i].last_frame, remote_status[i].last_frame); + } /* * Decompress the input. @@ -673,12 +617,6 @@ UdpProtocol::OnQualityReply(UdpMsg *msg, int len) return true; } -bool -UdpProtocol::OnKeepAlive(UdpMsg *msg, int len) -{ - return true; -} - void UdpProtocol::GetNetworkStats(struct GGPONetworkStats *s) { @@ -716,16 +654,3 @@ UdpProtocol::RecommendFrameDelay() // XXX: require idle input should be a configuration parameter return _timesync.recommend_frame_wait_duration(false); } - - -void -UdpProtocol::SetDisconnectTimeout(int timeout) -{ - _disconnect_timeout = timeout; -} - -void -UdpProtocol::SetDisconnectNotifyStart(int timeout) -{ - _disconnect_notify_start = timeout; -} diff --git a/dep/ggpo-x/src/network/udp_proto.h b/dep/ggpo-x/src/network/udp_proto.h index 32ebad721..4b1cf6301 100644 --- a/dep/ggpo-x/src/network/udp_proto.h +++ b/dep/ggpo-x/src/network/udp_proto.h @@ -37,9 +37,6 @@ public: Synchronizing, Synchronzied, Input, - Disconnected, - NetworkInterrupted, - NetworkResumed, }; Type type; @@ -85,8 +82,6 @@ public: void SetLocalFrameNumber(int num); float RecommendFrameDelay(); int RemoteFrameDelay()const; - void SetDisconnectTimeout(int timeout); - void SetDisconnectNotifyStart(int timeout); void SetFrameDelay(int delay); void ApplyToEvents(std::function cb); void StartPollLoop(); @@ -124,7 +119,6 @@ protected: bool OnInputAck(UdpMsg *msg, int len); bool OnQualityReport(UdpMsg *msg, int len); bool OnQualityReply(UdpMsg *msg, int len); - bool OnKeepAlive(UdpMsg *msg, int len); protected: /* @@ -179,11 +173,6 @@ protected: GameInput _last_acked_input; unsigned int _last_send_time; unsigned int _last_recv_time; - unsigned int _shutdown_timeout; - unsigned int _disconnect_event_sent; - unsigned int _disconnect_timeout; - unsigned int _disconnect_notify_start; - bool _disconnect_notify_sent; uint16 _next_send_seq; uint16 _next_recv_seq; diff --git a/src/core/netplay.cpp b/src/core/netplay.cpp index 0abf98b56..7a664e2be 100644 --- a/src/core/netplay.cpp +++ b/src/core/netplay.cpp @@ -215,7 +215,10 @@ void Netplay::HandleEnetEvent(const ENetEvent* event) if (player_id < 0) return; + // TODO: This one's gonna get kinda tricky... who do we orphan when they disconnect? Log_WarningPrintf("ENet player %d disconnected", player_id); + Host::OnNetplayMessage(fmt::format("*** DISCONNECTED PLAYER {} ***", player_id)); + ggpo_disconnect_player(s_ggpo, PlayerIdToGGPOHandle(player_id)); s_enet_peers[player_id] = nullptr; } break; @@ -355,7 +358,7 @@ s32 Netplay::Start(s32 lhandle, u16 lport, const std::string& raddr, u16 rport, ENetAddress host_address; host_address.host = ENET_HOST_ANY; - host_address.port = lport - 10; + host_address.port = lport; s_enet_host = enet_host_create(&host_address, MAX_PLAYERS - 1, NUM_ENET_CHANNELS, 0, 0); if (!s_enet_host) { @@ -381,7 +384,7 @@ s32 Netplay::Start(s32 lhandle, u16 lport, const std::string& raddr, u16 rport, return -1; } - peer_addresses[other_player_id].port = rport - 10; + peer_addresses[other_player_id].port = rport; } // Create system. @@ -874,19 +877,9 @@ bool Netplay::NpOnEventCb(void* ctx, GGPOEvent* ev) case GGPOEventCode::GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER: Host::OnNetplayMessage(fmt::format("Netplay Synchronized With Player: {}", ev->u.synchronized.player)); break; - case GGPOEventCode::GGPO_EVENTCODE_DISCONNECTED_FROM_PEER: - Host::OnNetplayMessage(fmt::format("Netplay Player: %d Disconnected", ev->u.disconnected.player)); - break; case GGPOEventCode::GGPO_EVENTCODE_RUNNING: Host::OnNetplayMessage("Netplay Is Running"); break; - case GGPOEventCode::GGPO_EVENTCODE_CONNECTION_INTERRUPTED: - Host::OnNetplayMessage(fmt::format("Netplay Player: {} Connection Interupted, Timeout: {}", ev->u.connection_interrupted.player, - ev->u.connection_interrupted.disconnect_timeout)); - break; - case GGPOEventCode::GGPO_EVENTCODE_CONNECTION_RESUMED: - Host::OnNetplayMessage(fmt::format("Netplay Player: {} Connection Resumed", ev->u.connection_resumed.player)); - break; case GGPOEventCode::GGPO_EVENTCODE_TIMESYNC: HandleTimeSyncEvent(ev->u.timesync.frames_ahead, ev->u.timesync.timeSyncPeriodInFrames); break;