GGPO: poll_network functionality and ggpo_set_manual_network_polling

This commit is contained in:
HeatXD 2023-04-11 20:29:33 +02:00
parent 7cf4ed2d30
commit de9c16bb73
No known key found for this signature in database
GPG Key ID: BF30D71B2F1305C7
9 changed files with 108 additions and 17 deletions

View File

@ -541,8 +541,9 @@ GGPO_API GGPOErrorCode __cdecl ggpo_disconnect_player(GGPOSession *,
GGPO_API GGPOErrorCode __cdecl ggpo_advance_frame(GGPOSession *, uint16_t checksum); 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); 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 *, GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *,
int timeout); 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 -- * ggpo_set_disconnect_notify_start --
* *
* The time to wait before the first GGPO_EVENTCODE_NETWORK_INTERRUPTED timeout * 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. * before the GGPO_EVENTCODE_NETWORK_INTERRUPTED event is sent.
*/ */
GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_notify_start(GGPOSession *, 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 -- * ggpo_log --

View File

@ -22,12 +22,14 @@ public:
virtual GGPOErrorCode CurrentFrame(int& current) =0; virtual GGPOErrorCode CurrentFrame(int& current) =0;
virtual GGPOErrorCode Chat(const char* text) = 0;// { return GGPO_OK; } virtual GGPOErrorCode Chat(const char* text) = 0;// { return GGPO_OK; }
virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) = 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 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 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 SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; }
virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
virtual GGPOErrorCode SetManualNetworkPolling(bool value) = 0;
}; };

View File

@ -27,6 +27,7 @@ Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb,
_callbacks = *cb; _callbacks = *cb;
_synchronizing = true; _synchronizing = true;
_next_recommended_sleep = 0; _next_recommended_sleep = 0;
_manual_network_polling = false;
/* /*
* Initialize the synchronziation layer * Initialize the synchronziation layer
@ -150,6 +151,7 @@ void Peer2PeerBackend::CheckDesync()
} }
} }
GGPOErrorCode GGPOErrorCode
Peer2PeerBackend::DoPoll() Peer2PeerBackend::DoPoll()
{ {
@ -165,7 +167,8 @@ Peer2PeerBackend::DoPoll()
} }
if (!_sync.InRollback()) { if (!_sync.InRollback()) {
_poll.Pump(0); if (!_manual_network_polling)
_poll.Pump(0);
PollUdpProtocolEvents(); PollUdpProtocolEvents();
CheckDesync(); CheckDesync();
@ -402,11 +405,27 @@ Peer2PeerBackend::SyncInput(void *values,
} }
return GGPO_OK; return GGPO_OK;
} }
GGPOErrorCode Peer2PeerBackend::CurrentFrame(int& current)
GGPOErrorCode
Peer2PeerBackend::CurrentFrame(int& current)
{ {
current = _sync.GetFrameCount(); current = _sync.GetFrameCount();
return GGPO_OK; 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 GGPOErrorCode
Peer2PeerBackend::IncrementFrame(uint16_t checksum1) Peer2PeerBackend::IncrementFrame(uint16_t checksum1)
{ {

View File

@ -34,7 +34,10 @@ public:
virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) override; virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) override;
virtual GGPOErrorCode Chat(const char* text) override; virtual GGPOErrorCode Chat(const char* text) override;
virtual GGPOErrorCode CurrentFrame(int& current) 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); virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len);
protected: protected:
@ -72,6 +75,8 @@ protected:
int _disconnect_timeout; int _disconnect_timeout;
int _disconnect_notify_start; int _disconnect_notify_start;
bool _manual_network_polling;
UdpMsg::connect_status _local_connect_status[UDP_MSG_MAX_PLAYERS]; UdpMsg::connect_status _local_connect_status[UDP_MSG_MAX_PLAYERS];
struct ChecksumEntry { struct ChecksumEntry {
int nFrame; int nFrame;

View File

@ -20,6 +20,7 @@ SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb,
{ {
_callbacks = *cb; _callbacks = *cb;
_synchronizing = true; _synchronizing = true;
_manual_network_polling = false;
for (int i = 0; i < ARRAY_SIZE(_inputs); i++) { for (int i = 0; i < ARRAY_SIZE(_inputs); i++) {
_inputs[i].frame = -1; _inputs[i].frame = -1;
@ -46,10 +47,11 @@ SpectatorBackend::~SpectatorBackend()
{ {
} }
GGPOErrorCode GGPOErrorCode
SpectatorBackend::DoPoll() SpectatorBackend::DoPoll()
{ {
_poll.Pump(0); if (!_manual_network_polling)
_poll.Pump(0);
PollUdpProtocolEvents(); PollUdpProtocolEvents();
return GGPO_OK; return GGPO_OK;
@ -86,11 +88,27 @@ SpectatorBackend::SyncInput(void *values,
return GGPO_OK; return GGPO_OK;
} }
GGPOErrorCode SpectatorBackend::CurrentFrame(int& current) GGPOErrorCode
SpectatorBackend::CurrentFrame(int& current)
{ {
current= _next_input_to_send; current= _next_input_to_send;
return GGPO_OK; 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 GGPOErrorCode
SpectatorBackend::IncrementFrame(uint16_t checksum) SpectatorBackend::IncrementFrame(uint16_t checksum)
{ {

View File

@ -36,7 +36,8 @@ public:
virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; }
virtual GGPOErrorCode CurrentFrame(int& current) override; virtual GGPOErrorCode CurrentFrame(int& current) override;
virtual GGPOErrorCode PollNetwork() override;
virtual GGPOErrorCode SetManualNetworkPolling(bool value) override;
public: public:
virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len); virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len);
@ -57,6 +58,7 @@ protected:
int _num_players; int _num_players;
int _next_input_to_send; int _next_input_to_send;
GameInput _inputs[SPECTATOR_FRAME_BUFFER_SIZE]; GameInput _inputs[SPECTATOR_FRAME_BUFFER_SIZE];
bool _manual_network_polling;
}; };
#endif #endif

View File

@ -27,7 +27,10 @@ public:
virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; } virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; }
virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; } virtual GGPOErrorCode Chat(const char* text) override { return GGPO_ERRORCODE_UNSUPPORTED; }
virtual GGPOErrorCode CurrentFrame(int& current) override; 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 { struct SavedInfo {
int frame; int frame;
int checksum; int checksum;

View File

@ -191,6 +191,16 @@ ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout)
return ggpo->SetDisconnectTimeout(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 GGPOErrorCode
ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout) 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); 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, GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
GGPOSessionCallbacks *cb, GGPOSessionCallbacks *cb,
const char *game, const char *game,

View File

@ -7,10 +7,10 @@
#include "common/timer.h" #include "common/timer.h"
#include "digital_controller.h" #include "digital_controller.h"
#include "ggponet.h" #include "ggponet.h"
#include "host_settings.h"
#include "pad.h" #include "pad.h"
#include "spu.h" #include "spu.h"
#include "system.h" #include "system.h"
#include "host_settings.h"
#include <bitset> #include <bitset>
#include <deque> #include <deque>
Log_SetChannel(Netplay); Log_SetChannel(Netplay);
@ -82,7 +82,6 @@ static Common::Timer::Value s_next_frame_time = 0;
// Netplay Impl // Netplay Impl
s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ldelay, u32 pred) s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ldelay, u32 pred)
{ {
SetSettings(); SetSettings();
@ -105,7 +104,7 @@ s32 Netplay::Start(s32 lhandle, u16 lport, std::string& raddr, u16 rport, s32 ld
GGPOErrorCode result; GGPOErrorCode result;
result = ggpo_start_session(&s_ggpo, &cb, "Duckstation-Netplay", 2, sizeof(Netplay::Input), lport, s_max_pred); 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_timeout(s_ggpo, 3000);
ggpo_set_disconnect_notify_start(s_ggpo, 1000); 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_frame_delay(s_ggpo, s_local_handle, ldelay);
ggpo_set_manual_network_polling(s_ggpo, true);
return result; return result;
} }
@ -227,8 +227,7 @@ void Netplay::Throttle()
for (;;) for (;;)
{ {
// Poll network. // Poll network.
// TODO: Ideally we would sleep on the poll()/select() here instead. ggpo_poll_network(s_ggpo);
ggpo_idle(s_ggpo);
current_time = Common::Timer::GetCurrentValue(); current_time = Common::Timer::GetCurrentValue();
if (current_time >= s_next_frame_time) if (current_time >= s_next_frame_time)
@ -250,6 +249,7 @@ void Netplay::AdvanceFrame(u16 checksum)
void Netplay::RunFrame() void Netplay::RunFrame()
{ {
// run game // run game
bool needIdle = true;
auto result = GGPO_OK; auto result = GGPO_OK;
int disconnectFlags = 0; int disconnectFlags = 0;
Netplay::Input inputs[2] = {}; Netplay::Input inputs[2] = {};
@ -268,8 +268,13 @@ void Netplay::RunFrame()
// enable again when rolling back done // enable again when rolling back done
SPU::SetAudioOutputMuted(false); SPU::SetAudioOutputMuted(false);
NetplayAdvanceFrame(inputs, disconnectFlags); 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) void Netplay::CollectInput(u32 slot, u32 bind, float value)