For Qt GUI, added netplay client state load request functionality.

This commit is contained in:
harry 2024-03-21 22:06:40 -04:00
parent 55654f7191
commit 5a0898ccbe
4 changed files with 127 additions and 4 deletions

View File

@ -42,6 +42,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static uint32_t opsCrc32 = 0; static uint32_t opsCrc32 = 0;
static void *traceRegistrationHandle = nullptr; static void *traceRegistrationHandle = nullptr;
static bool serverRequestedStateLoad = false;
struct NetPlayFrameData struct NetPlayFrameData
{ {
@ -678,6 +679,46 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } ); sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
} }
} }
break;
case NETPLAY_SYNC_STATE_RESP:
{
bool acceptStateLoadReq = false;
FCEU_printf("Sync state request received from client '%s'\n", client->userName.toLocal8Bit().constData());
if (allowClientStateLoadReq)
{
QString msgBoxTxt = tr("Client '") + client->userName + tr("' has requested to load a new state:\n");
msgBoxTxt += tr("\nDo you want to load it?");
int ans = QMessageBox::question( consoleWindow, tr("Client State Load Request"), msgBoxTxt, QMessageBox::Yes | QMessageBox::No );
if (ans == QMessageBox::Yes)
{
acceptStateLoadReq = true;
}
}
if (acceptStateLoadReq)
{
char *stateData = &static_cast<char*>(msgBuf)[ sizeof(netPlayMsgHdr) ];
FCEU_printf("Sync state request accepted\n");
EMUFILE_MEMORY em( stateData, msgSize );
FCEU_WRAPPER_LOCK();
serverRequestedStateLoad = true;
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
serverRequestedStateLoad = false;
FCEU_WRAPPER_UNLOCK();
opsCrc32 = 0;
netPlayFrameData.reset();
inputClear();
resyncAllClients();
}
}
break;
default: default:
printf("Unknown Msg: %08X\n", msgId); printf("Unknown Msg: %08X\n", msgId);
break; break;
@ -1088,6 +1129,44 @@ int NetPlayClient::requestRomLoad( const char *romPath )
return 0; return 0;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int NetPlayClient::requestStateLoad(EMUFILE *is)
{
size_t dataSize;
char *dataBuf;
netPlayMsgHdr hdr(NETPLAY_SYNC_STATE_RESP);
dataSize = is->size();
hdr.msgSize += dataSize;
if (dataSize == 0)
{
return -1;
}
dataBuf = static_cast<char*>(::malloc(dataSize));
if (dataBuf == nullptr)
{
return -1;
}
is->fseek( 0, SEEK_SET );
size_t readResult = is->fread( dataBuf, dataSize );
if (readResult != dataSize )
{
printf("Read Error\n");
}
printf("Sending Client ROM Sync Request\n");
hdr.toNetworkByteOrder();
sock->write( reinterpret_cast<const char*>(&hdr), sizeof(netPlayMsgHdr));
sock->write( reinterpret_cast<const char*>(dataBuf), dataSize );
::free(dataBuf);
return 0;
}
//-----------------------------------------------------------------------------
void NetPlayClient::recordPingResult( uint64_t delay_ms ) void NetPlayClient::recordPingResult( uint64_t delay_ms )
{ {
pingNumSamples++; pingNumSamples++;
@ -1313,7 +1392,9 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
EMUFILE_MEMORY em( stateData, msgSize ); EMUFILE_MEMORY em( stateData, msgSize );
FCEU_WRAPPER_LOCK(); FCEU_WRAPPER_LOCK();
serverRequestedStateLoad = true;
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP ); FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
serverRequestedStateLoad = false;
FCEU_WRAPPER_UNLOCK(); FCEU_WRAPPER_UNLOCK();
opsCrc32 = 0; opsCrc32 = 0;
@ -1447,11 +1528,17 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent)
grid->addWidget( lbl, 0, 0, 1, 1 ); grid->addWidget( lbl, 0, 0, 1, 1 );
grid->addWidget( frameLeadSpinBox, 0, 1, 1, 1 ); grid->addWidget( frameLeadSpinBox, 0, 1, 1, 1 );
bool romLoadReqEna = false;
allowClientRomReqCBox = new QCheckBox(tr("Allow Client ROM Load Requests")); allowClientRomReqCBox = new QCheckBox(tr("Allow Client ROM Load Requests"));
grid->addWidget( allowClientRomReqCBox, 1, 0, 1, 2 ); grid->addWidget( allowClientRomReqCBox, 1, 0, 1, 2 );
g_config->getOption("SDL.NetPlayHostAllowClientRomLoadReq", &romLoadReqEna);
allowClientRomReqCBox->setChecked(romLoadReqEna);
bool stateLoadReqEna = false;
allowClientStateReqCBox = new QCheckBox(tr("Allow Client State Load Requests")); allowClientStateReqCBox = new QCheckBox(tr("Allow Client State Load Requests"));
grid->addWidget( allowClientStateReqCBox, 2, 0, 1, 2 ); grid->addWidget( allowClientStateReqCBox, 2, 0, 1, 2 );
g_config->getOption("SDL.NetPlayHostAllowClientStateLoadReq", &stateLoadReqEna);
allowClientStateReqCBox->setChecked(stateLoadReqEna);
startButton = new QPushButton( tr("Start") ); startButton = new QPushButton( tr("Start") );
startButton->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton)); startButton->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton));
@ -1511,6 +1598,9 @@ void NetPlayHostDialog::onStartClicked(void)
server->setAllowClientRomLoadRequest( allowClientRomReqCBox->isChecked() ); server->setAllowClientRomLoadRequest( allowClientRomReqCBox->isChecked() );
server->setAllowClientStateLoadRequest( allowClientStateReqCBox->isChecked() ); server->setAllowClientStateLoadRequest( allowClientStateReqCBox->isChecked() );
g_config->setOption("SDL.NetPlayHostAllowClientRomLoadReq", allowClientRomReqCBox->isChecked() );
g_config->setOption("SDL.NetPlayHostAllowClientStateLoadReq", allowClientStateReqCBox->isChecked() );
bool listenSucceeded = server->listen( QHostAddress::Any, netPort ); bool listenSucceeded = server->listen( QHostAddress::Any, netPort );
if (listenSucceeded) if (listenSucceeded)
@ -2217,3 +2307,18 @@ void NetPlayOnFrameBegin()
//printf("Frame: %u Ops:%08X Ram:%08X\n", data.frameNum, data.opsCrc32, data.ramCrc32 ); //printf("Frame: %u Ops:%08X Ram:%08X\n", data.frameNum, data.opsCrc32, data.ramCrc32 );
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool NetPlayStateLoadReq(EMUFILE* is)
{
auto* client = NetPlayClient::GetInstance();
bool shouldLoad = (client == nullptr) || serverRequestedStateLoad;
printf("NetPlay Load State: %i\n", shouldLoad);
if ( (client != nullptr) && !serverRequestedStateLoad)
{ // Send state to host
client->requestStateLoad(is);
}
return !shouldLoad;
}
//----------------------------------------------------------------------------

View File

@ -164,8 +164,8 @@ class NetPlayServer : public QTcpServer
uint32_t maxLeadFrames = 10u; uint32_t maxLeadFrames = 10u;
uint32_t clientWaitCounter = 0; uint32_t clientWaitCounter = 0;
uint32_t inputFrameCount = 0; uint32_t inputFrameCount = 0;
bool allowClientRomLoadReq = true; bool allowClientRomLoadReq = false;
bool allowClientStateLoadReq = true; bool allowClientStateLoadReq = false;
public: public:
signals: signals:
@ -198,6 +198,7 @@ class NetPlayClient : public QObject
void forceDisconnect(); void forceDisconnect();
bool flushData(); bool flushData();
int requestRomLoad( const char *romPath ); int requestRomLoad( const char *romPath );
int requestStateLoad(EMUFILE* is);
QTcpSocket* createSocket(void); QTcpSocket* createSocket(void);
void setSocket(QTcpSocket *s); void setSocket(QTcpSocket *s);
@ -426,6 +427,7 @@ int NetPlayFrameWait(void);
void NetPlayOnFrameBegin(void); void NetPlayOnFrameBegin(void);
void NetPlayReadInputFrame(uint8_t* joy); void NetPlayReadInputFrame(uint8_t* joy);
void NetPlayCloseSession(void); void NetPlayCloseSession(void);
bool NetPlayStateLoadReq(EMUFILE* is);
void NetPlayTraceInstruction(uint8_t *opcode, int size); void NetPlayTraceInstruction(uint8_t *opcode, int size);
void openNetPlayHostDialog(QWidget* parent = nullptr); void openNetPlayHostDialog(QWidget* parent = nullptr);
void openNetPlayJoinDialog(QWidget* parent = nullptr); void openNetPlayJoinDialog(QWidget* parent = nullptr);

View File

@ -633,6 +633,8 @@ InitConfig()
config->addOption('k', "netkey", "SDL.NetworkGameKey", ""); config->addOption('k', "netkey", "SDL.NetworkGameKey", "");
config->addOption("port", "SDL.NetworkPort", NetPlayServer::DefaultPort); config->addOption("port", "SDL.NetworkPort", NetPlayServer::DefaultPort);
config->addOption("players", "SDL.NetworkPlayers", 1); config->addOption("players", "SDL.NetworkPlayers", 1);
config->addOption("SDL.NetPlayHostAllowClientRomLoadReq", 0);
config->addOption("SDL.NetPlayHostAllowClientStateLoadReq", 0);
// input configuration options // input configuration options
config->addOption("input1", "SDL.Input.0", "GamePad.0"); config->addOption("input1", "SDL.Input.0", "GamePad.0");

View File

@ -639,6 +639,11 @@ int FCEUSS_LoadFP_old(EMUFILE* is, ENUM_SSLOADPARAMS params)
return(x); return(x);
} }
#ifdef __QT_DRIVER__
// Qt Driver NetPlay state load handler. This is to control state loading,
// only hosts can load states and clients can request loads.
bool NetPlayStateLoadReq(EMUFILE* is);
#endif
bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params) bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
{ {
@ -665,6 +670,13 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
return ret; return ret;
} }
#ifdef __QT_DRIVER__
if ( NetPlayStateLoadReq(is) )
{
return false;
}
#endif
size_t totalsize = FCEU_de32lsb(header + 4); size_t totalsize = FCEU_de32lsb(header + 4);
int stateversion = FCEU_de32lsb(header + 8); int stateversion = FCEU_de32lsb(header + 8);
uint32_t comprlen = FCEU_de32lsb(header + 12); uint32_t comprlen = FCEU_de32lsb(header + 12);
@ -687,7 +699,8 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
int error = uncompress(memory_savestate.buf(), &uncomprlen, &compressed_buf[0], comprlen); int error = uncompress(memory_savestate.buf(), &uncomprlen, &compressed_buf[0], comprlen);
if(error != Z_OK || uncomprlen != totalsize) if(error != Z_OK || uncomprlen != totalsize)
return false; // we dont need to restore the backup here because we havent messed with the emulator state yet return false; // we dont need to restore the backup here because we havent messed with the emulator state yet
} else }
else
{ {
// the savestate is not compressed: just read from is to memory_savestate.vec // the savestate is not compressed: just read from is to memory_savestate.vec
is->fread(memory_savestate.buf(), totalsize); is->fread(memory_savestate.buf(), totalsize);
@ -710,7 +723,8 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
FCEUPPU_LoadState(stateversion); FCEUPPU_LoadState(stateversion);
FCEUSND_LoadState(stateversion); FCEUSND_LoadState(stateversion);
x=FCEUMOV_PostLoad(); x=FCEUMOV_PostLoad();
} else if (backup) }
else if (backup)
{ {
msBackupSavestate.fseek(0,SEEK_SET); msBackupSavestate.fseek(0,SEEK_SET);
FCEUSS_LoadFP(&msBackupSavestate,SSLOADPARAM_NOBACKUP); FCEUSS_LoadFP(&msBackupSavestate,SSLOADPARAM_NOBACKUP);