diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt index 0f6069c0..ce424033 100644 --- a/docs/net_protocol.txt +++ b/docs/net_protocol.txt @@ -264,12 +264,28 @@ Server Reply: Join Game Ack +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Server Reply: Join Game Failed + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 12 | Message Length = 8 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Failure Reason | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Failure Reason: + 0x0001 - Game is full + 0x0002 - Game is already running + 0x0003 - Invalid Password + 0xFFFF - Other reason + + Server Notification: Player Joined 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 12 | Message Length = 12 | + | Message Type = 13 | Message Length = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -284,7 +300,7 @@ Server Notification: Player Left 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 13 | Message Length = 8 | + | Message Type = 14 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -295,7 +311,7 @@ Client Request: Kick Player 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 14 | Message Length = 8 | + | Message Type = 15 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -306,10 +322,11 @@ Client Request: Leave Current Game 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 15 | Message Length = 8 | + | Message Type = 16 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +(will be answered with a Server Notification: Removed From Game) Client Request: Start Event @@ -317,7 +334,7 @@ Client Request: Start Event 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 16 | Message Length = 8 | + | Message Type = 17 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Flags | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -330,7 +347,7 @@ Server Notification: Game Start 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 17 | Message Length | + | Message Type = 18 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Dealer Player Id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -361,7 +378,7 @@ Server Notification: Hand Start 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 18 | Message Length = 8 | + | Message Type = 19 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Your 1st Card | Your 2nd Card | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -375,7 +392,7 @@ Server Request/Notification: Player's Turn 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 19 | Message Length = 8 | + | Message Type = 20 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -394,7 +411,7 @@ Client Reply/Request: Player's Action 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 20 | Message Length = 12 | + | Message Type = 21 | Message Length = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Game State | Player Action | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -419,7 +436,7 @@ Server Notification: Player's Action Done 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 21 | Message Length = 20 | + | Message Type = 22 | Message Length = 20 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -440,7 +457,7 @@ Server Reply: Player's Action Rejected 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 22 | Message Length = 16 | + | Message Type = 23 | Message Length = 16 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Game State | Player Action | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -468,7 +485,7 @@ Server Notification: Deal Flop Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 23 | Message Length = 12 | + | Message Type = 24 | Message Length = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Flop 1st Card | Flop 2nd Card | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -481,7 +498,7 @@ Server Notification: Deal Turn Card 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 24 | Message Length = 8 | + | Message Type = 25 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Turn Card | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -492,7 +509,7 @@ Server Notification: Deal River Card 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 25 | Message Length = 8 | + | Message Type = 26 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | River Card | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -503,7 +520,7 @@ Server Notification: All In Show Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 26 | Message Length | + | Message Type = 27 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Number Of PlayerCards Records | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -525,7 +542,7 @@ Server Notification: End Of Hand Show Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 27 | Message Length | + | Message Type = 28 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Number Of PlayerResult Records | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -559,7 +576,7 @@ Server Notification: End Of Hand Hide Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 28 | Message Length = 16 | + | Message Type = 29 | Message Length = 16 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -574,12 +591,30 @@ Server Notification: End Of Game 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 29 | Message Length = 8 | + | Message Type = 30 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Winner Player Id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Server Notification: Removed From Game + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 256 | Message Length = 8 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Remove Reason | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Remove Reason: + 0x0000 - On Request (no error) + 0x0001 - Game is full + 0x0002 - Game is already running + 0x0003 - Kicked from the game + 0xFFFF - Other reason + + + Client Request: Send Chat Text 0 1 2 3 @@ -614,7 +649,7 @@ Server Notification: Chat Text +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -Server Reply: Error +Server Notification: Error 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -625,12 +660,13 @@ Server Reply: Error +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Error Reason: - 0x0001 - Join Game - Version not supported - 0x0002 - Join Game - Server full - 0x0003 - Join Game - Game is already running - 0x0004 - Join Game - Invalid Password - 0x0005 - Join Game - Player Name already in use - 0x0006 - Join Game - Invalid Player Name + 0x0000 - Reserved + 0x0001 - Init - Version not supported + 0x0002 - Init - Server Full + 0x0003 - Init - (unused) + 0x0004 - Init - Invalid Password + 0x0005 - Init - Player Name already in use + 0x0006 - Init - Invalid Player Name 0xFF01 - General Error - Invalid packet 0xFF02 - General Error - Invalid state 0xFF03 - General Error - Kicked from the server diff --git a/src/engine/playerinterface.h b/src/engine/playerinterface.h index c2a6e6da..a57bac45 100644 --- a/src/engine/playerinterface.h +++ b/src/engine/playerinterface.h @@ -80,8 +80,8 @@ public: virtual void setMyCardsValueInt(int theValue) =0; virtual int getMyCardsValueInt() const =0; - virtual void setMyBestHandPosition(int* theValue) =0; - virtual void getMyBestHandPosition(int* theValue) const =0; + virtual void setMyBestHandPosition(int* theValue) =0; + virtual void getMyBestHandPosition(int* theValue) const =0; virtual void setMyRoundStartCash(int theValue) =0; virtual int getMyRoundStartCash() const =0; diff --git a/src/gui/generic/serverguiwrapper.cpp b/src/gui/generic/serverguiwrapper.cpp index 1c200e6d..235a3eaa 100644 --- a/src/gui/generic/serverguiwrapper.cpp +++ b/src/gui/generic/serverguiwrapper.cpp @@ -108,6 +108,8 @@ void ServerGuiWrapper::logPlayerWinGame(std::string playerName, int gameID) {} void ServerGuiWrapper::SignalNetClientConnect(int actionID) { if (myClientcb) myClientcb->SignalNetClientConnect(actionID); } void ServerGuiWrapper::SignalNetClientGameInfo(int actionID) { if (myClientcb) myClientcb->SignalNetClientGameInfo(actionID); } void ServerGuiWrapper::SignalNetClientError(int errorID, int osErrorID) { if (myClientcb) myClientcb->SignalNetClientError(errorID, osErrorID); } +void ServerGuiWrapper::SignalNetClientNotification(int notificationId) { if (myClientcb) myClientcb->SignalNetClientNotification(notificationId); } +void ServerGuiWrapper::SignalNetClientRemovedFromGame(int notificationId) { if (myClientcb) myClientcb->SignalNetClientRemovedFromGame(notificationId); } void ServerGuiWrapper::SignalNetClientSelfJoined(unsigned playerId, const std::string &playerName, PlayerRights rights) { if (myClientcb) myClientcb->SignalNetClientSelfJoined(playerId, playerName, rights); } void ServerGuiWrapper::SignalNetClientPlayerJoined(unsigned playerId, const std::string &playerName, PlayerRights rights) { if (myClientcb) myClientcb->SignalNetClientPlayerJoined(playerId, playerName, rights); } void ServerGuiWrapper::SignalNetClientPlayerChanged(unsigned playerId, const std::string &newPlayerName) { if (myClientcb) myClientcb->SignalNetClientPlayerChanged(playerId, newPlayerName); } diff --git a/src/gui/generic/serverguiwrapper.h b/src/gui/generic/serverguiwrapper.h index 327a0699..481a88c0 100644 --- a/src/gui/generic/serverguiwrapper.h +++ b/src/gui/generic/serverguiwrapper.h @@ -92,6 +92,8 @@ public: void SignalNetClientConnect(int actionID); void SignalNetClientGameInfo(int actionID); void SignalNetClientError(int errorID, int osErrorID); + void SignalNetClientNotification(int notificationId); + void SignalNetClientRemovedFromGame(int notificationId); void SignalNetClientSelfJoined(unsigned playerId, const std::string &playerName, PlayerRights rights); void SignalNetClientPlayerJoined(unsigned playerId, const std::string &playerName, PlayerRights rights); void SignalNetClientPlayerChanged(unsigned playerId, const std::string &newPlayerName); diff --git a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp index e82226a7..34a05519 100644 --- a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp +++ b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.cpp @@ -25,6 +25,7 @@ gameLobbyDialogImpl::gameLobbyDialogImpl(QWidget *parent, ConfigFile *c) connect( treeWidget_GameList, SIGNAL( currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem*) ), this, SLOT( gameSelected(QTreeWidgetItem*, QTreeWidgetItem*) ) ); connect( pushButton_StartGame, SIGNAL( clicked() ), this, SLOT( startGame() ) ); connect( pushButton_Kick, SIGNAL( clicked() ), this, SLOT( kickPlayer() ) ); + connect( pushButton_Leave, SIGNAL( clicked() ), this, SLOT( leaveGame() ) ); connect( treeWidget_connectedPlayers, SIGNAL( currentItemChanged ( QTreeWidgetItem*, QTreeWidgetItem*) ), this, SLOT( playerSelected(QTreeWidgetItem*, QTreeWidgetItem*) ) ); clearDialog(); @@ -66,9 +67,6 @@ void gameLobbyDialogImpl::createGame() currentGameName = QString::fromUtf8(myConfig->readConfigString("MyName").c_str()) + QString("'s game"); - // Update dialog - gameModeDialogUpdate(); - label_SmallBlind->setText(QString::number(gameData.smallBlind)); label_StartCash->setText(QString::number(gameData.startMoney)); label_MaximumNumberOfPlayers->setText(QString::number(gameData.maxNumberOfPlayers)); @@ -86,9 +84,6 @@ void gameLobbyDialogImpl::joinGame() { assert(mySession); mySession->clientJoinGame(item->data(0, Qt::UserRole).toUInt(), ""); - - // Update dialog - gameModeDialogUpdate(); } } @@ -100,6 +95,11 @@ void gameLobbyDialogImpl::refresh(int actionID) { } } +void gameLobbyDialogImpl::removedFromGame(int reason) +{ + clearDialog(); +} + void gameLobbyDialogImpl::gameSelected(QTreeWidgetItem* item, QTreeWidgetItem*) { if (item) @@ -259,6 +259,9 @@ void gameLobbyDialogImpl::checkPlayerQuantity() { void gameLobbyDialogImpl::joinedNetworkGame(unsigned playerId, QString playerName, int rights) { + // Update dialog + gameModeDialogUpdate(); + isAdmin = rights == PLAYER_RIGHTS_ADMIN; addConnectedPlayer(playerId, playerName, rights); } @@ -329,10 +332,17 @@ void gameLobbyDialogImpl::playerSelected(QTreeWidgetItem* item, QTreeWidgetItem* } void gameLobbyDialogImpl::startGame() { + assert(mySession); mySession->sendStartEvent(checkBox_fillUpWithComputerOpponents->isChecked()); } +void gameLobbyDialogImpl::leaveGame() { + + assert(mySession); + mySession->sendLeaveCurrentGame(); +} + void gameLobbyDialogImpl::kickPlayer() { QTreeWidgetItem *item = treeWidget_connectedPlayers->currentItem(); diff --git a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h index 7d0f554a..5b5039ad 100644 --- a/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h +++ b/src/gui/qt/gamelobbydialog/gamelobbydialogimpl.h @@ -65,7 +65,9 @@ public slots: void playerSelected(QTreeWidgetItem*, QTreeWidgetItem*); void refresh(int actionID); + void removedFromGame(int reason); void startGame(); + void leaveGame(); void kickPlayer(); void gameModeDialogUpdate(); diff --git a/src/gui/qt/guiwrapper.cpp b/src/gui/qt/guiwrapper.cpp index 6003f113..496c6fd8 100644 --- a/src/gui/qt/guiwrapper.cpp +++ b/src/gui/qt/guiwrapper.cpp @@ -111,6 +111,8 @@ void GuiWrapper::logPlayerWinGame(std::string playerName, int gameID) { myLog->s void GuiWrapper::SignalNetClientConnect(int actionID) { myW->signalNetClientConnect(actionID); } void GuiWrapper::SignalNetClientGameInfo(int actionID) { myW->signalNetClientGameInfo(actionID); } void GuiWrapper::SignalNetClientError(int errorID, int osErrorID) { myW->signalNetClientError(errorID, osErrorID); } +void GuiWrapper::SignalNetClientNotification(int notificationId) { myW->signalNetClientNotification(notificationId); } +void GuiWrapper::SignalNetClientRemovedFromGame(int notificationId) { myW->signalNetClientRemovedFromGame(notificationId); } void GuiWrapper::SignalNetClientSelfJoined(unsigned playerId, const string &playerName, PlayerRights rights) { myW->signalNetClientSelfJoined(playerId, QString::fromUtf8(playerName.c_str()), rights); } void GuiWrapper::SignalNetClientPlayerJoined(unsigned playerId, const string &playerName, PlayerRights rights) { myW->signalNetClientPlayerJoined(playerId, QString::fromUtf8(playerName.c_str()), rights); } void GuiWrapper::SignalNetClientPlayerChanged(unsigned playerId, const string &newPlayerName) diff --git a/src/gui/qt/guiwrapper.h b/src/gui/qt/guiwrapper.h index e858c015..f7c6e38e 100644 --- a/src/gui/qt/guiwrapper.h +++ b/src/gui/qt/guiwrapper.h @@ -99,6 +99,8 @@ public: void SignalNetClientConnect(int actionID); void SignalNetClientGameInfo(int actionID); void SignalNetClientError(int errorID, int osErrorID); + void SignalNetClientNotification(int notificationId); + void SignalNetClientRemovedFromGame(int notificationId); void SignalNetClientSelfJoined(unsigned playerId, const std::string &playerName, PlayerRights rights); void SignalNetClientPlayerJoined(unsigned playerId, const std::string &playerName, PlayerRights rights); void SignalNetClientPlayerChanged(unsigned playerId, const std::string &newPlayerName); diff --git a/src/gui/qt/mainwindow/mainwindowimpl.cpp b/src/gui/qt/mainwindow/mainwindowimpl.cpp index 4fa479a8..d3cf9080 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.cpp +++ b/src/gui/qt/mainwindow/mainwindowimpl.cpp @@ -663,9 +663,12 @@ mainWindowImpl::mainWindowImpl(ConfigFile *c, QMainWindow *parent) connect(this, SIGNAL(signalNetClientGameListRemove(unsigned)), myGameLobbyDialog, SLOT(removeGame(unsigned))); connect(this, SIGNAL(signalNetClientGameListPlayerJoined(unsigned, unsigned)), myGameLobbyDialog, SLOT(gameAddPlayer(unsigned, unsigned))); connect(this, SIGNAL(signalNetClientGameListPlayerLeft(unsigned, unsigned)), myGameLobbyDialog, SLOT(gameRemovePlayer(unsigned, unsigned))); + connect(this, SIGNAL(signalNetClientRemovedFromGame(int)), myGameLobbyDialog, SLOT(removedFromGame(int))); // Errors are handled globally, not within one dialog. connect(this, SIGNAL(signalNetClientError(int, int)), this, SLOT(networkError(int, int))); + connect(this, SIGNAL(signalNetClientNotification(int)), this, SLOT(networkNotification(int))); + connect(this, SIGNAL(signalNetClientRemovedFromGame(int)), this, SLOT(networkNotification(int))); connect(this, SIGNAL(signalNetServerError(int, int)), this, SLOT(networkError(int, int))); connect(this, SIGNAL(signalNetClientGameStart(boost::shared_ptr)), this, SLOT(networkStart(boost::shared_ptr))); @@ -2587,11 +2590,6 @@ void mainWindowImpl::networkError(int errorID, int osErrorID) { tr("Sorry, this server is already full."), QMessageBox::Close); } break; - case ERR_NET_GAME_ALREADY_RUNNING: - { QMessageBox::warning(this, tr("Network Error"), - tr("Unable to join - the server has already started the game."), - QMessageBox::Close); } - break; case ERR_NET_INVALID_PASSWORD: { QMessageBox::warning(this, tr("Network Error"), tr("Invalid password when joining the game.\nPlease reenter the password and try again."), @@ -2649,6 +2647,35 @@ void mainWindowImpl::networkError(int errorID, int osErrorID) { myStartNetworkGameDialog->reject(); } +void mainWindowImpl::networkNotification(int notificationId) +{ + switch (notificationId) + { + case NTF_NET_REMOVED_KICKED: + { QMessageBox::warning(this, tr("Network Notification"), + tr("You were kicked from the game."), + QMessageBox::Close); } + break; + case NTF_NET_REMOVED_GAME_FULL: + case NTF_NET_JOIN_GAME_FULL: + { QMessageBox::warning(this, tr("Network Notification"), + tr("Sorry, this game is already full."), + QMessageBox::Close); } + break; + case NTF_NET_REMOVED_ALREADY_RUNNING: + case NTF_NET_JOIN_ALREADY_RUNNING: + { QMessageBox::warning(this, tr("Network Notification"), + tr("Unable to join - the server has already started the game."), + QMessageBox::Close); } + break; + case NTF_NET_JOIN_INVALID_PASSWORD: + { QMessageBox::warning(this, tr("Network Notification"), + tr("Invalid password when joining the game.\nPlease reenter the password and try again."), + QMessageBox::Close); } + break; + } +} + void mainWindowImpl::networkStart(boost::shared_ptr game) { mySession->startClientGame(game); diff --git a/src/gui/qt/mainwindow/mainwindowimpl.h b/src/gui/qt/mainwindow/mainwindowimpl.h index 1071019a..16bc4189 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.h +++ b/src/gui/qt/mainwindow/mainwindowimpl.h @@ -126,6 +126,8 @@ signals: void signalNetClientConnect(int actionID); void signalNetClientGameInfo(int actionID); void signalNetClientError(int errorID, int osErrorID); + void signalNetClientNotification(int notificationId); + void signalNetClientRemovedFromGame(int notificationId); void signalNetServerError(int errorID, int osErrorID); void signalNetClientSelfJoined(unsigned playerId, QString playerName, int rights); void signalNetClientPlayerJoined(unsigned playerId, QString playerName, int rights); @@ -276,6 +278,7 @@ public slots: void tabSwitchAction(); void networkError(int, int); + void networkNotification(int); void networkStart(boost::shared_ptr game); void closeEvent(QCloseEvent*); diff --git a/src/net/clientcallback.h b/src/net/clientcallback.h index a0387d76..b4bc89c0 100644 --- a/src/net/clientcallback.h +++ b/src/net/clientcallback.h @@ -35,6 +35,8 @@ public: virtual void SignalNetClientConnect(int actionID) = 0; virtual void SignalNetClientGameInfo(int actionID) = 0; virtual void SignalNetClientError(int errorID, int osErrorID) = 0; + virtual void SignalNetClientNotification(int notificationId) = 0; + virtual void SignalNetClientRemovedFromGame(int notificationId) = 0; virtual void SignalNetClientGameListNew(unsigned gameId) = 0; virtual void SignalNetClientGameListRemove(unsigned gameId) = 0; diff --git a/src/net/clientthread.h b/src/net/clientthread.h index 1e0ee658..d1b85ebc 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -55,6 +55,7 @@ public: const std::string &playerName); void SendKickPlayer(unsigned playerId); + void SendLeaveCurrentGame(); void SendStartEvent(bool fillUpWithCpuPlayers); void SendPlayerAction(); void SendChatMessage(const std::string &msg); @@ -105,6 +106,7 @@ protected: void AddPlayerData(boost::shared_ptr playerData); void RemovePlayerData(unsigned playerId); + void ClearPlayerDataList(); void MapPlayerDataList(); const PlayerDataList &GetPlayerDataList() const; boost::shared_ptr GetPlayerDataByUniqueId(unsigned id); @@ -117,6 +119,7 @@ protected: void RemoveGameInfo(unsigned gameId); void ModifyGameInfoAddPlayer(unsigned gameId, unsigned playerId); void ModifyGameInfoRemovePlayer(unsigned gameId, unsigned playerId); + void ClearGameInfoMap(); bool IsSessionEstablished() const; void SetSessionEstablished(bool flag); diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 4b8a6fec..a67e6c24 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -387,6 +387,15 @@ AbstractClientStateReceiving::Process(ClientThread &client) tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData); client.SetPlayerInfo(infoData.playerId, infoData.playerInfo); } + else if (tmpPacket->ToNetPacketRemovedFromGame()) + { + NetPacketRemovedFromGame::Data removedData; + tmpPacket->ToNetPacketRemovedFromGame()->GetData(removedData); + client.ClearPlayerDataList(); + client.ClearGameInfoMap(); + client.GetCallback().SignalNetClientRemovedFromGame(removedData.removeReason); + client.SetState(ClientStateWaitJoin::Instance()); + } else if (tmpPacket->ToNetPacketError()) { // Server reported an error. @@ -545,6 +554,13 @@ ClientStateWaitJoin::InternalProcess(ClientThread &client, boost::shared_ptrToNetPacketJoinGameFailed()) + { + // Failed to join a game. + NetPacketJoinGameFailed::Data joinGameFailedData; + packet->ToNetPacketJoinGameFailed()->GetData(joinGameFailedData); + client.GetCallback().SignalNetClientNotification(joinGameFailedData.failureCode); + } return retVal; } diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index 1794515b..413e161b 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -97,6 +97,14 @@ ClientThread::SendKickPlayer(unsigned playerId) m_outPacketList.push_back(request); } +void +ClientThread::SendLeaveCurrentGame() +{ + boost::shared_ptr request(new NetPacketLeaveCurrentGame); + boost::mutex::scoped_lock lock(m_outPacketListMutex); + m_outPacketList.push_back(request); +} + void ClientThread::SendStartEvent(bool fillUpWithCpuPlayers) { @@ -507,6 +515,12 @@ ClientThread::RemovePlayerData(unsigned playerId) } } +void +ClientThread::ClearPlayerDataList() +{ + m_playerDataList.clear(); +} + void ClientThread::MapPlayerDataList() { @@ -692,6 +706,13 @@ ClientThread::ModifyGameInfoRemovePlayer(unsigned gameId, unsigned playerId) GetCallback().SignalNetClientGameListPlayerLeft(gameId, playerId); } +void +ClientThread::ClearGameInfoMap() +{ + boost::mutex::scoped_lock lock(m_gameInfoMapMutex); + m_gameInfoMap.clear(); +} + bool ClientThread::IsSessionEstablished() const { diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index 6bc92bde..ed781203 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -38,24 +38,27 @@ using namespace std; #define NET_TYPE_CREATE_GAME 0x0009 #define NET_TYPE_JOIN_GAME 0x000A #define NET_TYPE_JOIN_GAME_ACK 0x000B -#define NET_TYPE_PLAYER_JOINED 0x000C -#define NET_TYPE_PLAYER_LEFT 0x000D -#define NET_TYPE_KICK_PLAYER 0x000E -#define NET_TYPE_LEAVE_CURRENT_GAME 0x000F -#define NET_TYPE_START_EVENT 0x0010 -#define NET_TYPE_GAME_START 0x0011 -#define NET_TYPE_HAND_START 0x0012 -#define NET_TYPE_PLAYERS_TURN 0x0013 -#define NET_TYPE_PLAYERS_ACTION 0x0014 -#define NET_TYPE_PLAYERS_ACTION_DONE 0x0015 -#define NET_TYPE_PLAYERS_ACTION_REJECTED 0x0016 -#define NET_TYPE_DEAL_FLOP_CARDS 0x0017 -#define NET_TYPE_DEAL_TURN_CARD 0x0018 -#define NET_TYPE_DEAL_RIVER_CARD 0x0019 -#define NET_TYPE_ALL_IN_SHOW_CARDS 0x001A -#define NET_TYPE_END_OF_HAND_SHOW_CARDS 0x001B -#define NET_TYPE_END_OF_HAND_HIDE_CARDS 0x001C -#define NET_TYPE_END_OF_GAME 0x001D +#define NET_TYPE_JOIN_GAME_FAILED 0x000C +#define NET_TYPE_PLAYER_JOINED 0x000D +#define NET_TYPE_PLAYER_LEFT 0x000E +#define NET_TYPE_KICK_PLAYER 0x000F +#define NET_TYPE_LEAVE_CURRENT_GAME 0x0010 +#define NET_TYPE_START_EVENT 0x0011 +#define NET_TYPE_GAME_START 0x0012 +#define NET_TYPE_HAND_START 0x0013 +#define NET_TYPE_PLAYERS_TURN 0x0014 +#define NET_TYPE_PLAYERS_ACTION 0x0015 +#define NET_TYPE_PLAYERS_ACTION_DONE 0x0016 +#define NET_TYPE_PLAYERS_ACTION_REJECTED 0x0017 +#define NET_TYPE_DEAL_FLOP_CARDS 0x0018 +#define NET_TYPE_DEAL_TURN_CARD 0x0019 +#define NET_TYPE_DEAL_RIVER_CARD 0x001A +#define NET_TYPE_ALL_IN_SHOW_CARDS 0x001B +#define NET_TYPE_END_OF_HAND_SHOW_CARDS 0x001C +#define NET_TYPE_END_OF_HAND_HIDE_CARDS 0x001D +#define NET_TYPE_END_OF_GAME 0x001E + +#define NET_TYPE_REMOVED_FROM_GAME 0x0100 #define NET_TYPE_SEND_CHAT_TEXT 0x0200 #define NET_TYPE_CHAT_TEXT 0x0201 @@ -69,12 +72,26 @@ using namespace std; #define NET_START_FLAG_FILL_WITH_CPU_PLAYERS 0x01 -#define NET_ERR_JOIN_GAME_VERSION_NOT_SUPPORTED 0x0001 -#define NET_ERR_JOIN_GAME_SERVER_FULL 0x0002 -#define NET_ERR_JOIN_GAME_ALREADY_RUNNING 0x0003 -#define NET_ERR_JOIN_GAME_INVALID_PASSWORD 0x0004 -#define NET_ERR_JOIN_GAME_PLAYER_NAME_IN_USE 0x0005 -#define NET_ERR_JOIN_GAME_INVALID_PLAYER_NAME 0x0006 +// Reasons why join game failed. +#define NET_JOIN_FAILED_GAME_FULL 0x0001 +#define NET_JOIN_FAILED_GAME_ALREADY_RUNNING 0x0002 +#define NET_JOIN_FAILED_INVALID_PASSWORD 0x0003 +#define NET_JOIN_FAILED_OTHER 0xFFFF + +// Reasons for being removed from a game. +#define NET_REMOVED_ON_REQUEST 0x0000 +#define NET_REMOVED_GAME_FULL 0x0001 +#define NET_REMOVED_GAME_ALREADY_RUNNING 0x0002 +#define NET_REMOVED_KICKED 0x0003 +#define NET_REMOVED_OTHER_REASON 0xFFFF + +// Internal error codes. +#define NET_ERR_RESERVED 0x0000 +#define NET_ERR_INIT_VERSION_NOT_SUPPORTED 0x0001 +#define NET_ERR_INIT_SERVER_FULL 0x0002 +#define NET_ERR_INIT_INVALID_PASSWORD 0x0004 +#define NET_ERR_INIT_PLAYER_NAME_IN_USE 0x0005 +#define NET_ERR_INIT_INVALID_PLAYER_NAME 0x0006 #define NET_ERR_GENERAL_INVALID_PACKET 0xFF01 #define NET_ERR_GENERAL_INVALID_STATE 0xFF02 #define NET_ERR_GENERAL_PLAYER_KICKED 0xFF03 @@ -199,6 +216,13 @@ struct GCC_PACKED NetPacketJoinGameAckData u_int32_t startMoney; }; +struct GCC_PACKED NetPacketJoinGameFailedData +{ + NetPacketHeader head; + u_int16_t failureReason; + u_int16_t reserved; +}; + struct GCC_PACKED NetPacketPlayerJoinedData { NetPacketHeader head; @@ -362,6 +386,13 @@ struct GCC_PACKED NetPacketEndOfGameData u_int32_t winnerPlayerId; }; +struct GCC_PACKED NetPacketRemovedFromGameData +{ + NetPacketHeader head; + u_int16_t removeReason; + u_int16_t reserved; +}; + struct GCC_PACKED NetPacketSendChatTextData { NetPacketHeader head; @@ -380,7 +411,7 @@ struct GCC_PACKED NetPacketChatTextData struct GCC_PACKED NetPacketErrorData { NetPacketHeader head; - u_int16_t reason; + u_int16_t errorReason; u_int16_t reserved; }; @@ -450,6 +481,9 @@ NetPacket::Create(char *data, unsigned &dataSize) case NET_TYPE_JOIN_GAME_ACK: tmpPacket = boost::shared_ptr(new NetPacketJoinGameAck); break; + case NET_TYPE_JOIN_GAME_FAILED: + tmpPacket = boost::shared_ptr(new NetPacketJoinGameFailed); + break; case NET_TYPE_PLAYER_JOINED: tmpPacket = boost::shared_ptr(new NetPacketPlayerJoined); break; @@ -459,6 +493,9 @@ NetPacket::Create(char *data, unsigned &dataSize) case NET_TYPE_KICK_PLAYER: tmpPacket = boost::shared_ptr(new NetPacketKickPlayer); break; + case NET_TYPE_LEAVE_CURRENT_GAME: + tmpPacket = boost::shared_ptr(new NetPacketLeaveCurrentGame); + break; case NET_TYPE_START_EVENT: tmpPacket = boost::shared_ptr(new NetPacketStartEvent); break; @@ -501,6 +538,9 @@ NetPacket::Create(char *data, unsigned &dataSize) case NET_TYPE_END_OF_GAME: tmpPacket = boost::shared_ptr(new NetPacketEndOfGame); break; + case NET_TYPE_REMOVED_FROM_GAME: + tmpPacket = boost::shared_ptr(new NetPacketRemovedFromGame); + break; case NET_TYPE_SEND_CHAT_TEXT: tmpPacket = boost::shared_ptr(new NetPacketSendChatText); break; @@ -660,6 +700,12 @@ NetPacket::ToNetPacketJoinGameAck() const return NULL; } +const NetPacketJoinGameFailed * +NetPacket::ToNetPacketJoinGameFailed() const +{ + return NULL; +} + const NetPacketPlayerJoined * NetPacket::ToNetPacketPlayerJoined() const { @@ -678,6 +724,12 @@ NetPacket::ToNetPacketKickPlayer() const return NULL; } +const NetPacketLeaveCurrentGame * +NetPacket::ToNetPacketLeaveCurrentGame() const +{ + return NULL; +} + const NetPacketStartEvent * NetPacket::ToNetPacketStartEvent() const { @@ -762,6 +814,12 @@ NetPacket::ToNetPacketEndOfGame() const return NULL; } +const NetPacketRemovedFromGame * +NetPacket::ToNetPacketRemovedFromGame() const +{ + return NULL; +} + const NetPacketSendChatText * NetPacket::ToNetPacketSendChatText() const { @@ -1776,6 +1834,92 @@ NetPacketJoinGameAck::InternalCheck(const NetPacketHeader* data) const //----------------------------------------------------------------------------- +NetPacketJoinGameFailed::NetPacketJoinGameFailed() +: NetPacket(NET_TYPE_JOIN_GAME_FAILED, sizeof(NetPacketJoinGameFailedData), sizeof(NetPacketJoinGameFailedData)) +{ +} + +NetPacketJoinGameFailed::~NetPacketJoinGameFailed() +{ +} + +boost::shared_ptr +NetPacketJoinGameFailed::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketJoinGameFailed); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketJoinGameFailed::SetData(const NetPacketJoinGameFailed::Data &inData) +{ + NetPacketJoinGameFailedData *tmpData = (NetPacketJoinGameFailedData *)GetRawData(); + + switch (inData.failureCode) + { + // Join Game Errors. + case NTF_NET_JOIN_GAME_FULL : + tmpData->failureReason = htons(NET_JOIN_FAILED_GAME_FULL); + break; + case NTF_NET_JOIN_ALREADY_RUNNING : + tmpData->failureReason = htons(NET_JOIN_FAILED_GAME_ALREADY_RUNNING); + break; + case NTF_NET_JOIN_INVALID_PASSWORD : + tmpData->failureReason = htons(NET_JOIN_FAILED_INVALID_PASSWORD); + break; + default : + tmpData->failureReason = htons(NET_JOIN_FAILED_OTHER); + break; + } + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketJoinGameFailed::GetData(NetPacketJoinGameFailed::Data &outData) const +{ + NetPacketJoinGameFailedData *tmpData = (NetPacketJoinGameFailedData *)GetRawData(); + + switch (ntohs(tmpData->failureReason)) + { + // Join Game Errors. + case NET_JOIN_FAILED_GAME_FULL : + outData.failureCode = NTF_NET_JOIN_GAME_FULL; + break; + case NET_JOIN_FAILED_GAME_ALREADY_RUNNING : + outData.failureCode = NTF_NET_JOIN_ALREADY_RUNNING; + break; + case NET_JOIN_FAILED_INVALID_PASSWORD : + outData.failureCode = NTF_NET_JOIN_INVALID_PASSWORD; + break; + default : + outData.failureCode = NTF_NET_INTERNAL; + break; + } +} + +const NetPacketJoinGameFailed * +NetPacketJoinGameFailed::ToNetPacketJoinGameFailed() const +{ + return this; +} + +void +NetPacketJoinGameFailed::InternalCheck(const NetPacketHeader*) const +{ + // Nothing to do. +} + +//----------------------------------------------------------------------------- + NetPacketPlayerJoined::NetPacketPlayerJoined() : NetPacket(NET_TYPE_PLAYER_JOINED, sizeof(NetPacketPlayerJoinedData), sizeof(NetPacketPlayerJoinedData)) { @@ -1952,6 +2096,43 @@ NetPacketKickPlayer::InternalCheck(const NetPacketHeader*) const //----------------------------------------------------------------------------- +NetPacketLeaveCurrentGame::NetPacketLeaveCurrentGame() +: NetPacket(NET_TYPE_LEAVE_CURRENT_GAME, sizeof(NetPacketLeaveCurrentGame), sizeof(NetPacketLeaveCurrentGame)) +{ +} + +NetPacketLeaveCurrentGame::~NetPacketLeaveCurrentGame() +{ +} + +boost::shared_ptr +NetPacketLeaveCurrentGame::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketLeaveCurrentGame); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +const NetPacketLeaveCurrentGame * +NetPacketLeaveCurrentGame::ToNetPacketLeaveCurrentGame() const +{ + return this; +} + +void +NetPacketLeaveCurrentGame::InternalCheck(const NetPacketHeader*) const +{ + // Nothing to do. +} + +//----------------------------------------------------------------------------- + NetPacketStartEvent::NetPacketStartEvent() : NetPacket(NET_TYPE_START_EVENT, sizeof(NetPacketStartEventData), sizeof(NetPacketStartEventData)) { @@ -3000,6 +3181,97 @@ NetPacketEndOfGame::InternalCheck(const NetPacketHeader*) const //----------------------------------------------------------------------------- +NetPacketRemovedFromGame::NetPacketRemovedFromGame() +: NetPacket(NET_TYPE_REMOVED_FROM_GAME, sizeof(NetPacketRemovedFromGameData), sizeof(NetPacketRemovedFromGameData)) +{ +} + +NetPacketRemovedFromGame::~NetPacketRemovedFromGame() +{ +} + +boost::shared_ptr +NetPacketRemovedFromGame::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketRemovedFromGame); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketRemovedFromGame::SetData(const NetPacketRemovedFromGame::Data &inData) +{ + NetPacketRemovedFromGameData *tmpData = (NetPacketRemovedFromGameData *)GetRawData(); + + switch (inData.removeReason) + { + case NTF_NET_REMOVED_ON_REQUEST : + tmpData->removeReason = htons(NET_REMOVED_ON_REQUEST); + break; + case NTF_NET_REMOVED_GAME_FULL : + tmpData->removeReason = htons(NET_REMOVED_GAME_FULL); + break; + case NTF_NET_REMOVED_ALREADY_RUNNING : + tmpData->removeReason = htons(NET_REMOVED_GAME_ALREADY_RUNNING); + break; + case NTF_NET_REMOVED_KICKED : + tmpData->removeReason = htons(NET_REMOVED_KICKED); + break; + default : + tmpData->removeReason = htons(NET_REMOVED_OTHER_REASON); + break; + } + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketRemovedFromGame::GetData(NetPacketRemovedFromGame::Data &outData) const +{ + NetPacketRemovedFromGameData *tmpData = (NetPacketRemovedFromGameData *)GetRawData(); + + switch (ntohs(tmpData->removeReason)) + { + // Removed Errors. + case NET_REMOVED_ON_REQUEST : + outData.removeReason = NTF_NET_REMOVED_ON_REQUEST; + break; + case NET_REMOVED_GAME_FULL : + outData.removeReason = NTF_NET_REMOVED_GAME_FULL; + break; + case NET_REMOVED_GAME_ALREADY_RUNNING : + outData.removeReason = NTF_NET_REMOVED_ALREADY_RUNNING; + break; + case NET_REMOVED_KICKED : + outData.removeReason = NTF_NET_REMOVED_KICKED; + break; + default : + outData.removeReason = NTF_NET_INTERNAL; + break; + } +} + +const NetPacketRemovedFromGame * +NetPacketRemovedFromGame::ToNetPacketRemovedFromGame() const +{ + return this; +} + +void +NetPacketRemovedFromGame::InternalCheck(const NetPacketHeader*) const +{ + // Nothing to do. +} + +//----------------------------------------------------------------------------- + NetPacketSendChatText::NetPacketSendChatText() : NetPacket(NET_TYPE_SEND_CHAT_TEXT, sizeof(NetPacketSendChatTextData), MAX_PACKET_SIZE) { @@ -3176,6 +3448,7 @@ NetPacketChatText::InternalCheck(const NetPacketHeader* data) const } // No more checks required - this packet is sent by the server. } + //----------------------------------------------------------------------------- NetPacketError::NetPacketError() @@ -3208,37 +3481,34 @@ NetPacketError::SetData(const NetPacketError::Data &inData) switch (inData.errorCode) { - // Join Game Errors. + // Init Errors. case ERR_NET_VERSION_NOT_SUPPORTED : - tmpData->reason = htons(NET_ERR_JOIN_GAME_VERSION_NOT_SUPPORTED); + tmpData->errorReason = htons(NET_ERR_INIT_VERSION_NOT_SUPPORTED); break; case ERR_NET_SERVER_FULL : - tmpData->reason = htons(NET_ERR_JOIN_GAME_SERVER_FULL); - break; - case ERR_NET_GAME_ALREADY_RUNNING : - tmpData->reason = htons(NET_ERR_JOIN_GAME_ALREADY_RUNNING); + tmpData->errorReason = htons(NET_ERR_INIT_SERVER_FULL); break; case ERR_NET_INVALID_PASSWORD : - tmpData->reason = htons(NET_ERR_JOIN_GAME_INVALID_PASSWORD); + tmpData->errorReason = htons(NET_ERR_INIT_INVALID_PASSWORD); break; case ERR_NET_PLAYER_NAME_IN_USE : - tmpData->reason = htons(NET_ERR_JOIN_GAME_PLAYER_NAME_IN_USE); + tmpData->errorReason = htons(NET_ERR_INIT_PLAYER_NAME_IN_USE); break; case ERR_NET_INVALID_PLAYER_NAME : - tmpData->reason = htons(NET_ERR_JOIN_GAME_INVALID_PLAYER_NAME); + tmpData->errorReason = htons(NET_ERR_INIT_INVALID_PLAYER_NAME); break; // General Errors. case ERR_SOCK_INVALID_PACKET : - tmpData->reason = htons(NET_ERR_GENERAL_INVALID_PACKET); + tmpData->errorReason = htons(NET_ERR_GENERAL_INVALID_PACKET); break; case ERR_SOCK_INVALID_STATE : - tmpData->reason = htons(NET_ERR_GENERAL_INVALID_STATE); + tmpData->errorReason = htons(NET_ERR_GENERAL_INVALID_STATE); break; case ERR_NET_PLAYER_KICKED : - tmpData->reason = htons(NET_ERR_GENERAL_PLAYER_KICKED); + tmpData->errorReason = htons(NET_ERR_GENERAL_PLAYER_KICKED); break; default : - tmpData->reason = htons(NET_ERR_OTHER); + tmpData->errorReason = htons(NET_ERR_OTHER); break; } @@ -3251,25 +3521,22 @@ NetPacketError::GetData(NetPacketError::Data &outData) const { NetPacketErrorData *tmpData = (NetPacketErrorData *)GetRawData(); - switch (ntohs(tmpData->reason)) + switch (ntohs(tmpData->errorReason)) { - // Join Game Errors. - case NET_ERR_JOIN_GAME_VERSION_NOT_SUPPORTED : + // Init Errors. + case NET_ERR_INIT_VERSION_NOT_SUPPORTED : outData.errorCode = ERR_NET_VERSION_NOT_SUPPORTED; break; - case NET_ERR_JOIN_GAME_SERVER_FULL : + case NET_ERR_INIT_SERVER_FULL : outData.errorCode = ERR_NET_SERVER_FULL; break; - case NET_ERR_JOIN_GAME_ALREADY_RUNNING : - outData.errorCode = ERR_NET_GAME_ALREADY_RUNNING; - break; - case NET_ERR_JOIN_GAME_INVALID_PASSWORD : + case NET_ERR_INIT_INVALID_PASSWORD : outData.errorCode = ERR_NET_INVALID_PASSWORD; break; - case NET_ERR_JOIN_GAME_PLAYER_NAME_IN_USE : + case NET_ERR_INIT_PLAYER_NAME_IN_USE : outData.errorCode = ERR_NET_PLAYER_NAME_IN_USE; break; - case NET_ERR_JOIN_GAME_INVALID_PLAYER_NAME : + case NET_ERR_INIT_INVALID_PLAYER_NAME : outData.errorCode = ERR_NET_INVALID_PLAYER_NAME; break; // General Errors. diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index d783cdc9..29efe9bd 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -142,7 +142,7 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) packet = server.GetReceiver().Recv(session.sessionData->GetSocket(), session.sessionData->GetReceiveBuffer()); } catch (const NetException &) { - server.CloseSessionDelayed(session); + server.RemoveSession(session); return retVal; } @@ -167,6 +167,10 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) server.GetSender().Send(session.sessionData->GetSocket(), info); } } + else if (packet->ToNetPacketLeaveCurrentGame()) + { + server.MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST); + } // Chat text is always allowed. else if (packet->ToNetPacketSendChatText()) { @@ -243,7 +247,7 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s // Check the number of players. if (curNumPlayers >= (size_t)server.GetGameData().maxNumberOfPlayers) { - server.SessionError(session, ERR_NET_SERVER_FULL); + server.MoveSessionToLobby(session, NTF_NET_REMOVED_GAME_FULL); } else { @@ -359,7 +363,7 @@ void AbstractServerGameStateRunning::HandleNewSession(ServerGameThread &server, SessionWrapper session) { // Do not accept new sessions in this state. - server.SessionError(session, ERR_NET_GAME_ALREADY_RUNNING); + server.MoveSessionToLobby(session, NTF_NET_REMOVED_ALREADY_RUNNING); } //----------------------------------------------------------------------------- diff --git a/src/net/common/servergamethread.cpp b/src/net/common/servergamethread.cpp index 58859f91..64da0ee1 100644 --- a/src/net/common/servergamethread.cpp +++ b/src/net/common/servergamethread.cpp @@ -185,7 +185,7 @@ void ServerGameThread::InternalKickPlayer(unsigned playerId) { SessionWrapper tmpSession = GetSessionManager().GetSessionByUniquePlayerId(playerId); - SessionError(tmpSession, ERR_NET_PLAYER_KICKED); + MoveSessionToLobby(tmpSession, NTF_NET_REMOVED_KICKED); } PlayerDataList @@ -262,18 +262,9 @@ ServerGameThread::ResetComputerPlayerList() } void -ServerGameThread::SessionError(SessionWrapper session, int errorCode) -{ - if (session.sessionData.get()) - { - SendError(session.sessionData->GetSocket(), errorCode); - CloseSessionDelayed(session); - } -} - -void -ServerGameThread::CloseSessionDelayed(SessionWrapper session) +ServerGameThread::RemoveSession(SessionWrapper session) { + assert(session.sessionData.get()); GetSessionManager().RemoveSession(session.sessionData->GetSocket()); boost::shared_ptr tmpPlayerData = session.playerData; @@ -285,26 +276,24 @@ ServerGameThread::CloseSessionDelayed(SessionWrapper session) thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId(); static_cast(thisPlayerLeft.get())->SetData(thisPlayerLeftData); GetSessionManager().SendToAllSessions(GetSender(), thisPlayerLeft, SessionData::Game); + + GetLobbyThread().NotifyPlayerLeftGame(GetId(), session.playerData->GetUniqueId()); } - - GetLobbyThread().CloseSessionDelayed(session); - GetLobbyThread().NotifyPlayerLeftGame(GetId(), session.playerData->GetUniqueId()); } void -ServerGameThread::SendError(SOCKET s, int errorCode) +ServerGameThread::SessionError(SessionWrapper session, int errorCode) { - boost::shared_ptr packet(new NetPacketError); - NetPacketError::Data errorData; - errorData.errorCode = errorCode; - static_cast(packet.get())->SetData(errorData); - GetSender().Send(s, packet); + assert(session.sessionData.get()); + RemoveSession(session); + GetLobbyThread().SessionError(session, errorCode); } void -ServerGameThread::RejectSession(SessionWrapper session) +ServerGameThread::MoveSessionToLobby(SessionWrapper session, int reason) { - // TODO + RemoveSession(session); + GetLobbyThread().ReAddSession(session, reason); } void diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 6e5f194f..af36256e 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -80,6 +80,19 @@ ServerLobbyThread::AddConnection(boost::shared_ptr data) m_connectQueue.push_back(data); } +void +ServerLobbyThread::ReAddSession(SessionWrapper session, int reason) +{ + boost::shared_ptr packet(new NetPacketRemovedFromGame); + NetPacketRemovedFromGame::Data removedData; + removedData.removeReason = reason; + static_cast(packet.get())->SetData(removedData); + GetSender().Send(session.sessionData->GetSocket(), packet); + + boost::mutex::scoped_lock lock(m_sessionQueueMutex); + m_sessionQueue.push_back(session); +} + void ServerLobbyThread::CloseSessionDelayed(SessionWrapper session) { @@ -160,6 +173,20 @@ ServerLobbyThread::Main() if (tmpData.get()) HandleNewConnection(tmpData); } + { + // Handle one incoming session at a time. + SessionWrapper tmpSession; + { + boost::mutex::scoped_lock lock(m_sessionQueueMutex); + if (!m_sessionQueue.empty()) + { + tmpSession = m_sessionQueue.front(); + m_sessionQueue.pop_front(); + } + } + if (tmpSession.sessionData.get() && tmpSession.playerData.get()) + HandleNewSession(tmpSession); + } // Process loop. ProcessLoop(); // Close sessions. @@ -197,7 +224,7 @@ ServerLobbyThread::ProcessLoop() } catch (const NetException &) { // On error: Close this session. - CloseSessionDelayed(session); + m_sessionManager.RemoveSession(session.sessionData->GetSocket()); return; } if (packet.get()) @@ -279,13 +306,7 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketIn GetSender().Send(session.sessionData->GetSocket(), initAck); // Send the game list to the client. - GameMap::const_iterator game_i = m_gameMap.begin(); - GameMap::const_iterator game_end = m_gameMap.end(); - while (game_i != game_end) - { - GetSender().Send(session.sessionData->GetSocket(), CreateNetPacketGameListNew(*game_i->second)); - ++game_i; - } + SendGameList(session.sessionData->GetSocket()); // Set player data for session. m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData); @@ -378,7 +399,7 @@ ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPack } else { - SessionError(session, ERR_NET_INVALID_PASSWORD); + SendJoinGameFailed(session.sessionData->GetSocket(), NTF_NET_JOIN_INVALID_PASSWORD); } } else @@ -485,6 +506,35 @@ ServerLobbyThread::HandleNewConnection(boost::shared_ptr connData) } } +void +ServerLobbyThread::HandleNewSession(SessionWrapper session) +{ + if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS) + { + // This session has been temporarily stored - check if no + // one else got the player name during that time. + if (!m_sessionManager.IsPlayerConnected(session.playerData->GetName())) + { + // Send the list of games. + SendGameList(session.sessionData->GetSocket()); + // Set state (back) to established. + session.sessionData->SetState(SessionData::Established); + // Add session to lobby list. + m_sessionManager.AddSession(session); + } + else + { + // Gracefully close this session. + SessionError(session, ERR_NET_PLAYER_NAME_IN_USE); + } + } + else + { + // Gracefully close this session. + SessionError(session, ERR_NET_SERVER_FULL); + } +} + void ServerLobbyThread::CleanupConnectQueue() { @@ -514,6 +564,28 @@ ServerLobbyThread::SendError(SOCKET s, int errorCode) GetSender().Send(s, packet); } +void +ServerLobbyThread::SendJoinGameFailed(SOCKET s, int reason) +{ + boost::shared_ptr packet(new NetPacketJoinGameFailed); + NetPacketJoinGameFailed::Data failedData; + failedData.failureCode = reason; + static_cast(packet.get())->SetData(failedData); + GetSender().Send(s, packet); +} + +void +ServerLobbyThread::SendGameList(SOCKET s) +{ + GameMap::const_iterator game_i = m_gameMap.begin(); + GameMap::const_iterator game_end = m_gameMap.end(); + while (game_i != game_end) + { + GetSender().Send(s, CreateNetPacketGameListNew(*game_i->second)); + ++game_i; + } +} + ServerCallback & ServerLobbyThread::GetCallback() { diff --git a/src/net/netpacket.h b/src/net/netpacket.h index cca421d3..8bc5892a 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -51,9 +51,11 @@ class NetPacketPlayerInfo; class NetPacketCreateGame; class NetPacketJoinGame; class NetPacketJoinGameAck; +class NetPacketJoinGameFailed; class NetPacketPlayerJoined; class NetPacketPlayerLeft; class NetPacketKickPlayer; +class NetPacketLeaveCurrentGame; class NetPacketStartEvent; class NetPacketGameStart; class NetPacketHandStart; @@ -68,6 +70,7 @@ class NetPacketAllInShowCards; class NetPacketEndOfHandShowCards; class NetPacketEndOfHandHideCards; class NetPacketEndOfGame; +class NetPacketRemovedFromGame; class NetPacketSendChatText; class NetPacketChatText; class NetPacketError; @@ -100,9 +103,11 @@ public: virtual const NetPacketCreateGame *ToNetPacketCreateGame() const; virtual const NetPacketJoinGame *ToNetPacketJoinGame() const; virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const; + virtual const NetPacketJoinGameFailed *ToNetPacketJoinGameFailed() const; virtual const NetPacketPlayerJoined *ToNetPacketPlayerJoined() const; virtual const NetPacketPlayerLeft *ToNetPacketPlayerLeft() const; virtual const NetPacketKickPlayer *ToNetPacketKickPlayer() const; + virtual const NetPacketLeaveCurrentGame *ToNetPacketLeaveCurrentGame() const; virtual const NetPacketStartEvent *ToNetPacketStartEvent() const; virtual const NetPacketGameStart *ToNetPacketGameStart() const; virtual const NetPacketHandStart *ToNetPacketHandStart() const; @@ -117,6 +122,7 @@ public: virtual const NetPacketEndOfHandShowCards *ToNetPacketEndOfHandShowCards() const; virtual const NetPacketEndOfHandHideCards *ToNetPacketEndOfHandHideCards() const; virtual const NetPacketEndOfGame *ToNetPacketEndOfGame() const; + virtual const NetPacketRemovedFromGame *ToNetPacketRemovedFromGame() const; virtual const NetPacketSendChatText *ToNetPacketSendChatText() const; virtual const NetPacketChatText *ToNetPacketChatText() const; virtual const NetPacketError *ToNetPacketError() const; @@ -404,6 +410,29 @@ protected: virtual void InternalCheck(const NetPacketHeader* data) const; }; +class NetPacketJoinGameFailed : public NetPacket +{ +public: + struct Data + { + int failureCode; + }; + + NetPacketJoinGameFailed(); + virtual ~NetPacketJoinGameFailed(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketJoinGameFailed *ToNetPacketJoinGameFailed() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + class NetPacketPlayerJoined : public NetPacket { public: @@ -474,6 +503,22 @@ protected: virtual void InternalCheck(const NetPacketHeader* data) const; }; +class NetPacketLeaveCurrentGame : public NetPacket +{ +public: + + NetPacketLeaveCurrentGame(); + virtual ~NetPacketLeaveCurrentGame(); + + virtual boost::shared_ptr Clone() const; + + virtual const NetPacketLeaveCurrentGame *ToNetPacketLeaveCurrentGame() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + class NetPacketStartEvent : public NetPacket { public: @@ -838,6 +883,29 @@ protected: virtual void InternalCheck(const NetPacketHeader* data) const; }; +class NetPacketRemovedFromGame : public NetPacket +{ +public: + struct Data + { + u_int16_t removeReason; + }; + + NetPacketRemovedFromGame(); + virtual ~NetPacketRemovedFromGame(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketRemovedFromGame *ToNetPacketRemovedFromGame() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + class NetPacketSendChatText : public NetPacket { public: diff --git a/src/net/servergamethread.h b/src/net/servergamethread.h index 812157bf..e2284433 100644 --- a/src/net/servergamethread.h +++ b/src/net/servergamethread.h @@ -80,10 +80,9 @@ protected: void AddComputerPlayer(boost::shared_ptr player); void ResetComputerPlayerList(); + void RemoveSession(SessionWrapper session); void SessionError(SessionWrapper session, int errorCode); - void CloseSessionDelayed(SessionWrapper session); - void SendError(SOCKET s, int errorCode); - void RejectSession(SessionWrapper session); + void MoveSessionToLobby(SessionWrapper session, int reason); void RemoveDisconnectedPlayers(); size_t GetCurNumberOfPlayers() const; diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 4374e8de..f2dad0cc 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -51,7 +51,8 @@ public: void Init(const std::string &pwd); void AddConnection(boost::shared_ptr data); - void CloseSessionDelayed(SessionWrapper session); + void ReAddSession(SessionWrapper session, int reason); + void SessionError(SessionWrapper session, int errorCode); void NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId); void NotifyPlayerLeftGame(unsigned gameId, unsigned playerId); @@ -64,6 +65,7 @@ public: protected: typedef std::deque > ConnectQueue; + typedef std::deque SessionQueue; typedef std::list SessionList; typedef std::list > > CloseSessionList; typedef std::map > GameMap; @@ -86,14 +88,17 @@ protected: void TerminateGames(); void HandleNewConnection(boost::shared_ptr connData); + void HandleNewSession(SessionWrapper session); SOCKET Select(); void CleanupConnectQueue(); void CleanupSessionMap(); - void SessionError(SessionWrapper session, int errorCode); + void CloseSessionDelayed(SessionWrapper session); void SendError(SOCKET s, int errorCode); + void SendJoinGameFailed(SOCKET s, int reason); + void SendGameList(SOCKET s); SenderThread &GetSender(); ReceiverHelper &GetReceiver(); @@ -113,6 +118,9 @@ private: ConnectQueue m_connectQueue; mutable boost::mutex m_connectQueueMutex; + SessionQueue m_sessionQueue; + mutable boost::mutex m_sessionQueueMutex; + SessionManager m_sessionManager; CloseSessionList m_closeSessionList; diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index e0e123c8..bb8c0bf0 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -44,20 +44,31 @@ // The following errors are game errors. #define ERR_NET_VERSION_NOT_SUPPORTED 101 #define ERR_NET_SERVER_FULL 102 -#define ERR_NET_GAME_ALREADY_RUNNING 103 -#define ERR_NET_INVALID_PASSWORD 104 -#define ERR_NET_INVALID_PASSWORD_STR 105 -#define ERR_NET_PLAYER_NAME_IN_USE 106 -#define ERR_NET_INVALID_PLAYER_NAME 107 -#define ERR_NET_INVALID_PLAYER_CARDS 108 -#define ERR_NET_INVALID_PLAYER_RESULTS 109 -#define ERR_NET_INVALID_GAME_NAME 110 -#define ERR_NET_UNKNOWN_GAME 111 -#define ERR_NET_INVALID_CHAT_TEXT 112 -#define ERR_NET_UNKNOWN_PLAYER_ID 113 -#define ERR_NET_INVALID_ROUND 114 -#define ERR_NET_PLAYER_KICKED 115 -#define ERR_NET_INVALID_PLAYER_COUNT 116 +#define ERR_NET_INVALID_PASSWORD 103 +#define ERR_NET_INVALID_PASSWORD_STR 104 +#define ERR_NET_PLAYER_NAME_IN_USE 105 +#define ERR_NET_INVALID_PLAYER_NAME 106 +#define ERR_NET_INVALID_PLAYER_CARDS 107 +#define ERR_NET_INVALID_PLAYER_RESULTS 108 +#define ERR_NET_INVALID_GAME_NAME 109 +#define ERR_NET_UNKNOWN_GAME 110 +#define ERR_NET_INVALID_CHAT_TEXT 111 +#define ERR_NET_UNKNOWN_PLAYER_ID 112 +#define ERR_NET_INVALID_ROUND 113 +#define ERR_NET_PLAYER_KICKED 114 +#define ERR_NET_INVALID_PLAYER_COUNT 115 + +// Notifications - removed from game +#define NTF_NET_INTERNAL 201 +#define NTF_NET_REMOVED_ON_REQUEST 202 +#define NTF_NET_REMOVED_GAME_FULL 203 +#define NTF_NET_REMOVED_ALREADY_RUNNING 204 +#define NTF_NET_REMOVED_KICKED 205 + +// Notifications - join failed +#define NTF_NET_JOIN_GAME_FULL 206 +#define NTF_NET_JOIN_ALREADY_RUNNING 207 +#define NTF_NET_JOIN_INVALID_PASSWORD 208 // This is an internal message which is not reported. #define MSG_SOCK_INTERNAL_PENDING 0 diff --git a/src/session.cpp b/src/session.cpp index 968e7980..db9e3238 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -234,6 +234,13 @@ void Session::waitForNetworkServer(unsigned timeoutMsec) } } +void Session::sendLeaveCurrentGame() +{ + if (!myNetClient) + return; // only act if client is running. + myNetClient->SendLeaveCurrentGame(); +} + void Session::sendStartEvent(bool fillUpWithCpuPlayers) { if (!myNetClient) diff --git a/src/session.h b/src/session.h index 0b765fa6..150ddc7e 100755 --- a/src/session.h +++ b/src/session.h @@ -53,6 +53,7 @@ public: void clientJoinGame(unsigned gameId, const std::string &password); void startNetworkServer(); + void sendLeaveCurrentGame(); void sendStartEvent(bool fillUpWithCpuPlayers); void terminateNetworkServer(); void waitForNetworkServer(unsigned timeoutMsec);