diff --git a/src/drivers/Qt/NetPlay.cpp b/src/drivers/Qt/NetPlay.cpp index de55d8200..df3a41e74 100644 --- a/src/drivers/Qt/NetPlay.cpp +++ b/src/drivers/Qt/NetPlay.cpp @@ -443,6 +443,9 @@ void NetPlayServer::onRomLoad() //printf("New ROM Loaded!\n"); FCEU_WRAPPER_LOCK(); + opsCrc32 = 0; + netPlayFrameData.reset(); + inputClear(); inputFrameCount = static_cast(currFrameCounter); @@ -460,13 +463,16 @@ void NetPlayServer::onStateLoad() //printf("New State Loaded!\n"); FCEU_WRAPPER_LOCK(); + opsCrc32 = 0; + netPlayFrameData.reset(); + inputClear(); inputFrameCount = static_cast(currFrameCounter); // New State has been loaded by server, signal clients to load and sync for (auto& client : clientList ) { - //sendRomLoadReq( client ); + sendRomLoadReq( client ); sendStateSyncReq( client ); } FCEU_WRAPPER_UNLOCK(); @@ -477,12 +483,16 @@ void NetPlayServer::onNesReset() //printf("NES Reset Event!\n"); FCEU_WRAPPER_LOCK(); + opsCrc32 = 0; + netPlayFrameData.reset(); + inputClear(); inputFrameCount = static_cast(currFrameCounter); // NES Reset has occurred on server, signal clients sync for (auto& client : clientList ) { + sendRomLoadReq( client ); sendStateSyncReq( client ); } FCEU_WRAPPER_UNLOCK(); @@ -530,7 +540,27 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s msg->toHostByteOrder(); printf("Authorize: Player: %i Passwd: %s\n", msg->playerId, msg->pswd); - if (sessionPasswd.isEmpty()) + bool version_chk_ok = true; + + if (enforceAppVersionCheck) + { + version_chk_ok = (msg->appVersionMajor == FCEU_VERSION_MAJOR) && + (msg->appVersionMinor == FCEU_VERSION_MINOR) && + (msg->appVersionPatch == FCEU_VERSION_PATCH); + } + + if (!version_chk_ok) + { + netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG); + errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT); + errorMsg.setFlag(netPlayTextMsgFlags::ERROR); + errorMsg.printf("Client/Host Version Mismatch:\nHost version is %i.%i.%i\nClient version is %i.%i.%i", + FCEU_VERSION_MAJOR, FCEU_VERSION_MINOR, FCEU_VERSION_PATCH, + msg->appVersionMajor, msg->appVersionMinor, msg->appVersionPatch); + sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } ); + client->flushData(); + } + else if (sessionPasswd.isEmpty()) { authentication_passed = true; } @@ -542,6 +572,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s { netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG); errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT); + errorMsg.setFlag(netPlayTextMsgFlags::ERROR); errorMsg.printf("Invalid Password"); sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } ); client->flushData(); @@ -564,6 +595,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s { netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG); errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT); + errorMsg.setFlag(netPlayTextMsgFlags::ERROR); errorMsg.printf("Player %i role is not available", msg->playerId+1); sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } ); client->flushData(); @@ -693,6 +725,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s else { netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG); + errorMsg.setFlag(netPlayTextMsgFlags::WARNING); errorMsg.printf("Host is rejected ROMs load request"); sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } ); } @@ -726,14 +759,10 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s FCEU_WRAPPER_LOCK(); serverRequestedStateLoad = true; + // Clients will be resync'd during this load call. FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP ); serverRequestedStateLoad = false; FCEU_WRAPPER_UNLOCK(); - - opsCrc32 = 0; - netPlayFrameData.reset(); - inputClear(); - resyncAllClients(); } } break; @@ -1347,11 +1376,28 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize ) switch (msgId) { + case NETPLAY_INFO_MSG: + { + auto *msg = static_cast*>(msgBuf); + msg->toHostByteOrder(); + FCEU_printf("NetPlay Info: %s\n", msg->getBuffer()); + + if (msg->isFlagSet(netPlayTextMsgFlags::DISCONNECT)) + { + sock->disconnectFromHost(); + } + FCEU_DispMessage("NetPlay Errors... check message log",0); + } + break; case NETPLAY_ERROR_MSG: { auto *msg = static_cast*>(msgBuf); msg->toHostByteOrder(); - FCEU_printf("NetPlay Error: 0x%X %s\n", msg->code, msg->getBuffer()); + FCEU_printf("NetPlay Error: %s\n", msg->getBuffer()); + + QString msgBoxTxt = tr("Host has replied with an error:\n\n"); + msgBoxTxt += tr(msg->getBuffer()); + QMessageBox::critical( consoleWindow, tr("NetPlay Error"), msgBoxTxt, QMessageBox::Ok ); if (msg->isFlagSet(netPlayTextMsgFlags::DISCONNECT)) { @@ -1547,21 +1593,28 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent) grid->addWidget( lbl, 0, 0, 1, 1 ); grid->addWidget( frameLeadSpinBox, 0, 1, 1, 1 ); + bool enforceAppVersionChk = false; + enforceAppVersionChkCBox = new QCheckBox(tr("Enforce Client Versions Match")); + grid->addWidget( enforceAppVersionChkCBox, 1, 0, 1, 2 ); + g_config->getOption("SDL.NetPlayHostEnforceAppVersionChk", &enforceAppVersionChk); + enforceAppVersionChkCBox->setChecked(enforceAppVersionChk); + bool romLoadReqEna = false; allowClientRomReqCBox = new QCheckBox(tr("Allow Client ROM Load Requests")); - grid->addWidget( allowClientRomReqCBox, 1, 0, 1, 2 ); + grid->addWidget( allowClientRomReqCBox, 2, 0, 1, 2 ); g_config->getOption("SDL.NetPlayHostAllowClientRomLoadReq", &romLoadReqEna); allowClientRomReqCBox->setChecked(romLoadReqEna); bool stateLoadReqEna = false; allowClientStateReqCBox = new QCheckBox(tr("Allow Client State Load Requests")); - grid->addWidget( allowClientStateReqCBox, 2, 0, 1, 2 ); + grid->addWidget( allowClientStateReqCBox, 3, 0, 1, 2 ); g_config->getOption("SDL.NetPlayHostAllowClientStateLoadReq", &stateLoadReqEna); allowClientStateReqCBox->setChecked(stateLoadReqEna); connect(passwordRequiredCBox, SIGNAL(stateChanged(int)), this, SLOT(passwordRequiredChanged(int))); connect(allowClientRomReqCBox, SIGNAL(stateChanged(int)), this, SLOT(allowClientRomReqChanged(int))); connect(allowClientStateReqCBox, SIGNAL(stateChanged(int)), this, SLOT(allowClientStateReqChanged(int))); + connect(enforceAppVersionChkCBox, SIGNAL(stateChanged(int)), this, SLOT(enforceAppVersionChkChanged(int))); startButton = new QPushButton( tr("Start") ); startButton->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton)); @@ -1609,11 +1662,19 @@ void NetPlayHostDialog::passwordRequiredChanged(int state) void NetPlayHostDialog::allowClientRomReqChanged(int state) { g_config->setOption("SDL.NetPlayHostAllowClientRomLoadReq", state != Qt::Unchecked); + g_config->save(); } //----------------------------------------------------------------------------- void NetPlayHostDialog::allowClientStateReqChanged(int state) { g_config->setOption("SDL.NetPlayHostAllowClientStateLoadReq", state != Qt::Unchecked); + g_config->save(); +} +//----------------------------------------------------------------------------- +void NetPlayHostDialog::enforceAppVersionChkChanged(int state) +{ + g_config->setOption("SDL.NetPlayHostEnforceAppVersionChk", state != Qt::Unchecked); + g_config->save(); } //----------------------------------------------------------------------------- void NetPlayHostDialog::onStartClicked(void) @@ -1632,6 +1693,7 @@ void NetPlayHostDialog::onStartClicked(void) server->setRole( playerRoleBox->currentData().toInt() ); server->sessionName = sessionNameEntry->text(); server->setMaxLeadFrames( frameLeadSpinBox->value() ); + server->setEnforceAppVersionCheck( enforceAppVersionChkCBox->isChecked() ); server->setAllowClientRomLoadRequest( allowClientRomReqCBox->isChecked() ); server->setAllowClientStateLoadRequest( allowClientStateReqCBox->isChecked() ); diff --git a/src/drivers/Qt/NetPlay.h b/src/drivers/Qt/NetPlay.h index 08e4d85ff..e9bfe3825 100644 --- a/src/drivers/Qt/NetPlay.h +++ b/src/drivers/Qt/NetPlay.h @@ -139,6 +139,7 @@ class NetPlayServer : public QTcpServer uint32_t getMaxLeadFrames(){ return maxLeadFrames; } void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; } + void setEnforceAppVersionCheck(bool value){ enforceAppVersionCheck = value; } void setAllowClientRomLoadRequest(bool value){ allowClientRomLoadReq = value; } void setAllowClientStateLoadRequest(bool value){ allowClientStateLoadReq = value; } @@ -164,6 +165,7 @@ class NetPlayServer : public QTcpServer uint32_t maxLeadFrames = 10u; uint32_t clientWaitCounter = 0; uint32_t inputFrameCount = 0; + bool enforceAppVersionCheck = true; bool allowClientRomLoadReq = false; bool allowClientStateLoadReq = false; @@ -334,6 +336,7 @@ class NetPlayHostDialog : public QDialog QLineEdit *passwordEntry; QCheckBox *passwordRequiredCBox; QSpinBox *frameLeadSpinBox; + QCheckBox *enforceAppVersionChkCBox; QCheckBox *allowClientRomReqCBox; QCheckBox *allowClientStateReqCBox; @@ -345,6 +348,7 @@ public slots: void passwordRequiredChanged(int state); void allowClientRomReqChanged(int state); void allowClientStateReqChanged(int state); + void enforceAppVersionChkChanged(int state); }; class NetPlayJoinDialog : public QDialog diff --git a/src/drivers/Qt/NetPlayMsgDef.h b/src/drivers/Qt/NetPlayMsgDef.h index 1d8d1393c..960505d2d 100644 --- a/src/drivers/Qt/NetPlayMsgDef.h +++ b/src/drivers/Qt/NetPlayMsgDef.h @@ -4,6 +4,7 @@ #include #include +#include "version.h" // Network Byte Swap Functions uint16_t netPlayByteSwap(uint16_t); @@ -92,12 +93,17 @@ struct netPlayAuthResp { netPlayMsgHdr hdr; + uint16_t appVersionMajor; + uint16_t appVersionMinor; + uint32_t appVersionPatch; char playerId; char userName[64]; char pswd[72]; netPlayAuthResp(void) - : hdr(NETPLAY_AUTH_RESP, sizeof(netPlayAuthResp)), playerId(NETPLAY_SPECTATOR) + : hdr(NETPLAY_AUTH_RESP, sizeof(netPlayAuthResp)), + appVersionMajor(FCEU_VERSION_MAJOR), appVersionMinor(FCEU_VERSION_MINOR), appVersionPatch(FCEU_VERSION_PATCH), + playerId(NETPLAY_SPECTATOR) { memset(pswd, 0, sizeof(pswd)); } @@ -105,19 +111,26 @@ struct netPlayAuthResp void toHostByteOrder() { hdr.toHostByteOrder(); + appVersionMajor = netPlayByteSwap(appVersionMajor); + appVersionMinor = netPlayByteSwap(appVersionMinor); + appVersionPatch = netPlayByteSwap(appVersionPatch); } void toNetworkByteOrder() { hdr.toNetworkByteOrder(); + appVersionMajor = netPlayByteSwap(appVersionMajor); + appVersionMinor = netPlayByteSwap(appVersionMinor); + appVersionPatch = netPlayByteSwap(appVersionPatch); } }; struct netPlayTextMsgFlags { static const uint32_t DISCONNECT = 0x00000001; - static const uint32_t WARNING = 0x00000002; - static const uint32_t INFO = 0x00000004; + static const uint32_t ERROR = 0x00000002; + static const uint32_t WARNING = 0x00000004; + static const uint32_t INFO = 0x00000008; }; template @@ -125,12 +138,11 @@ struct netPlayTextMsg { netPlayMsgHdr hdr; - unsigned short code; - unsigned short flags; - unsigned short dataSize; + uint32_t flags; + uint16_t dataSize; netPlayTextMsg(int type) - : hdr(type, sizeof(netPlayTextMsg)), code(0), flags(0), dataSize(0) + : hdr(type, sizeof(netPlayTextMsg)), flags(0), dataSize(0) { hdr.msgSize = sizeof(*this) - N + 1; memset(data, 0, N); @@ -202,7 +214,6 @@ struct netPlayTextMsg void toHostByteOrder() { hdr.toHostByteOrder(); - code = netPlayByteSwap(code); flags = netPlayByteSwap(flags); dataSize = netPlayByteSwap(dataSize); } @@ -210,7 +221,6 @@ struct netPlayTextMsg void toNetworkByteOrder() { hdr.toNetworkByteOrder(); - code = netPlayByteSwap(code); flags = netPlayByteSwap(flags); dataSize = netPlayByteSwap(dataSize); } diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index 601e2e89e..d996326f9 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -635,6 +635,7 @@ InitConfig() config->addOption("players", "SDL.NetworkPlayers", 1); config->addOption("SDL.NetPlayHostAllowClientRomLoadReq", 0); config->addOption("SDL.NetPlayHostAllowClientStateLoadReq", 0); + config->addOption("SDL.NetPlayHostEnforceAppVersionChk", 1); // input configuration options config->addOption("input1", "SDL.Input.0", "GamePad.0");