diff --git a/src/net/clientthread.h b/src/net/clientthread.h index e25734a9..c43fe903 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -76,6 +76,7 @@ protected: typedef std::map GameInfoMap; typedef std::list > NetPacketList; typedef std::map PlayerInfoMap; + typedef std::map > AvatarDataMap; // Main function of the thread. virtual void Main(); @@ -88,6 +89,10 @@ protected: void SetPlayerInfo(unsigned id, const PlayerInfo &info); void SetNewGameAdmin(unsigned id); + void AddTempAvatarData(unsigned playerId, unsigned avatarSize, AvatarFileType type); + void StoreInTempAvatarData(unsigned playerId, const std::vector &data); + void CompleteTempAvatarData(unsigned playerId); + const ClientContext &GetContext() const; ClientContext &GetContext(); @@ -156,6 +161,8 @@ private: mutable boost::mutex m_playerInfoMapMutex; PlayerIdList m_playerInfoRequestList; + AvatarDataMap m_tempAvatarMap; + unsigned m_curGameId; unsigned m_guiPlayerId; bool m_sessionEstablished; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index f04528a8..00241ce8 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -352,6 +352,7 @@ ClientStateStartSession::Process(ClientThread &client) initData.password = context.GetPassword(); initData.playerName = context.GetPlayerName(); string avatarFile = context.GetAvatarFile(); + initData.showAvatar = false; if (!avatarFile.empty()) { if (client.GetAvatarManager().GetHashForAvatar(avatarFile, initData.avatar)) @@ -394,6 +395,16 @@ AbstractClientStateReceiving::Process(ClientThread &client) NetPacketPlayerInfo::Data infoData; tmpPacket->ToNetPacketPlayerInfo()->GetData(infoData); client.SetPlayerInfo(infoData.playerId, infoData.playerInfo); + // Retrieve avatar if needed. + if (infoData.playerInfo.hasAvatar && !client.GetAvatarManager().HasAvatar(infoData.playerInfo.avatar)) + { + boost::shared_ptr retrieveAvatar(new NetPacketRetrieveAvatar); + NetPacketRetrieveAvatar::Data retrieveAvatarData; + retrieveAvatarData.requestId = infoData.playerId; + retrieveAvatarData.avatar = infoData.playerInfo.avatar; + static_cast(retrieveAvatar.get())->SetData(retrieveAvatarData); + client.GetSender().Send(client.GetContext().GetSocket(), retrieveAvatar); + } } else if (tmpPacket->ToNetPacketRemovedFromGame()) { @@ -481,6 +492,24 @@ AbstractClientStateReceiving::Process(ClientThread &client) tmpPacket->ToNetPacketGameListPlayerLeft()->GetData(playerLeftData); client.ModifyGameInfoRemovePlayer(playerLeftData.gameId, playerLeftData.playerId); } + else if (tmpPacket->ToNetPacketAvatarHeader()) + { + NetPacketAvatarHeader::Data headerData; + tmpPacket->ToNetPacketAvatarHeader()->GetData(headerData); + client.AddTempAvatarData(headerData.requestId, headerData.avatarFileSize, headerData.avatarFileType); + } + else if (tmpPacket->ToNetPacketAvatarFile()) + { + NetPacketAvatarFile::Data fileData; + tmpPacket->ToNetPacketAvatarFile()->GetData(fileData); + client.StoreInTempAvatarData(fileData.requestId, fileData.fileData); + } + else if (tmpPacket->ToNetPacketAvatarEnd()) + { + NetPacketAvatarEnd::Data endData; + tmpPacket->ToNetPacketAvatarEnd()->GetData(endData); + client.CompleteTempAvatarData(endData.requestId); + } else if (tmpPacket->ToNetPacketError()) { // Server reported an error. @@ -543,6 +572,7 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr< { client.GetSender().SendLowPrio(client.GetContext().GetSocket(), tmpList); } + // TODO handle error } return retVal; diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index ee887e75..7177d0b0 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -387,6 +387,7 @@ ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info) boost::mutex::scoped_lock lock(m_playerInfoMapMutex); m_playerInfoMap[id] = info; } + // Update player data for current game. boost::shared_ptr playerData = GetPlayerDataByUniqueId(id); if (playerData.get()) @@ -397,11 +398,15 @@ ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info) { string avatarFile; if (GetAvatarManager().GetAvatarFileName(info.avatar, avatarFile)) + { playerData->SetAvatarFile(avatarFile); + } } } + // Notify GUI GetCallback().SignalNetClientPlayerChanged(id, info.playerName); + } void @@ -416,6 +421,52 @@ ClientThread::SetNewGameAdmin(unsigned id) } } +void +ClientThread::AddTempAvatarData(unsigned playerId, unsigned avatarSize, AvatarFileType type) +{ + boost::shared_ptr tmpAvatar(new AvatarData); + tmpAvatar->fileData.reserve(avatarSize); + tmpAvatar->fileType = type; + tmpAvatar->reportedSize = avatarSize; + + m_tempAvatarMap[playerId] = tmpAvatar; +} + +void +ClientThread::StoreInTempAvatarData(unsigned playerId, const vector &data) +{ + AvatarDataMap::iterator pos = m_tempAvatarMap.find(playerId); + if (pos == m_tempAvatarMap.end()) + throw NetException(ERR_NET_INVALID_REQUEST_ID, 0); + // We trust the server (concerning size of the data). + std::copy(data.begin(), data.end(), back_inserter(pos->second->fileData)); +} + +void +ClientThread::CompleteTempAvatarData(unsigned playerId) +{ + AvatarDataMap::iterator pos = m_tempAvatarMap.find(playerId); + if (pos == m_tempAvatarMap.end()) + throw NetException(ERR_NET_INVALID_REQUEST_ID, 0); + + boost::shared_ptr tmpAvatar = pos->second; + unsigned avatarSize = (unsigned)tmpAvatar->fileData.size(); + if (avatarSize != tmpAvatar->reportedSize) + throw NetException(ERR_NET_WRONG_AVATAR_SIZE, 0); + + PlayerInfo tmpPlayerInfo; + if (!GetCachedPlayerInfo(playerId, tmpPlayerInfo)) + throw NetException(ERR_NET_UNKNOWN_PLAYER_ID, 0); + + GetAvatarManager().StoreAvatarInCache(tmpPlayerInfo.avatar, tmpAvatar->fileType, &tmpAvatar->fileData[0], avatarSize); + // TODO log error + // Free memory. + m_tempAvatarMap.erase(pos); + + // Update player info, but never re-request avatar. + SetPlayerInfo(playerId, tmpPlayerInfo); +} + const ClientContext & ClientThread::GetContext() const { diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 9bb87b7a..71f80587 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -156,6 +156,11 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) // Delegate to Lobby. server.GetLobbyThread().HandleGameRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo()); } + else if (packet->ToNetPacketRetrieveAvatar()) + { + // Delegate to Lobby. + server.GetLobbyThread().HandleGameRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar()); + } else if (packet->ToNetPacketLeaveCurrentGame()) { server.MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST); diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 113f33f1..fa6cba39 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -169,6 +169,13 @@ ServerLobbyThread::HandleGameRetrievePlayerInfo(SessionWrapper session, const Ne HandleNetPacketRetrievePlayerInfo(session, tmpPacket); } +void +ServerLobbyThread::HandleGameRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket) +{ + // Someone within a game requested an avatar. + HandleNetPacketRetrieveAvatar(session, tmpPacket); +} + void ServerLobbyThread::RemoveGame(unsigned id) { @@ -295,6 +302,8 @@ ServerLobbyThread::ProcessLoop() { if (packet->ToNetPacketRetrievePlayerInfo()) HandleNetPacketRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo()); + else if (packet->ToNetPacketRetrieveAvatar()) + HandleNetPacketRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar()); else if (packet->ToNetPacketCreateGame()) HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame()); else if (packet->ToNetPacketJoinGame()) @@ -356,7 +365,7 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketIn m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData); session.playerData = tmpPlayerData; - if (!GetAvatarManager().HasAvatar(initData.avatar)) + if (initData.showAvatar && !GetAvatarManager().HasAvatar(initData.avatar)) RequestPlayerAvatar(session); else EstablishSession(session); @@ -416,6 +425,7 @@ ServerLobbyThread::HandleNetPacketAvatarEnd(SessionWrapper session, const NetPac if (avatarSize == tmpAvatar->reportedSize) { GetAvatarManager().StoreAvatarInCache(avatarMD5, tmpAvatar->fileType, &tmpAvatar->fileData[0], avatarSize); + // TODO log error // Free memory. session.playerData->SetNetAvatarData(boost::shared_ptr()); // Init finished - start session. @@ -454,6 +464,21 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con // TODO: handle error } +void +ServerLobbyThread::HandleNetPacketRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket) +{ + NetPacketRetrieveAvatar::Data request; + tmpPacket.GetData(request); + + string tmpFile; + if (GetAvatarManager().GetAvatarFileName(request.avatar, tmpFile)) + { + NetPacketList tmpPackets; + if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, request.requestId, tmpPackets)) + GetSender().SendLowPrio(session.sessionData->GetSocket(), tmpPackets); + } +} + void ServerLobbyThread::HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket) { diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 27015509..7221b943 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -61,6 +61,7 @@ public: void NotifyStartingGame(unsigned gameId); void HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket); + void HandleGameRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket); void RemoveGame(unsigned id); @@ -88,6 +89,7 @@ protected: void HandleNetPacketAvatarFile(SessionWrapper session, const NetPacketAvatarFile &tmpPacket); void HandleNetPacketAvatarEnd(SessionWrapper session, const NetPacketAvatarEnd &tmpPacket); void HandleNetPacketRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket); + void HandleNetPacketRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket); void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket); void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket); void EstablishSession(SessionWrapper session); diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index 239c4bcd..8b8542e1 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -59,6 +59,8 @@ #define ERR_NET_INVALID_PLAYER_COUNT 115 #define ERR_NET_TOO_MANY_MANUAL_BLINDS 116 #define ERR_NET_BUF_INVALID_SIZE 117 +#define ERR_NET_INVALID_REQUEST_ID 118 +#define ERR_NET_WRONG_AVATAR_SIZE 119 #define ERR_IRC_INTERNAL 151 #define ERR_IRC_CONNECT_FAILED 152