diff --git a/dep/ggpo-x/include/ggponet.h b/dep/ggpo-x/include/ggponet.h index 96ce61500..188dfcaba 100644 --- a/dep/ggpo-x/include/ggponet.h +++ b/dep/ggpo-x/include/ggponet.h @@ -541,8 +541,9 @@ GGPO_API GGPOErrorCode __cdecl ggpo_disconnect_player(GGPOSession *, GGPO_API GGPOErrorCode __cdecl ggpo_advance_frame(GGPOSession *, uint16_t checksum); /* - * ggpo_get_current_frame -- current frame GGPO is dealing with - * + * ggpo_get_current_frame -- + * + * current frame GGPO is dealing with */ GGPO_API GGPOErrorCode __cdecl ggpo_get_current_frame(GGPOSession* ggpo, int& nFrame); /* @@ -573,8 +574,16 @@ GGPO_API GGPOErrorCode __cdecl ggpo_get_network_stats(GGPOSession *, */ GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *, int timeout); - /* + * ggpo_enable_manual_network_polling -- + * + * disables polling done by ggpo and it's expected that ggpo_poll_network will be used instead. + * + */ + +GGPO_API GGPOErrorCode __cdecl ggpo_set_manual_network_polling(GGPOSession*, + bool value); + /* * ggpo_set_disconnect_notify_start -- * * The time to wait before the first GGPO_EVENTCODE_NETWORK_INTERRUPTED timeout @@ -584,7 +593,15 @@ GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *, * before the GGPO_EVENTCODE_NETWORK_INTERRUPTED event is sent. */ GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_notify_start(GGPOSession *, - int timeout); + int timeout); +/* +* ggpo_poll_network -- +* +* polls the network socket for any messages to be sent and recieved. +* +*/ + +GGPO_API GGPOErrorCode __cdecl ggpo_poll_network(GGPOSession*); /* * ggpo_log -- diff --git a/dep/ggpo-x/src/backends/backend.h b/dep/ggpo-x/src/backends/backend.h index 9b2466a8d..7b747e0ae 100644 --- a/dep/ggpo-x/src/backends/backend.h +++ b/dep/ggpo-x/src/backends/backend.h @@ -22,12 +22,14 @@ public: virtual GGPOErrorCode CurrentFrame(int& current) =0; virtual GGPOErrorCode Chat(const char* text) = 0;// { return GGPO_OK; } virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) = 0;// { return GGPO_OK; } + virtual GGPOErrorCode PollNetwork() = 0; virtual GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) { return GGPO_OK; } virtual GGPOErrorCode Logv(const char *fmt, va_list list) { ::Logv(fmt, list); return GGPO_OK; } virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } + virtual GGPOErrorCode SetManualNetworkPolling(bool value) = 0; }; diff --git a/dep/ggpo-x/src/backends/p2p.cpp b/dep/ggpo-x/src/backends/p2p.cpp index ab090f9c9..210ae2e35 100644 --- a/dep/ggpo-x/src/backends/p2p.cpp +++ b/dep/ggpo-x/src/backends/p2p.cpp @@ -27,6 +27,7 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb, _callbacks = *cb; _synchronizing = true; _next_recommended_sleep = 0; + _manual_network_polling = false; /* * Initialize the synchronziation layer @@ -150,6 +151,7 @@ void Peer2PeerBackend::CheckDesync() } } + GGPOErrorCode Peer2PeerBackend::DoPoll() { @@ -165,7 +167,8 @@ Peer2PeerBackend::DoPoll() } if (!_sync.InRollback()) { - _poll.Pump(0); + if (!_manual_network_polling) + _poll.Pump(0); PollUdpProtocolEvents(); CheckDesync(); @@ -402,11 +405,27 @@ Peer2PeerBackend::SyncInput(void *values, } return GGPO_OK; } -GGPOErrorCode Peer2PeerBackend::CurrentFrame(int& current) + +GGPOErrorCode +Peer2PeerBackend::CurrentFrame(int& current) { current = _sync.GetFrameCount(); return GGPO_OK; } + +GGPOErrorCode +Peer2PeerBackend::PollNetwork() +{ + _poll.Pump(0); + return GGPO_OK; +} + +GGPOErrorCode Peer2PeerBackend::SetManualNetworkPolling(bool value) +{ + _manual_network_polling = value; + return GGPO_OK; +} + GGPOErrorCode Peer2PeerBackend::IncrementFrame(uint16_t checksum1) { diff --git a/dep/ggpo-x/src/backends/p2p.h b/dep/ggpo-x/src/backends/p2p.h index 62cfea0f9..100df7dc6 100644 --- a/dep/ggpo-x/src/backends/p2p.h +++ b/dep/ggpo-x/src/backends/p2p.h @@ -34,7 +34,10 @@ public: virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) override; virtual GGPOErrorCode Chat(const char* text) override; virtual GGPOErrorCode CurrentFrame(int& current) override; -public: + virtual GGPOErrorCode PollNetwork() override; + virtual GGPOErrorCode SetManualNetworkPolling(bool value) override; + + public: virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len); protected: @@ -72,6 +75,8 @@ protected: int _disconnect_timeout; int _disconnect_notify_start; + bool _manual_network_polling; + UdpMsg::connect_status _local_connect_status[UDP_MSG_MAX_PLAYERS]; struct ChecksumEntry { int nFrame; diff --git a/dep/ggpo-x/src/backends/spectator.cpp b/dep/ggpo-x/src/backends/spectator.cpp index 5d1011819..71ca42519 100644 --- a/dep/ggpo-x/src/backends/spectator.cpp +++ b/dep/ggpo-x/src/backends/spectator.cpp @@ -20,6 +20,7 @@ SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb, { _callbacks = *cb; _synchronizing = true; + _manual_network_polling = false; for (int i = 0; i < ARRAY_SIZE(_inputs); i++) { _inputs[i].frame = -1; @@ -46,10 +47,11 @@ SpectatorBackend::~SpectatorBackend() { } -GGPOErrorCode +GGPOErrorCode SpectatorBackend::DoPoll() { - _poll.Pump(0); + if (!_manual_network_polling) + _poll.Pump(0); PollUdpProtocolEvents(); return GGPO_OK; @@ -86,11 +88,27 @@ SpectatorBackend::SyncInput(void *values, return GGPO_OK; } -GGPOErrorCode SpectatorBackend::CurrentFrame(int& current) +GGPOErrorCode +SpectatorBackend::CurrentFrame(int& current) { current= _next_input_to_send; return GGPO_OK; } + +GGPOErrorCode +SpectatorBackend::PollNetwork() +{ + _poll.Pump(0); + return GGPO_OK; +} + +GGPOErrorCode +SpectatorBackend::SetManualNetworkPolling(bool value) +{ + _manual_network_polling = value; + return GGPO_OK; +} + GGPOErrorCode SpectatorBackend::IncrementFrame(uint16_t checksum) { diff --git a/dep/ggpo-x/src/backends/spectator.h b/dep/ggpo-x/src/backends/spectator.h index 4d4645140..255fb4231 100644 --- a/dep/ggpo-x/src/backends/spectator.h +++ b/dep/ggpo-x/src/backends/spectator.h @@ -36,7 +36,8 @@ public: virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode CurrentFrame(int& current) override; - + virtual GGPOErrorCode PollNetwork() override; + virtual GGPOErrorCode SetManualNetworkPolling(bool value) override; public: virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len); @@ -57,6 +58,7 @@ protected: int _num_players; int _next_input_to_send; GameInput _inputs[SPECTATOR_FRAME_BUFFER_SIZE]; + bool _manual_network_polling; }; #endif diff --git a/dep/ggpo-x/src/backends/synctest.h b/dep/ggpo-x/src/backends/synctest.h index 924dbfb27..8339dadf4 100644 --- a/dep/ggpo-x/src/backends/synctest.h +++ b/dep/ggpo-x/src/backends/synctest.h @@ -27,7 +27,10 @@ public: virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; } virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode CurrentFrame(int& current) override; -protected: + virtual GGPOErrorCode PollNetwork() override { return GGPO_OK; }; + virtual GGPOErrorCode SetManualNetworkPolling(bool value) override { return GGPO_OK; }; + + protected: struct SavedInfo { int frame; int checksum; diff --git a/dep/ggpo-x/src/main.cpp b/dep/ggpo-x/src/main.cpp index 36d0b264b..0ed0b9ad2 100644 --- a/dep/ggpo-x/src/main.cpp +++ b/dep/ggpo-x/src/main.cpp @@ -191,6 +191,16 @@ ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout) return ggpo->SetDisconnectTimeout(timeout); } +GGPOErrorCode +ggpo_set_manual_network_polling(GGPOSession *ggpo, bool value) +{ + if (!ggpo) + { + return GGPO_ERRORCODE_INVALID_SESSION; + } + return ggpo->SetManualNetworkPolling(value); +} + GGPOErrorCode ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout) { @@ -200,6 +210,16 @@ ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout) return ggpo->SetDisconnectNotifyStart(timeout); } +GGPOErrorCode +ggpo_poll_network(GGPOSession* ggpo) +{ + if (!ggpo) + { + return GGPO_ERRORCODE_INVALID_SESSION; + } + return ggpo->PollNetwork(); +} + GGPOErrorCode ggpo_start_spectating(GGPOSession **session, GGPOSessionCallbacks *cb, const char *game, diff --git a/src/core/netplay.cpp b/src/core/netplay.cpp index f2f68c081..3bfaaeaab 100644 --- a/src/core/netplay.cpp +++ b/src/core/netplay.cpp @@ -7,10 +7,10 @@ #include "common/timer.h" #include "digital_controller.h" #include "ggponet.h" +#include "host_settings.h" #include "pad.h" #include "spu.h" #include "system.h" -#include "host_settings.h" #include #include Log_SetChannel(Netplay); @@ -82,7 +82,6 @@ static Common::Timer::Value s_next_frame_time = 0; // Netplay Impl - s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ldelay, u32 pred) { SetSettings(); @@ -105,7 +104,7 @@ s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ld GGPOErrorCode result; result = ggpo_start_session(&s_ggpo, &cb, "Duckstation-Netplay", 2, sizeof(Netplay::Input), lport, s_max_pred); - //result = ggpo_start_synctest(&s_ggpo, &cb, (char*)"asdf", 2, sizeof(Netplay::Input), 1); + // result = ggpo_start_synctest(&s_ggpo, &cb, (char*)"asdf", 2, sizeof(Netplay::Input), 1); ggpo_set_disconnect_timeout(s_ggpo, 3000); ggpo_set_disconnect_notify_start(s_ggpo, 1000); @@ -133,6 +132,7 @@ s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ld } } ggpo_set_frame_delay(s_ggpo, s_local_handle, ldelay); + ggpo_set_manual_network_polling(s_ggpo, true); return result; } @@ -227,8 +227,7 @@ void Netplay::Throttle() for (;;) { // Poll network. - // TODO: Ideally we would sleep on the poll()/select() here instead. - ggpo_idle(s_ggpo); + ggpo_poll_network(s_ggpo); current_time = Common::Timer::GetCurrentValue(); if (current_time >= s_next_frame_time) @@ -250,6 +249,7 @@ void Netplay::AdvanceFrame(u16 checksum) void Netplay::RunFrame() { // run game + bool needIdle = true; auto result = GGPO_OK; int disconnectFlags = 0; Netplay::Input inputs[2] = {}; @@ -268,8 +268,13 @@ void Netplay::RunFrame() // enable again when rolling back done SPU::SetAudioOutputMuted(false); NetplayAdvanceFrame(inputs, disconnectFlags); + // coming here means that the system doesnt need to idle anymore + needIdle = false; } } + // allow ggpo to do housekeeping if needed + if (needIdle) + ggpo_idle(s_ggpo); } void Netplay::CollectInput(u32 slot, u32 bind, float value)