diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt
index 9f87f700..80cbec81 100644
--- a/docs/net_protocol.txt
+++ b/docs/net_protocol.txt
@@ -483,6 +483,7 @@ Server Notification: Player Left
Leave Reason:
0x0000 - On Request
0x0001 - Kicked from the game
+ 0x0002 - Left game due to error
0xFFFF - Other reason
diff --git a/src/gui/generic/serverguiwrapper.cpp b/src/gui/generic/serverguiwrapper.cpp
index e414a188..cb25da6e 100644
--- a/src/gui/generic/serverguiwrapper.cpp
+++ b/src/gui/generic/serverguiwrapper.cpp
@@ -128,7 +128,7 @@ void ServerGuiWrapper::SignalNetClientRemovedFromGame(int notificationId) { if (
void ServerGuiWrapper::SignalNetClientSelfJoined(unsigned playerId, const string &playerName, PlayerRights rights) { if (myClientcb) myClientcb->SignalNetClientSelfJoined(playerId, playerName, rights); }
void ServerGuiWrapper::SignalNetClientPlayerJoined(unsigned playerId, const string &playerName, PlayerRights rights) { if (myClientcb) myClientcb->SignalNetClientPlayerJoined(playerId, playerName, rights); }
void ServerGuiWrapper::SignalNetClientPlayerChanged(unsigned playerId, const string &newPlayerName) { if (myClientcb) myClientcb->SignalNetClientPlayerChanged(playerId, newPlayerName); }
-void ServerGuiWrapper::SignalNetClientPlayerLeft(unsigned playerId, const string &playerName) { if (myClientcb) myClientcb->SignalNetClientPlayerLeft(playerId, playerName); }
+void ServerGuiWrapper::SignalNetClientPlayerLeft(unsigned playerId, const string &playerName, int removeReason) { if (myClientcb) myClientcb->SignalNetClientPlayerLeft(playerId, playerName, removeReason); }
void ServerGuiWrapper::SignalNetClientNewGameAdmin(unsigned playerId, const string &playerName) { if (myClientcb) myClientcb->SignalNetClientNewGameAdmin(playerId, playerName); }
void ServerGuiWrapper::SignalNetClientGameListNew(unsigned gameId) { if (myClientcb) myClientcb->SignalNetClientGameListNew(gameId); }
void ServerGuiWrapper::SignalNetClientGameListRemove(unsigned gameId) { if (myClientcb) myClientcb->SignalNetClientGameListRemove(gameId); }
diff --git a/src/gui/generic/serverguiwrapper.h b/src/gui/generic/serverguiwrapper.h
index 07b2d84a..b7b6528e 100644
--- a/src/gui/generic/serverguiwrapper.h
+++ b/src/gui/generic/serverguiwrapper.h
@@ -114,7 +114,7 @@ public:
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);
- void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName);
+ void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName, int removeReason);
void SignalNetClientNewGameAdmin(unsigned playerId, const std::string &playerName);
void SignalNetClientChatMsg(const std::string &playerName, const std::string &msg);
void SignalNetClientWaitDialog();
diff --git a/src/gui/qt/gametable/log/log.cpp b/src/gui/qt/gametable/log/log.cpp
index 51f4b4aa..6bcc0c1b 100755
--- a/src/gui/qt/gametable/log/log.cpp
+++ b/src/gui/qt/gametable/log/log.cpp
@@ -40,7 +40,7 @@ Log::Log(gameTableImpl* w, ConfigFile *c) : myW(w), myConfig(c), myLogDir(0), my
connect(this, SIGNAL(signalLogPlayerSitsOut(QString)), this, SLOT(logPlayerSitsOut(QString)));
connect(this, SIGNAL(signalLogDealBoardCardsMsg(int, int, int, int, int, int)), this, SLOT(logDealBoardCardsMsg(int, int, int, int, int, int)));
connect(this, SIGNAL(signalLogFlipHoleCardsMsg(QString, int, int, int, QString)), this, SLOT(logFlipHoleCardsMsg(QString, int, int, int, QString)));
- connect(this, SIGNAL(signalLogPlayerLeftMsg(QString)), this, SLOT(logPlayerLeftMsg(QString)));
+ connect(this, SIGNAL(signalLogPlayerLeftMsg(QString, int)), this, SLOT(logPlayerLeftMsg(QString, int)));
connect(this, SIGNAL(signalLogNewGameAdminMsg(QString)), this, SLOT(logNewGameAdminMsg(QString)));
connect(this, SIGNAL(signalLogPlayerWinGame(QString, int)), this, SLOT(logPlayerWinGame(QString, int)));
connect(this, SIGNAL(signalFlushLogAtGame(int)), this, SLOT(flushLogAtGame(int)));
@@ -323,7 +323,7 @@ void Log::logFlipHoleCardsMsg(QString playerName, int card1, int card2, int card
}
-void Log::logPlayerLeftMsg(QString playerName) {
+void Log::logPlayerLeftMsg(QString playerName, int wasKicked) {
myW->textBrowser_Log->append( ""+playerName+" has left the game!");
diff --git a/src/gui/qt/gametable/log/log.h b/src/gui/qt/gametable/log/log.h
index 54cbb5e8..058936df 100755
--- a/src/gui/qt/gametable/log/log.h
+++ b/src/gui/qt/gametable/log/log.h
@@ -47,7 +47,7 @@ public slots:
void logPlayerSitsOut(QString playerName);
void logDealBoardCardsMsg(int roundID, int card1, int card2, int card3, int card4 = -1, int card5 = -1);
void logFlipHoleCardsMsg(QString playerName, int card1, int card2, int cardsValueInt = -1, QString showHas = "shows");
- void logPlayerLeftMsg(QString playerName);
+ void logPlayerLeftMsg(QString playerName, int wasKicked);
void logNewGameAdminMsg(QString playerName);
void logPlayerWinGame(QString playerName, int gameID);
void flushLogAtGame(int gameID);
@@ -69,7 +69,7 @@ signals:
void signalLogPlayerSitsOut(QString playerName);
void signalLogDealBoardCardsMsg(int roundID, int card1, int card2, int card3, int card4 = -1, int card5 = -1);
void signalLogFlipHoleCardsMsg(QString playerName, int card1, int card2, int cardsValueInt = -1, QString showHas = "shows");
- void signalLogPlayerLeftMsg(QString playerName);
+ void signalLogPlayerLeftMsg(QString playerName, int wasKicked);
void signalLogNewGameAdminMsg(QString playerName);
void signalLogPlayerWinGame(QString playerName, int gameID);
void signalFlushLogAtGame(int gameID);
diff --git a/src/gui/qt/guiwrapper.cpp b/src/gui/qt/guiwrapper.cpp
index eca637b5..27833c23 100644
--- a/src/gui/qt/guiwrapper.cpp
+++ b/src/gui/qt/guiwrapper.cpp
@@ -25,6 +25,8 @@
#include "gametableimpl.h"
#include "startwindowimpl.h"
#include "configfile.h"
+#include
+
using namespace std;
@@ -135,12 +137,12 @@ void GuiWrapper::SignalNetClientPlayerChanged(unsigned playerId, const string &n
{
myStartWindow->signalNetClientPlayerChanged(playerId, QString::fromUtf8(newPlayerName.c_str()));
}
-void GuiWrapper::SignalNetClientPlayerLeft(unsigned playerId, const string &playerName)
+void GuiWrapper::SignalNetClientPlayerLeft(unsigned playerId, const string &playerName, int removeReason)
{
QString tmpName(QString::fromUtf8(playerName.c_str()));
myStartWindow->signalNetClientPlayerLeft(playerId, tmpName);
if (!playerName.empty() && playerName[0] != '#')
- myLog->signalLogPlayerLeftMsg(tmpName);
+ myLog->signalLogPlayerLeftMsg(tmpName, removeReason == NTF_NET_REMOVED_KICKED);
}
void GuiWrapper::SignalNetClientNewGameAdmin(unsigned playerId, const string &playerName) {
diff --git a/src/gui/qt/guiwrapper.h b/src/gui/qt/guiwrapper.h
index dd72550b..9d3f8ce9 100644
--- a/src/gui/qt/guiwrapper.h
+++ b/src/gui/qt/guiwrapper.h
@@ -122,7 +122,7 @@ public:
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);
- void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName);
+ void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName, int removeReason);
void SignalNetClientNewGameAdmin(unsigned playerId, const std::string &playerName);
void SignalNetClientChatMsg(const std::string &playerName, const std::string &msg);
void SignalNetClientWaitDialog();
diff --git a/src/net/clientcallback.h b/src/net/clientcallback.h
index 6e7a770f..99796d69 100644
--- a/src/net/clientcallback.h
+++ b/src/net/clientcallback.h
@@ -53,7 +53,7 @@ public:
virtual void SignalNetClientSelfJoined(unsigned playerId, const std::string &playerName, PlayerRights rights) = 0;
virtual void SignalNetClientPlayerJoined(unsigned playerId, const std::string &playerName, PlayerRights rights) = 0;
virtual void SignalNetClientPlayerChanged(unsigned playerId, const std::string &newPlayerName) = 0;
- virtual void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName) = 0;
+ virtual void SignalNetClientPlayerLeft(unsigned playerId, const std::string &playerName, int removeReason) = 0;
virtual void SignalNetClientNewGameAdmin(unsigned playerId, const std::string &playerName) = 0;
virtual void SignalNetClientChatMsg(const std::string &playerName, const std::string &msg) = 0;
diff --git a/src/net/clientthread.h b/src/net/clientthread.h
index 8bb91c29..720993f5 100644
--- a/src/net/clientthread.h
+++ b/src/net/clientthread.h
@@ -132,7 +132,7 @@ protected:
QtToolsInterface &GetQtToolsInterface();
void AddPlayerData(boost::shared_ptr playerData);
- void RemovePlayerData(unsigned playerId);
+ void RemovePlayerData(unsigned playerId, int removeReason);
void ClearPlayerDataList();
void MapPlayerDataList();
const PlayerDataList &GetPlayerDataList() const;
diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp
index 69d98b32..10de84e0 100644
--- a/src/net/common/clientstate.cpp
+++ b/src/net/common/clientstate.cpp
@@ -702,7 +702,7 @@ AbstractClientStateReceiving::Process(ClientThread &client)
tmpPacket->ToNetPacketPlayerLeft()->GetData(playerLeftData);
// Signal to GUI and remove from data list.
- client.RemovePlayerData(playerLeftData.playerId);
+ client.RemovePlayerData(playerLeftData.playerId, playerLeftData.removeReason);
}
else if (tmpPacket->ToNetPacketGameAdminChanged())
{
diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp
index 57bfe4b9..c0a578ec 100644
--- a/src/net/common/clientthread.cpp
+++ b/src/net/common/clientthread.cpp
@@ -765,7 +765,7 @@ ClientThread::AddPlayerData(boost::shared_ptr playerData)
}
void
-ClientThread::RemovePlayerData(unsigned playerId)
+ClientThread::RemovePlayerData(unsigned playerId, int removeReason)
{
boost::shared_ptr tmpData;
@@ -785,7 +785,7 @@ ClientThread::RemovePlayerData(unsigned playerId)
if (tmpData.get())
{
// Remove player from gui.
- GetCallback().SignalNetClientPlayerLeft(tmpData->GetUniqueId(), tmpData->GetName());
+ GetCallback().SignalNetClientPlayerLeft(tmpData->GetUniqueId(), tmpData->GetName(), removeReason);
}
}
diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp
index 1485d646..f152f504 100644
--- a/src/net/common/netpacket.cpp
+++ b/src/net/common/netpacket.cpp
@@ -113,6 +113,12 @@ using namespace std;
#define NET_REMOVED_START_FAILED 0x0005
#define NET_REMOVED_OTHER_REASON 0xFFFF
+// Reasons why player left a game.
+#define NET_LEFT_ON_REQUEST 0x0000
+#define NET_LEFT_KICKED 0x0001
+#define NET_LEFT_ERROR 0x0002
+#define NET_LEFT_OTHER_REASON 0xFFFF
+
// Reasons why ask kick was denied.
#define NET_ASK_KICK_DENIED_TEMPORARY 0x0000
#define NET_ASK_KICK_DENIED_OTHER_IN_PROGRESS 0x0001
@@ -3083,7 +3089,24 @@ NetPacketPlayerLeft::SetData(const NetPacketPlayerLeft::Data &inData)
NetPacketPlayerLeftData *tmpData = (NetPacketPlayerLeftData *)GetRawData();
// Set the data.
- tmpData->playerId = htonl(inData.playerId);
+ tmpData->playerId = htonl(inData.playerId);
+ tmpData->leaveReason = htons(inData.removeReason);
+
+ switch(inData.removeReason)
+ {
+ case NTF_NET_REMOVED_ON_REQUEST :
+ tmpData->leaveReason = htons(NET_LEFT_ON_REQUEST);
+ break;
+ case NTF_NET_REMOVED_KICKED :
+ tmpData->leaveReason = htons(NET_LEFT_KICKED);
+ break;
+ case NTF_NET_INTERNAL :
+ tmpData->leaveReason = htons(NET_LEFT_ERROR);
+ break;
+ default :
+ tmpData->leaveReason = htons(NET_LEFT_OTHER_REASON);
+ break;
+ }
// Check the packet - just in case.
Check(GetRawData());
@@ -3095,7 +3118,20 @@ NetPacketPlayerLeft::GetData(NetPacketPlayerLeft::Data &outData) const
// We assume that the data is valid. Validity has already been checked.
NetPacketPlayerLeftData *tmpData = (NetPacketPlayerLeftData *)GetRawData();
- outData.playerId = ntohl(tmpData->playerId);
+ outData.playerId = ntohl(tmpData->playerId);
+
+ switch(ntohs(tmpData->leaveReason))
+ {
+ case NET_LEFT_ON_REQUEST :
+ outData.removeReason = ntohs(NTF_NET_REMOVED_ON_REQUEST);
+ break;
+ case NET_LEFT_KICKED :
+ outData.removeReason = ntohs(NTF_NET_REMOVED_KICKED);
+ break;
+ default :
+ outData.removeReason = ntohs(NTF_NET_INTERNAL);
+ break;
+ }
}
const NetPacketPlayerLeft *
diff --git a/src/net/common/servergamethread.cpp b/src/net/common/servergamethread.cpp
index 28369388..7570afd0 100644
--- a/src/net/common/servergamethread.cpp
+++ b/src/net/common/servergamethread.cpp
@@ -375,7 +375,7 @@ ServerGameThread::ResetComputerPlayerList()
while (i != end)
{
GetLobbyThread().RemoveComputerPlayer(*i);
- RemovePlayerData(*i);
+ RemovePlayerData(*i, NTF_NET_REMOVED_ON_REQUEST);
++i;
}
@@ -383,7 +383,7 @@ ServerGameThread::ResetComputerPlayerList()
}
void
-ServerGameThread::GracefulRemoveSession(SessionWrapper session)
+ServerGameThread::GracefulRemoveSession(SessionWrapper session, int reason)
{
if (!session.sessionData.get())
throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
@@ -392,12 +392,12 @@ ServerGameThread::GracefulRemoveSession(SessionWrapper session)
boost::shared_ptr tmpPlayerData = session.playerData;
if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty())
{
- RemovePlayerData(tmpPlayerData);
+ RemovePlayerData(tmpPlayerData, reason);
}
}
void
-ServerGameThread::RemovePlayerData(boost::shared_ptr player)
+ServerGameThread::RemovePlayerData(boost::shared_ptr player, int reason)
{
if (player->GetRights() == PLAYER_RIGHTS_ADMIN)
{
@@ -427,6 +427,7 @@ ServerGameThread::RemovePlayerData(boost::shared_ptr player)
boost::shared_ptr thisPlayerLeft(new NetPacketPlayerLeft);
NetPacketPlayerLeft::Data thisPlayerLeftData;
thisPlayerLeftData.playerId = player->GetUniqueId();
+ thisPlayerLeftData.removeReason = reason;
static_cast(thisPlayerLeft.get())->SetData(thisPlayerLeftData);
GetSessionManager().SendToAllSessions(GetSender(), thisPlayerLeft, SessionData::Game);
@@ -437,7 +438,7 @@ void
ServerGameThread::ErrorRemoveSession(SessionWrapper session)
{
GetLobbyThread().RemoveSessionFromGame(session);
- GracefulRemoveSession(session);
+ GracefulRemoveSession(session, NTF_NET_INTERNAL);
}
void
@@ -452,7 +453,7 @@ ServerGameThread::SessionError(SessionWrapper session, int errorCode)
void
ServerGameThread::MoveSessionToLobby(SessionWrapper session, int reason)
{
- GracefulRemoveSession(session);
+ GracefulRemoveSession(session, reason);
// Reset ready flag - just in case it is set, player may leave at any time.
session.sessionData->ResetReadyFlag();
GetLobbyThread().ReAddSession(session, reason);
diff --git a/src/net/netpacket.h b/src/net/netpacket.h
index bc7d235c..9fd06572 100644
--- a/src/net/netpacket.h
+++ b/src/net/netpacket.h
@@ -720,6 +720,7 @@ public:
struct Data
{
u_int32_t playerId;
+ u_int16_t removeReason;
};
NetPacketPlayerLeft();
diff --git a/src/net/servergamethread.h b/src/net/servergamethread.h
index af723d0f..4cde759b 100644
--- a/src/net/servergamethread.h
+++ b/src/net/servergamethread.h
@@ -95,8 +95,8 @@ protected:
void AddComputerPlayer(boost::shared_ptr player);
void ResetComputerPlayerList();
- void GracefulRemoveSession(SessionWrapper session);
- void RemovePlayerData(boost::shared_ptr player);
+ void GracefulRemoveSession(SessionWrapper session, int reason);
+ void RemovePlayerData(boost::shared_ptr player, int reason);
void ErrorRemoveSession(SessionWrapper session);
void SessionError(SessionWrapper session, int errorCode);
void MoveSessionToLobby(SessionWrapper session, int reason);