diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 446ad872..84c337d6 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -3190,24 +3190,16 @@ void consoleWin_t::openPaletteEditorWin(void) void consoleWin_t::openNetPlayHostWindow(void) { - NetPlayHostDialog *win; - //printf("Open NetPlay Host Window\n"); - win = new NetPlayHostDialog(this); - - win->show(); + openNetPlayHostDialog(this); } void consoleWin_t::openNetPlayJoinWindow(void) { - NetPlayJoinDialog *win; - //printf("Open NetPlay Join Window\n"); - win = new NetPlayJoinDialog(this); - - win->show(); + openNetPlayJoinDialog(this); } void consoleWin_t::closeNetPlaySession(void) diff --git a/src/drivers/Qt/NetPlay.cpp b/src/drivers/Qt/NetPlay.cpp index 2794cba1..b06fee32 100644 --- a/src/drivers/Qt/NetPlay.cpp +++ b/src/drivers/Qt/NetPlay.cpp @@ -19,6 +19,7 @@ */ #include +#include #include "../../fceu.h" #include "../../state.h" @@ -277,24 +278,46 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s { case NETPLAY_AUTH_RESP: { + bool authentication_passed = false; netPlayAuthResp *msg = static_cast(msgBuf); printf("Authorize: Player: %i Passwd: %s\n", msg->playerId, msg->pswd); - if ( claimRole(client, msg->playerId) ) + if (sessionPasswd.isEmpty()) { - client->userName = msg->userName; - sendRomLoadReq( client ); - sendStateSyncReq( client ); - client->state = 1; - FCEU_DispMessage("%s Joined",0, client->userName.toLocal8Bit().constData()); + authentication_passed = true; } else { - netPlayErrorMsg<128> errorMsg; - errorMsg.setDisconnectFlag(); - errorMsg.printf("Player %i role is not available", msg->playerId+1); - sendMsg( client, &errorMsg, errorMsg.hdr.msgSize ); - client->flushData(); + authentication_passed = sessionPasswd.compare(msg->pswd, Qt::CaseSensitive) == 0; + + if (!authentication_passed) + { + netPlayErrorMsg<128> errorMsg; + errorMsg.setDisconnectFlag(); + errorMsg.printf("Invalid Password"); + sendMsg( client, &errorMsg, errorMsg.hdr.msgSize ); + client->flushData(); + } + } + + if (authentication_passed) + { + if ( claimRole(client, msg->playerId) ) + { + client->userName = msg->userName; + sendRomLoadReq( client ); + sendStateSyncReq( client ); + client->state = 1; + FCEU_DispMessage("%s Joined",0, client->userName.toLocal8Bit().constData()); + } + else + { + netPlayErrorMsg<128> errorMsg; + errorMsg.setDisconnectFlag(); + errorMsg.printf("Player %i role is not available", msg->playerId+1); + sendMsg( client, &errorMsg, errorMsg.hdr.msgSize ); + client->flushData(); + } } } break; @@ -502,7 +525,7 @@ void NetPlayClient::forceDisconnect() //----------------------------------------------------------------------------- bool NetPlayClient::isAuthenticated() { - return state > 0; + return (state > 0); } //----------------------------------------------------------------------------- bool NetPlayClient::isPlayerRole() @@ -532,18 +555,18 @@ void NetPlayClient::setSocket(QTcpSocket *s) } } //----------------------------------------------------------------------------- -int NetPlayClient::createSocket(void) +QTcpSocket* NetPlayClient::createSocket(void) { if (sock == nullptr) { sock = new QTcpSocket(this); + + connect(sock, SIGNAL(connected(void)) , this, SLOT(onConnect(void))); + connect(sock, SIGNAL(disconnected(void)), this, SLOT(onDisconnect(void))); + connect(sock, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); } - connect(sock, SIGNAL(connected(void)) , this, SLOT(onConnect(void))); - connect(sock, SIGNAL(disconnected(void)), this, SLOT(onDisconnect(void))); - connect(sock, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); - - return 0; + return sock; } //----------------------------------------------------------------------------- int NetPlayClient::connectToHost( const QString host, int port ) @@ -569,7 +592,9 @@ void NetPlayClient::onConnect(void) { printf("Client Connected!!!\n"); FCEU_DispMessage("Joined Host",0); - connected = true; + _connected = true; + + emit connected(); } //----------------------------------------------------------------------------- void NetPlayClient::onDisconnect(void) @@ -597,6 +622,8 @@ void NetPlayClient::onSocketError(QAbstractSocket::SocketError error) printf("Error: %s\n", errorMsg.toLocal8Bit().constData()); FCEU_DispMessage("%s", 0, errorMsg.toLocal8Bit().constData()); + + emit errorOccurred(errorMsg); } //----------------------------------------------------------------------------- static void clientMessageCallback( void *userData, void *msgBuf, size_t msgSize ) @@ -610,7 +637,7 @@ void NetPlayClient::update(void) { readMessages( clientMessageCallback, this ); - if (connected) + if (_connected) { uint32_t ctlrData = GetGamepadPressedImmediate(); uint32_t currFrame = static_cast(currFrameCounter); @@ -787,6 +814,8 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize ) //----------------------------------------------------------------------------- //--- NetPlayHostDialog //----------------------------------------------------------------------------- +NetPlayHostDialog* NetPlayHostDialog::instance = nullptr; +//----------------------------------------------------------------------------- NetPlayHostDialog::NetPlayHostDialog(QWidget *parent) : QDialog(parent) { @@ -796,6 +825,8 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent) QPushButton *cancelButton, *startButton; QLabel *lbl; + instance = this; + setWindowTitle("NetPlay Host Game"); mainLayout = new QVBoxLayout(); @@ -804,15 +835,18 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent) lbl = new QLabel( tr("Server Name:") ); grid->addWidget( lbl, 0, 0 ); - serverNameEntry = new QLineEdit(); - grid->addWidget( serverNameEntry, 0, 1 ); + sessionNameEntry = new QLineEdit(); + sessionNameEntry->setText("My Game"); + grid->addWidget( sessionNameEntry, 0, 1 ); lbl = new QLabel( tr("Port:") ); grid->addWidget( lbl, 1, 0 ); + int netPort = NetPlayServer::DefaultPort; + g_config->getOption("SDL.NetworkPort", &netPort); portEntry = new QSpinBox(); portEntry->setRange(0,65535); - portEntry->setValue(5050); + portEntry->setValue(netPort); grid->addWidget( portEntry, 1, 1 ); lbl = new QLabel( tr("Role:") ); @@ -827,6 +861,15 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent) playerRoleBox->setCurrentIndex(1); grid->addWidget( playerRoleBox, 2, 1 ); + passwordRequiredCBox = new QCheckBox(tr("Password Required")); + grid->addWidget( passwordRequiredCBox, 3, 0, 1, 2 ); + + lbl = new QLabel( tr("Password:") ); + grid->addWidget( lbl, 4, 0 ); + + passwordEntry = new QLineEdit(); + grid->addWidget( passwordEntry, 4, 1 ); + mainLayout->addLayout(grid); startButton = new QPushButton( tr("Start") ); @@ -848,6 +891,7 @@ NetPlayHostDialog::NetPlayHostDialog(QWidget *parent) //---------------------------------------------------------------------------- NetPlayHostDialog::~NetPlayHostDialog(void) { + instance = nullptr; //printf("Destroy NetPlay Host Window\n"); } //---------------------------------------------------------------------------- @@ -877,20 +921,41 @@ void NetPlayHostDialog::onStartClicked(void) } NetPlayServer::Create(consoleWindow); + const int netPort = portEntry->value(); server = NetPlayServer::GetInstance(); server->setRole( playerRoleBox->currentData().toInt() ); + server->sessionName = sessionNameEntry->text(); + server->sessionPasswd = passwordEntry->text(); - if (server->listen( QHostAddress::Any, portEntry->value() ) == false) + bool listenSucceeded = server->listen( QHostAddress::Any, netPort ); + + if (listenSucceeded) { - printf("Error: TCP server failed to listen\n"); + g_config->setOption("SDL.NetworkPort", netPort); + done(0); + deleteLater(); } + else + { + QString msg = "Failed to start TCP server on port "; + msg += QString::number(netPort); + msg += "\n\nReason: "; + msg += server->errorString(); + QMessageBox::warning( this, tr("TCP Server Error"), msg, QMessageBox::Ok ); - done(0); - deleteLater(); + // Server init failed, destruct server + if (server != nullptr) + { + delete server; + server = nullptr; + } + } } //----------------------------------------------------------------------------- //--- NetPlayJoinDialog //----------------------------------------------------------------------------- +NetPlayJoinDialog* NetPlayJoinDialog::instance = nullptr; +//----------------------------------------------------------------------------- NetPlayJoinDialog::NetPlayJoinDialog(QWidget *parent) : QDialog(parent) { @@ -900,6 +965,8 @@ NetPlayJoinDialog::NetPlayJoinDialog(QWidget *parent) QPushButton *cancelButton, *startButton; QLabel *lbl; + instance = this; + setWindowTitle("NetPlay Join Game"); mainLayout = new QVBoxLayout(); @@ -908,16 +975,20 @@ NetPlayJoinDialog::NetPlayJoinDialog(QWidget *parent) lbl = new QLabel( tr("Host:") ); grid->addWidget( lbl, 0, 0 ); + QString hostAddress = "localhost"; + g_config->getOption("SDL.NetworkIP", &hostAddress); hostEntry = new QLineEdit(); - hostEntry->setText("localhost"); + hostEntry->setText(hostAddress); grid->addWidget( hostEntry, 0, 1 ); lbl = new QLabel( tr("Port:") ); grid->addWidget( lbl, 1, 0 ); + int netPort = NetPlayServer::DefaultPort; + g_config->getOption("SDL.NetworkPort", &netPort); portEntry = new QSpinBox(); portEntry->setRange(0,65535); - portEntry->setValue(5050); + portEntry->setValue(netPort); grid->addWidget( portEntry, 1, 1 ); lbl = new QLabel( tr("Role:") ); @@ -935,11 +1006,9 @@ NetPlayJoinDialog::NetPlayJoinDialog(QWidget *parent) lbl = new QLabel( tr("User:") ); grid->addWidget( lbl, 3, 0 ); - QString name = qgetenv("USER"); - if (name.isEmpty()) - { - name = qgetenv("USERNAME"); - } + QString name; + g_config->getOption("SDL.NetworkUsername", &name); + userNameEntry = new QLineEdit(); userNameEntry->setMaxLength(63); userNameEntry->setText(name); @@ -973,6 +1042,7 @@ NetPlayJoinDialog::NetPlayJoinDialog(QWidget *parent) //---------------------------------------------------------------------------- NetPlayJoinDialog::~NetPlayJoinDialog(void) { + instance = nullptr; //printf("Destroy NetPlay Host Window\n"); } //---------------------------------------------------------------------------- @@ -1002,21 +1072,49 @@ void NetPlayJoinDialog::onJoinClicked(void) } NetPlayClient::Create(consoleWindow); + const int netPort = portEntry->value(); client = NetPlayClient::GetInstance(); client->role = playerRoleBox->currentData().toInt(); client->userName = userNameEntry->text(); client->password = passwordEntry->text(); - if (client->connectToHost( hostEntry->text(), portEntry->value() )) + QString hostAddress = hostEntry->text(); + + connect(client, SIGNAL(connected(void)) , this, SLOT(onConnect(void))); + connect(client, SIGNAL(errorOccurred(const QString&)), this, SLOT(onSocketError(const QString&))); + + if (client->connectToHost( hostAddress, netPort )) { FCEU_DispMessage("Host connect failed",0); } + g_config->setOption("SDL.NetworkIP", hostAddress); + g_config->setOption("SDL.NetworkPort", netPort); +} +//---------------------------------------------------------------------------- +void NetPlayJoinDialog::onConnect() +{ //printf("Close Window\n"); done(0); deleteLater(); } //---------------------------------------------------------------------------- +void NetPlayJoinDialog::onSocketError(const QString& errorMsg) +{ + QString msg = "Failed to connect to server"; + msg += "\n\nReason: "; + msg += errorMsg; + QMessageBox::warning( this, tr("Connection Error"), msg, QMessageBox::Ok ); + + NetPlayClient *client = NetPlayClient::GetInstance(); + + if (client != nullptr) + { + delete client; + client = nullptr; + } +} +//---------------------------------------------------------------------------- //---- Global Functions //---------------------------------------------------------------------------- bool NetPlayActive(void) @@ -1112,3 +1210,37 @@ void NetPlayCloseSession(void) NetPlayServer::Destroy(); } //---------------------------------------------------------------------------- +void openNetPlayHostDialog(QWidget* parent) +{ + NetPlayHostDialog* win = NetPlayHostDialog::GetInstance(); + + if (win == nullptr) + { + win = new NetPlayHostDialog(parent); + + win->show(); + } + else + { + win->activateWindow(); + win->raise(); + } +} +//---------------------------------------------------------------------------- +void openNetPlayJoinDialog(QWidget* parent) +{ + NetPlayJoinDialog* win = NetPlayJoinDialog::GetInstance(); + + if (win == nullptr) + { + win = new NetPlayJoinDialog(parent); + + win->show(); + } + else + { + win->activateWindow(); + win->raise(); + } +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/NetPlay.h b/src/drivers/Qt/NetPlay.h index 8ff86e3b..4768e5aa 100644 --- a/src/drivers/Qt/NetPlay.h +++ b/src/drivers/Qt/NetPlay.h @@ -67,6 +67,7 @@ class NetPlayServer : public QTcpServer NetPlayServer(QObject *parent = 0); ~NetPlayServer(void); + static constexpr int DefaultPort = 4046; static NetPlayServer *GetInstance(void){ return instance; }; static int Create(QObject *parent = 0); @@ -120,6 +121,8 @@ class NetPlayServer : public QTcpServer void serverProcessMessage( NetPlayClient *client, void *msgBuf, size_t msgSize ); + QString sessionName; + QString sessionPasswd; private: static NetPlayServer *instance; @@ -151,11 +154,12 @@ class NetPlayClient : public QObject int connectToHost( const QString host, int port ); - bool isConnected(void); + bool isConnected(void){ return _connected; } bool disconnectRequested(){ return disconnectPending; } void forceDisconnect(); bool flushData(); + QTcpSocket* createSocket(void); void setSocket(QTcpSocket *s); QTcpSocket* getSocket(void){ return sock; }; @@ -211,7 +215,6 @@ class NetPlayClient : public QObject uint8_t gpData[4]; private: - int createSocket(void); static NetPlayClient *instance; @@ -223,13 +226,17 @@ class NetPlayClient : public QObject char *recvMsgBuf = nullptr; bool disconnectPending = false; bool needsDestroy = false; - bool connected = false; + bool _connected = false; std::list input; FCEU::mutex inputMtx; static constexpr size_t recvMsgBufSize = 2 * 1024 * 1024; + signals: + void connected(void); + void errorOccurred(const QString&); + public slots: void onConnect(void); void onDisconnect(void); @@ -245,12 +252,17 @@ public: NetPlayHostDialog(QWidget *parent = 0); ~NetPlayHostDialog(void); + static NetPlayHostDialog *GetInstance(void){ return instance; }; protected: void closeEvent(QCloseEvent *event); - QLineEdit *serverNameEntry; + QLineEdit *sessionNameEntry; QSpinBox *portEntry; QComboBox *playerRoleBox; + QLineEdit *passwordEntry; + QCheckBox *passwordRequiredCBox; + + static NetPlayHostDialog* instance; public slots: void closeWindow(void); @@ -266,6 +278,8 @@ public: NetPlayJoinDialog(QWidget *parent = 0); ~NetPlayJoinDialog(void); + static NetPlayJoinDialog *GetInstance(void){ return instance; }; + protected: void closeEvent(QCloseEvent *event); @@ -275,10 +289,13 @@ protected: QLineEdit *userNameEntry; QLineEdit *passwordEntry; + static NetPlayJoinDialog* instance; + public slots: void closeWindow(void); void onJoinClicked(void); - + void onConnect(void); + void onSocketError(const QString& errorMsg); }; bool NetPlayActive(void); @@ -288,3 +305,5 @@ bool NetPlaySkipWait(void); int NetPlayFrameWait(void); void NetPlayReadInputFrame(uint8_t* joy); void NetPlayCloseSession(void); +void openNetPlayHostDialog(QWidget* parent = nullptr); +void openNetPlayJoinDialog(QWidget* parent = nullptr); diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index e68b3f9e..3d0ae813 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -35,6 +35,7 @@ #include "Qt/sdl-video.h" #include "Qt/AviRecord.h" #include "Qt/unix-netplay.h" +#include "Qt/NetPlay.h" #include "Qt/TasEditor/taseditor_config.h" #ifdef WIN32 @@ -618,13 +619,19 @@ InitConfig() config->addOption("SDL.winFullScreenBorder", 0); #endif + QString userName = qgetenv("USER"); + if (userName.isEmpty()) + { + userName = qgetenv("USERNAME"); + } + // network play options - netplay is broken config->addOption("server", "SDL.NetworkIsServer", 0); - config->addOption('n', "net", "SDL.NetworkIP", ""); - config->addOption('u', "user", "SDL.NetworkUsername", ""); + config->addOption('n', "net", "SDL.NetworkIP", "localhost"); + config->addOption('u', "user", "SDL.NetworkUsername", userName.toLocal8Bit().constData()); config->addOption('w', "pass", "SDL.NetworkPassword", ""); config->addOption('k', "netkey", "SDL.NetworkGameKey", ""); - config->addOption("port", "SDL.NetworkPort", 4046); + config->addOption("port", "SDL.NetworkPort", NetPlayServer::DefaultPort); config->addOption("players", "SDL.NetworkPlayers", 1); // input configuration options