diff --git a/src/gui/qt/mainwindow/mainwindowimpl.cpp b/src/gui/qt/mainwindow/mainwindowimpl.cpp index 821349a2..48cd6ab8 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.cpp +++ b/src/gui/qt/mainwindow/mainwindowimpl.cpp @@ -671,6 +671,7 @@ void mainWindowImpl::callJoinNetworkGameDialog() { mySession->terminateNetworkClient(); mySession->terminateNetworkServer(); + myWaitingForServerGameDialog->treeWidget->clear(); // Maybe use QUrl::toPunycode. mySession->startNetworkClient( myJoinNetworkGameDialog->lineEdit_ipAddress->text().toUtf8().constData(), diff --git a/src/net/clientcallback.h b/src/net/clientcallback.h index b9464922..17b5525e 100644 --- a/src/net/clientcallback.h +++ b/src/net/clientcallback.h @@ -21,6 +21,8 @@ #ifndef _CLIENTCALLBACK_H_ #define _CLIENTCALLBACK_H_ +#include + struct GameData; class ClientCallback @@ -33,6 +35,8 @@ public: virtual void SignalNetClientError(int errorID, int osErrorID) = 0; virtual void SignalNetClientGameStart(const GameData &gameData) = 0; + virtual void SignalNetClientPlayerJoined(const std::string &playerName) = 0; + virtual void SignalNetClientPlayerLeft(const std::string &playerName) = 0; }; #endif diff --git a/src/net/clientthread.h b/src/net/clientthread.h index ef31fb0e..fc4a369d 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -22,6 +22,7 @@ #define _CLIENTTHREAD_H_ #include +#include #include #include #include @@ -52,6 +53,7 @@ public: ClientCallback &GetCallback(); protected: + typedef std::map PlayerMap; // Main function of the thread. virtual void Main(); @@ -70,6 +72,8 @@ protected: ClientSenderCallback &GetSenderCallback(); + PlayerMap &GetPlayerMap(); + private: std::auto_ptr m_context; @@ -81,6 +85,7 @@ private: std::auto_ptr m_receiver; std::auto_ptr m_gameData; + PlayerMap m_playerMap; friend class ClientStateInit; friend class ClientStateStartResolve; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 07822725..3b7b7eff 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -330,7 +330,7 @@ ClientStateStartSession::Process(ClientThread &client) boost::shared_ptr packet(new NetPacketJoinGame); ((NetPacketJoinGame *)packet.get())->SetData(initData); - client.GetSender().Send(packet, context.GetSocket()); + client.GetSender().Send(context.GetSocket(), packet); client.SetState(ClientStateWaitSession::Instance()); @@ -374,6 +374,8 @@ ClientStateWaitSession::Process(ClientThread &client) tmpPacket->ToNetPacketJoinGameAck()->GetData(joinGameAckData); client.SetGameData(joinGameAckData.gameData); + client.GetCallback().SignalNetClientPlayerJoined(context.GetPlayerName()); + client.SetState(ClientStateWaitGame::Instance()); retVal = MSG_SOCK_SESSION_DONE; } @@ -410,22 +412,37 @@ ClientStateWaitGame::~ClientStateWaitGame() int ClientStateWaitGame::Process(ClientThread &client) { - int retVal; + int retVal = MSG_SOCK_INTERNAL_PENDING; ClientContext &context = client.GetContext(); // delegate to receiver helper class boost::shared_ptr tmpPacket = client.GetReceiver().Recv(context.GetSocket()); - if (tmpPacket.get() && tmpPacket->ToNetPacketGameStart()) + if (tmpPacket.get()) { - client.SetState(ClientStateFinal::Instance()); - retVal = MSG_NET_GAME_START; - } - else // TODO: handle error packet - { - retVal = MSG_SOCK_INTERNAL_PENDING; + if (tmpPacket->ToNetPacketGameStart()) + { + client.SetState(ClientStateFinal::Instance()); + retVal = MSG_NET_GAME_START; + } + else if (tmpPacket->ToNetPacketPlayerJoined()) + { + NetPacketPlayerJoined::Data playerData; + tmpPacket->ToNetPacketPlayerJoined()->GetData(playerData); + client.GetCallback().SignalNetClientPlayerJoined(playerData.playerName); + client.GetPlayerMap()[playerData.playerId] = playerData.playerName; + } + else if (tmpPacket->ToNetPacketPlayerLeft()) + { + // TODO hacked. + NetPacketPlayerLeft::Data playerData; + tmpPacket->ToNetPacketPlayerLeft()->GetData(playerData); + client.GetCallback().SignalNetClientPlayerLeft(client.GetPlayerMap()[playerData.playerId]); + client.GetPlayerMap().erase(playerData.playerId); + } } + // TODO: handle error packet return retVal; } diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index 8b7751dc..27fdaa61 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -180,3 +180,9 @@ ClientThread::GetSenderCallback() return *m_senderCallback; } +ClientThread::PlayerMap & +ClientThread::GetPlayerMap() +{ + return m_playerMap; +} + diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index ed57efaa..c8183166 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -158,6 +158,12 @@ NetPacket::Create(char *data, unsigned &dataSize) case NET_TYPE_GAME_START: tmpPacket = boost::shared_ptr(new NetPacketGameStart); break; + case NET_TYPE_PLAYER_JOINED: + tmpPacket = boost::shared_ptr(new NetPacketPlayerJoined); + break; + case NET_TYPE_PLAYER_LEFT: + tmpPacket = boost::shared_ptr(new NetPacketPlayerLeft); + break; case NET_TYPE_ERROR: tmpPacket = boost::shared_ptr(new NetPacketError); break; @@ -260,6 +266,18 @@ NetPacket::ToNetPacketGameStart() const return NULL; } +const NetPacketPlayerJoined * +NetPacket::ToNetPacketPlayerJoined() const +{ + return NULL; +} + +const NetPacketPlayerLeft * +NetPacket::ToNetPacketPlayerLeft() const +{ + return NULL; +} + const NetPacketError * NetPacket::ToNetPacketError() const { @@ -553,6 +571,164 @@ NetPacketGameStart::Check(const NetPacketHeader* data) const //----------------------------------------------------------------------------- +NetPacketPlayerJoined::NetPacketPlayerJoined() +: NetPacket(NET_TYPE_PLAYER_JOINED, sizeof(NetPacketPlayerJoinedData)) +{ +} + +NetPacketPlayerJoined::~NetPacketPlayerJoined() +{ +} + +boost::shared_ptr +NetPacketPlayerJoined::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketPlayerJoined); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketPlayerJoined::SetData(const NetPacketPlayerJoined::Data &inData) +{ + u_int16_t playerNameLen = (u_int16_t)inData.playerName.length(); + + if (!playerNameLen || playerNameLen > MAX_NAME_SIZE) + throw NetException(ERR_NET_INVALID_PLAYER_NAME, 0); + + // Resize the packet so that the data fits in. + Resize((u_int16_t) + (sizeof(NetPacketPlayerJoinedData) + ADD_PADDING(playerNameLen))); + + NetPacketPlayerJoinedData *tmpData = (NetPacketPlayerJoinedData *)GetRawData(); + assert(tmpData); + + // Set the data. + tmpData->playerFlags = htons((inData.ptype == PLAYER_TYPE_HUMAN) ? NET_PLAYER_FLAG_HUMAN : 0); + tmpData->playerId = htons(inData.playerId); + tmpData->playerNumber = htons(inData.playerNumber); + tmpData->playerNameLength = htons(playerNameLen); + memcpy(tmpData->playerName, inData.playerName.c_str(), playerNameLen); +} + +void +NetPacketPlayerJoined::GetData(NetPacketPlayerJoined::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketPlayerJoinedData *tmpData = (NetPacketPlayerJoinedData *)GetRawData(); + assert(tmpData); + + outData.ptype = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_HUMAN) ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER; + outData.playerId = ntohs(tmpData->playerId); + outData.playerNumber = ntohs(tmpData->playerNumber); + outData.playerName = string(tmpData->playerName, ntohs(tmpData->playerNameLength)); +} + +const NetPacketPlayerJoined * +NetPacketPlayerJoined::ToNetPacketPlayerJoined() const +{ + return this; +} + +void +NetPacketPlayerJoined::Check(const NetPacketHeader* data) const +{ + assert(data); + + u_int16_t dataLen = ntohs(data->length); + if (dataLen < sizeof(NetPacketPlayerJoinedData)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + + NetPacketPlayerJoinedData *tmpData = (NetPacketPlayerJoinedData *)data; + int playerNameLength = ntohs(tmpData->playerNameLength); + // Generous checking - larger packets are allowed. + if (dataLen < + sizeof(NetPacketPlayerJoinedData) + + ADD_PADDING(playerNameLength)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check string sizes. + if (!playerNameLength + || playerNameLength > MAX_NAME_SIZE) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } +} + +//----------------------------------------------------------------------------- + +NetPacketPlayerLeft::NetPacketPlayerLeft() +: NetPacket(NET_TYPE_PLAYER_LEFT, sizeof(NetPacketPlayerLeftData)) +{ +} + +NetPacketPlayerLeft::~NetPacketPlayerLeft() +{ +} + +boost::shared_ptr +NetPacketPlayerLeft::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketPlayerLeft); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketPlayerLeft::SetData(const NetPacketPlayerLeft::Data &inData) +{ + NetPacketPlayerLeftData *tmpData = (NetPacketPlayerLeftData *)GetRawData(); + assert(tmpData); + + // Set the data. + tmpData->playerId = htons(inData.playerId); +} + +void +NetPacketPlayerLeft::GetData(NetPacketPlayerLeft::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketPlayerLeftData *tmpData = (NetPacketPlayerLeftData *)GetRawData(); + assert(tmpData); + + outData.playerId = ntohs(tmpData->playerId); +} + +const NetPacketPlayerLeft * +NetPacketPlayerLeft::ToNetPacketPlayerLeft() const +{ + return this; +} + +void +NetPacketPlayerLeft::Check(const NetPacketHeader* data) const +{ + assert(data); + + u_int16_t dataLen = ntohs(data->length); + if (dataLen < sizeof(NetPacketPlayerLeftData)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } +} + +//----------------------------------------------------------------------------- + NetPacketError::NetPacketError() : NetPacket(NET_TYPE_ERROR, sizeof(NetPacketErrorData)) { diff --git a/src/net/common/senderthread.cpp b/src/net/common/senderthread.cpp index 326245ab..e064c3fc 100644 --- a/src/net/common/senderthread.cpp +++ b/src/net/common/senderthread.cpp @@ -35,7 +35,7 @@ SenderThread::~SenderThread() } void -SenderThread::Send(boost::shared_ptr packet, SOCKET sock) +SenderThread::Send(SOCKET sock, boost::shared_ptr packet) { if (packet.get() && IS_VALID_SOCKET(sock)) { diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index d4bd0c29..d8f9d89b 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -27,8 +27,6 @@ #include #include -#include - using namespace std; #define SERVER_WAIT_TIMEOUT_MSEC 50 @@ -82,12 +80,11 @@ ServerRecvStateInit::Process(ServerRecvThread &server) try { packet = server.GetReceiver().Recv(recvSock); - } catch (const NetException &e) + } catch (const NetException &) { if (session.get()) { - //server.CloseSessionDelayed(session); - Thread::Msleep(10); + server.CloseSessionDelayed(session); return retVal; } } @@ -99,6 +96,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (session->GetState() != SessionData::Init) { server.SessionError(session, ERR_SOCK_INVALID_STATE); + server.CloseSessionDelayed(session); return retVal; } @@ -107,6 +105,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (!tmpPacket) { server.SessionError(session, ERR_SOCK_INVALID_PACKET); + server.CloseSessionDelayed(session); return retVal; } @@ -117,6 +116,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (joinGameData.versionMajor != NET_VERSION_MAJOR) { server.SessionError(session, ERR_NET_VERSION_NOT_SUPPORTED); + server.CloseSessionDelayed(session); return retVal; } @@ -124,6 +124,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (!server.CheckPassword(joinGameData.password)) { server.SessionError(session, ERR_NET_INVALID_PASSWORD); + server.CloseSessionDelayed(session); return retVal; } @@ -133,6 +134,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (curNumPlayers >= (size_t)server.GetGameData().numberOfPlayers) { server.SessionError(session, ERR_NET_SERVER_FULL); + server.CloseSessionDelayed(session); return retVal; } @@ -140,30 +142,58 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (server.IsPlayerConnected(joinGameData.playerName)) { server.SessionError(session, ERR_NET_PLAYER_NAME_IN_USE); + server.CloseSessionDelayed(session); return retVal; } // Create player data object. - boost::shared_ptr tmpPlayerData(new PlayerData(m_curUniquePlayerId++)); + boost::shared_ptr tmpPlayerData(new PlayerData(m_curUniquePlayerId++, 0)); tmpPlayerData->SetName(joinGameData.playerName); tmpPlayerData->SetPlayerType(joinGameData.ptype); - // Signal joining player to GUI. - server.GetCallback().SignalNetServerPlayerJoined(tmpPlayerData->GetName()); - // Send ACK to client. boost::shared_ptr answer(new NetPacketJoinGameAck); NetPacketJoinGameAck::Data joinGameAckData; joinGameAckData.playerId = tmpPlayerData->GetUniqueId(); - joinGameAckData.playerNumber = 0;//playerDataList.size(); + joinGameAckData.playerNumber = tmpPlayerData->GetNumber(); joinGameAckData.sessionId = session->GetId(); // TODO: currently unused. joinGameAckData.gameData = server.GetGameData(); static_cast(answer.get())->SetData(joinGameAckData); - server.GetSender().Send(answer, recvSock); - session->SetState(SessionData::Established); + server.GetSender().Send(recvSock, answer); - // Store player data in list. - //playerDataList.push_back(tmpPlayerData); + // Send notifications for connected players to client. + PlayerDataList tmpPlayerList = server.GetPlayerDataList(); + PlayerDataList::iterator player_i = tmpPlayerList.begin(); + PlayerDataList::iterator player_end = tmpPlayerList.end(); + while (player_i != player_end) + { + boost::shared_ptr otherPlayerJoined(new NetPacketPlayerJoined); + NetPacketPlayerJoined::Data otherPlayerJoinedData; + otherPlayerJoinedData.playerId = (*player_i)->GetUniqueId(); + otherPlayerJoinedData.playerName = (*player_i)->GetName(); + otherPlayerJoinedData.playerNumber = (*player_i)->GetNumber(); + otherPlayerJoinedData.ptype = (*player_i)->GetType(); + static_cast(otherPlayerJoined.get())->SetData(otherPlayerJoinedData); + server.GetSender().Send(session->GetSocket(), otherPlayerJoined); + + ++player_i; + } + + // Send "Player Joined" to other clients. + boost::shared_ptr thisPlayerJoined(new NetPacketPlayerJoined); + NetPacketPlayerJoined::Data thisPlayerJoinedData; + thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId(); + thisPlayerJoinedData.playerName = tmpPlayerData->GetName(); + thisPlayerJoinedData.playerNumber = tmpPlayerData->GetNumber(); + thisPlayerJoinedData.ptype = tmpPlayerData->GetType(); + static_cast(thisPlayerJoined.get())->SetData(thisPlayerJoinedData); + server.SendToAllButOnePlayers(thisPlayerJoined, session->GetSocket()); + + // Set player data for session. + server.SetSessionPlayerData(session, tmpPlayerData); + + // Session is now established. + session->SetState(SessionData::Established); } } return retVal; diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index fee6d3a1..1eae433b 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -26,6 +26,8 @@ #include #include +#define SERVER_CLOSE_SESSION_DELAY_SEC 10 + using namespace std; class ServerSenderCallback : public SenderCallback @@ -69,13 +71,13 @@ ServerRecvThread::Init(const string &pwd, const GameData &gameData) } void -ServerRecvThread::SendError(int errorCode, SOCKET s) +ServerRecvThread::SendError(SOCKET s, int errorCode) { boost::shared_ptr packet(new NetPacketError); NetPacketError::Data errorData; errorData.errorCode = errorCode; static_cast(packet.get())->SetData(errorData); - GetSender().Send(packet, s); + GetSender().Send(s, packet); } void @@ -90,11 +92,57 @@ ServerRecvThread::SendToAllPlayers(boost::shared_ptr packet) while (i != end) { // Send each client a copy of the packet. - GetSender().Send(boost::shared_ptr(packet->Clone()), i->first); + GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); ++i; } } +void +ServerRecvThread::SendToAllButOnePlayers(boost::shared_ptr packet, SOCKET except) +{ + // This function needs to be thread safe. + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SocketSessionMap::iterator i = m_sessionMap.begin(); + SocketSessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + // Send each client but one a copy of the packet. + if (i->first != except) + GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); + ++i; + } +} + +void +ServerRecvThread::CloseSessionDelayed(boost::shared_ptr sessionData) +{ + { + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + m_sessionMap.erase(sessionData->GetSocket()); + } + + boost::shared_ptr tmpPlayerData = sessionData->GetPlayerData(); + if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty()) + { + GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName()); + + // Send "Player Left" to clients. + boost::shared_ptr thisPlayerLeft(new NetPacketPlayerLeft); + NetPacketPlayerLeft::Data thisPlayerLeftData; + thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId(); + static_cast(thisPlayerLeft.get())->SetData(thisPlayerLeftData); + SendToAllPlayers(thisPlayerLeft); + } + + boost::microsec_timer closeTimer; + closeTimer.start(); + CloseSessionList::value_type closeSessionData(closeTimer, sessionData); + m_closeSessionList.push_back(closeSessionData); +} + void ServerRecvThread::AddConnection(boost::shared_ptr data) { @@ -143,6 +191,8 @@ ServerRecvThread::Main() GetState().Process(*this); // Process thread-safe notifications. NotificationLoop(); + // Close sessions. + CloseSessionLoop(); } } catch (const NetException &) { @@ -174,6 +224,21 @@ ServerRecvThread::NotificationLoop() } } +void +ServerRecvThread::CloseSessionLoop() +{ + CloseSessionList::iterator i = m_closeSessionList.begin(); + CloseSessionList::iterator end = m_closeSessionList.end(); + + while (i != end) + { + CloseSessionList::iterator cur = i++; + + if (cur->first.elapsed().seconds() >= SERVER_CLOSE_SESSION_DELAY_SEC) + m_closeSessionList.erase(cur); + } +} + SOCKET ServerRecvThread::Select() { @@ -300,7 +365,7 @@ void ServerRecvThread::SessionError(boost::shared_ptr sessionData, int errorCode) { assert(sessionData.get()); - SendError(errorCode, sessionData->GetSocket()); + SendError(sessionData->GetSocket(), errorCode); } SenderThread & @@ -360,6 +425,34 @@ ServerRecvThread::IsPlayerConnected(const std::string &playerName) const return retVal; } +void +ServerRecvThread::SetSessionPlayerData(boost::shared_ptr sessionData, boost::shared_ptr playerData) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); // Paranoia + sessionData->SetPlayerData(playerData); + // Signal joining player to GUI. + GetCallback().SignalNetServerPlayerJoined(playerData->GetName()); +} + +PlayerDataList +ServerRecvThread::GetPlayerDataList() const +{ + PlayerDataList playerList; + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SocketSessionMap::const_iterator session_i = m_sessionMap.begin(); + SocketSessionMap::const_iterator session_end = m_sessionMap.end(); + + while (session_i != session_end) + { + boost::shared_ptr tmpPlayer(session_i->second->GetPlayerData()); + if (tmpPlayer.get() && !tmpPlayer->GetName().empty()) + playerList.push_back(tmpPlayer); + ++session_i; + } + return playerList; +} + ServerSenderCallback & ServerRecvThread::GetSenderCallback() { diff --git a/src/net/netpacket.h b/src/net/netpacket.h index 2bdd5c67..c3fa92e1 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -39,6 +39,8 @@ struct NetPacketHeader; class NetPacketJoinGame; class NetPacketJoinGameAck; class NetPacketGameStart; +class NetPacketPlayerJoined; +class NetPacketPlayerLeft; class NetPacketError; class NetPacket @@ -61,6 +63,8 @@ public: virtual const NetPacketJoinGame *ToNetPacketJoinGame() const; virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const; virtual const NetPacketGameStart *ToNetPacketGameStart() const; + virtual const NetPacketPlayerJoined *ToNetPacketPlayerJoined() const; + virtual const NetPacketPlayerLeft *ToNetPacketPlayerLeft() const; virtual const NetPacketError *ToNetPacketError() const; protected: @@ -150,6 +154,55 @@ protected: virtual void Check(const NetPacketHeader* data) const; }; +class NetPacketPlayerJoined : public NetPacket +{ +public: + struct Data + { + u_int16_t playerId; + u_int16_t playerNumber; + PlayerType ptype; + std::string playerName; + }; + + NetPacketPlayerJoined(); + virtual ~NetPacketPlayerJoined(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketPlayerJoined *ToNetPacketPlayerJoined() const; + +protected: + + virtual void Check(const NetPacketHeader* data) const; +}; + +class NetPacketPlayerLeft : public NetPacket +{ +public: + struct Data + { + u_int16_t playerId; + }; + + NetPacketPlayerLeft(); + virtual ~NetPacketPlayerLeft(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketPlayerLeft *ToNetPacketPlayerLeft() const; + +protected: + + virtual void Check(const NetPacketHeader* data) const; +}; + class NetPacketError : public NetPacket { public: diff --git a/src/net/senderthread.h b/src/net/senderthread.h index d049b933..ed09a030 100644 --- a/src/net/senderthread.h +++ b/src/net/senderthread.h @@ -39,7 +39,7 @@ public: SenderThread(SenderCallback &cb); virtual ~SenderThread(); - void Send(boost::shared_ptr packet, SOCKET sock); + void Send(SOCKET sock, boost::shared_ptr packet); protected: diff --git a/src/net/servercallback.h b/src/net/servercallback.h index d091c298..4278585f 100644 --- a/src/net/servercallback.h +++ b/src/net/servercallback.h @@ -32,6 +32,7 @@ public: virtual void SignalNetServerError(int errorID, int osErrorID) = 0; virtual void SignalNetServerPlayerJoined(const std::string &playerName) = 0; + virtual void SignalNetServerPlayerLeft(const std::string &playerName) = 0; }; #endif diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index f9b41e5a..6991ec69 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -22,15 +22,17 @@ #define _SERVERRECVTHREAD_H_ #include -#include -#include -#include -#include - #include #include #include +#include +#include +#include +#include +#include +#include + #define RECEIVER_THREAD_TERMINATE_TIMEOUT 200 // Notifications @@ -61,11 +63,13 @@ protected: typedef std::deque > ConnectQueue; typedef std::map > SocketSessionMap; typedef std::deque NotificationQueue; + typedef std::list > > CloseSessionList; // Main function of the thread. virtual void Main(); void NotificationLoop(); + void CloseSessionLoop(); SOCKET Select(); @@ -79,8 +83,11 @@ protected: void AddSession(boost::shared_ptr sessionData); void SessionError(boost::shared_ptr sessionData, int errorCode); - void SendError(int errorCode, SOCKET s); + void SendError(SOCKET s, int errorCode); void SendToAllPlayers(boost::shared_ptr packet); + void SendToAllButOnePlayers(boost::shared_ptr packet, SOCKET except); + + void CloseSessionDelayed(boost::shared_ptr sessionData); SenderThread &GetSender(); ReceiverHelper &GetReceiver(); @@ -90,6 +97,8 @@ protected: size_t GetCurNumberOfPlayers() const; bool IsPlayerConnected(const std::string &playerName) const; + void SetSessionPlayerData(boost::shared_ptr sessionData, boost::shared_ptr playerData); + PlayerDataList GetPlayerDataList() const; ServerSenderCallback &GetSenderCallback(); @@ -105,6 +114,8 @@ private: SocketSessionMap m_sessionMap; mutable boost::mutex m_sessionMapMutex; + CloseSessionList m_closeSessionList; + std::auto_ptr m_receiver; std::auto_ptr m_sender; diff --git a/src/playerdata.cpp b/src/playerdata.cpp index 79af9620..575dc8fc 100644 --- a/src/playerdata.cpp +++ b/src/playerdata.cpp @@ -19,8 +19,8 @@ #include -PlayerData::PlayerData(unsigned uniqueId) -: m_uniqueId(uniqueId), m_type(PLAYER_TYPE_COMPUTER) +PlayerData::PlayerData(unsigned uniqueId, int number) +: m_uniqueId(uniqueId), m_number(number), m_type(PLAYER_TYPE_COMPUTER) { } diff --git a/src/playerdata.h b/src/playerdata.h index 026ff224..a6e38067 100644 --- a/src/playerdata.h +++ b/src/playerdata.h @@ -35,7 +35,7 @@ enum PlayerType class PlayerData { public: - PlayerData(unsigned uniqueId); + PlayerData(unsigned uniqueId, int number); ~PlayerData(); const std::string &GetName() const @@ -52,9 +52,12 @@ public: {m_type = type;} unsigned GetUniqueId() const {return m_uniqueId;} + int GetNumber() const + {return m_number;} private: unsigned m_uniqueId; + int m_number; std::string m_name; std::string m_avatarFile; PlayerType m_type; diff --git a/src/session.cpp b/src/session.cpp index 5c6743e6..b3106d8f 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -69,7 +69,7 @@ void Session::startGame(const GameData &gameData) { //PlayerData erzeugen // TODO: PlayerType setzen // UniqueId = PlayerNumber for local games. - boost::shared_ptr playerData(new PlayerData(i)); + boost::shared_ptr playerData(new PlayerData(i, i)); playerData->SetName(myConfig->readConfigString(myName.str())); playerData->SetAvatarFile(myConfig->readConfigString(myAvatar.str()));