diff --git a/src/net/clientcontext.h b/src/net/clientcontext.h index c7eb51bf..0d200842 100644 --- a/src/net/clientcontext.h +++ b/src/net/clientcontext.h @@ -63,6 +63,10 @@ public: {return m_playerName;} void SetPlayerName(const std::string &playerName) {m_playerName = playerName;} + const std::string &GetAvatarFile() const + {return m_avatarFile;} + void SetAvatarFile(const std::string &avatarFile) + {m_avatarFile = avatarFile;} int GetClientSockaddrSize() const {return m_addrFamily == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);} @@ -79,6 +83,7 @@ private: std::string m_password; sockaddr_storage m_clientSockaddr; std::string m_playerName; + std::string m_avatarFile; ReceiveBuffer m_receiveBuffer; }; diff --git a/src/net/clientthread.h b/src/net/clientthread.h index d1b85ebc..b350958c 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -36,11 +36,12 @@ class ReceiverHelper; class ClientSenderCallback; class Game; class NetPacket; +class AvatarManager; class ClientThread : public Thread { public: - ClientThread(GuiInterface &gui); + ClientThread(GuiInterface &gui, AvatarManager &avatarManager); virtual ~ClientThread(); // Set the parameters. Does not do any error checking. @@ -52,7 +53,8 @@ public: bool ipv6, bool sctp, const std::string &pwd, - const std::string &playerName); + const std::string &playerName, + const std::string &avatarFile); void SendKickPlayer(unsigned playerId); void SendLeaveCurrentGame(); @@ -68,6 +70,7 @@ public: ClientCallback &GetCallback(); GuiInterface &GetGui(); + AvatarManager &GetAvatarManager(); protected: typedef std::map GameInfoMap; @@ -133,6 +136,7 @@ private: std::auto_ptr m_senderCallback; ClientState *m_curState; GuiInterface &m_gui; + AvatarManager &m_avatarManager; std::auto_ptr m_sender; std::auto_ptr m_receiver; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index a67e6c24..cda5fc19 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -349,6 +350,12 @@ ClientStateStartSession::Process(ClientThread &client) NetPacketInit::Data initData; initData.password = context.GetPassword(); initData.playerName = context.GetPlayerName(); + string avatarFile = context.GetAvatarFile(); + if (!avatarFile.empty()) + { + if (client.GetAvatarManager().GetHashForAvatar(avatarFile, initData.avatar)) + initData.showAvatar = true; + } boost::shared_ptr packet(new NetPacketInit); ((NetPacketInit *)packet.get())->SetData(initData); @@ -549,6 +556,7 @@ ClientStateWaitJoin::InternalProcess(ClientThread &client, boost::shared_ptr playerData( new PlayerData(client.GetGuiPlayerId(), 0, PLAYER_TYPE_HUMAN, joinGameAckData.prights)); playerData->SetName(context.GetPlayerName()); + playerData->SetAvatarFile(context.GetAvatarFile()); client.AddPlayerData(playerData); client.SetState(ClientStateWaitGame::Instance()); @@ -628,6 +636,12 @@ ClientStateWaitGame::InternalProcess(ClientThread &client, boost::shared_ptrSetName(info.playerName); + if (info.hasAvatar) + { + string avatarFile; + if (client.GetAvatarManager().GetAvatarFileName(info.avatar, avatarFile)) + playerData->SetAvatarFile(avatarFile); + } } else { diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index 413e161b..6597c78f 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -53,8 +54,9 @@ private: }; -ClientThread::ClientThread(GuiInterface &gui) -: m_curState(NULL), m_gui(gui), m_curGameId(1), m_guiPlayerId(0), m_sessionEstablished(false) +ClientThread::ClientThread(GuiInterface &gui, AvatarManager &avatarManager) +: m_curState(NULL), m_gui(gui), m_avatarManager(avatarManager), + m_curGameId(1), m_guiPlayerId(0), m_sessionEstablished(false) { m_context.reset(new ClientContext); m_senderCallback.reset(new ClientSenderCallback(*this)); @@ -68,7 +70,8 @@ ClientThread::~ClientThread() void ClientThread::Init( - const string &serverAddress, unsigned serverPort, bool ipv6, bool sctp, const string &pwd, const string &playerName) + const string &serverAddress, unsigned serverPort, bool ipv6, bool sctp, + const string &pwd, const string &playerName, const string &avatarFile) { if (IsRunning()) { @@ -84,6 +87,7 @@ ClientThread::Init( context.SetServerPort(serverPort); context.SetPassword(pwd); context.SetPlayerName(playerName); + context.SetAvatarFile(avatarFile); } void @@ -267,6 +271,12 @@ ClientThread::GetGui() return m_gui; } +AvatarManager & +ClientThread::GetAvatarManager() +{ + return m_avatarManager; +} + void ClientThread::Main() { @@ -382,6 +392,12 @@ ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info) { playerData->SetName(info.playerName); playerData->SetType(info.ptype); + if (info.hasAvatar) + { + string avatarFile; + if (GetAvatarManager().GetAvatarFileName(info.avatar, avatarFile)) + playerData->SetAvatarFile(avatarFile); + } } GetCallback().SignalNetClientPlayerChanged(id, info.playerName); diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index ed781203..7ce97aa1 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -68,10 +68,12 @@ using namespace std; #define NET_GAME_FLAG_PASSWORD_PROTECTED 0x01 #define NET_PLAYER_FLAG_HUMAN 0x01 -#define NET_PLAYER_FLAG_ADMIN 0x02 +#define NET_PLAYER_FLAG_HAS_AVATAR 0x02 #define NET_START_FLAG_FILL_WITH_CPU_PLAYERS 0x01 +#define NET_PRIVACY_FLAG_SHOW_AVATAR 0x01 + // Reasons why join game failed. #define NET_JOIN_FAILED_GAME_FULL 0x0001 #define NET_JOIN_FAILED_GAME_ALREADY_RUNNING 0x0002 @@ -118,7 +120,8 @@ struct GCC_PACKED NetPacketInitData u_int16_t requestedVersionMinor; u_int16_t passwordLength; u_int16_t playerNameLength; - u_int32_t reserved; + u_int16_t privacyFlags; + u_int16_t reserved; }; struct GCC_PACKED NetPacketInitAckData @@ -926,16 +929,29 @@ NetPacketInit::SetData(const NetPacketInit::Data &inData) if (passwordLen > MAX_PASSWORD_SIZE) throw NetException(ERR_NET_INVALID_PASSWORD_STR, 0); + int avatarSize = inData.showAvatar ? MD5_DATA_SIZE : 0; // Resize the packet so that the data fits in. Resize((u_int16_t) - (sizeof(NetPacketInitData) + ADD_PADDING(playerNameLen) + ADD_PADDING(passwordLen))); + (sizeof(NetPacketInitData) + + avatarSize + + ADD_PADDING(playerNameLen) + + ADD_PADDING(passwordLen))); NetPacketInitData *tmpData = (NetPacketInitData *)GetRawData(); // Set the data. tmpData->passwordLength = htons(passwordLen); tmpData->playerNameLength = htons(playerNameLen); - char *passwordPtr = (char *)tmpData + sizeof(NetPacketInitData); + + if (inData.showAvatar) + { + // Store MD5 sum of avatar. + tmpData->privacyFlags = htons(NET_PRIVACY_FLAG_SHOW_AVATAR); + char *avatarPtr = (char *)tmpData + sizeof(NetPacketInitData); + memcpy(avatarPtr, inData.avatar.data, MD5_DATA_SIZE); + } + + char *passwordPtr = (char *)tmpData + sizeof(NetPacketInitData) + avatarSize; memcpy(passwordPtr, inData.password.c_str(), passwordLen); memcpy(passwordPtr + ADD_PADDING(passwordLen), inData.playerName.c_str(), playerNameLen); @@ -952,8 +968,17 @@ NetPacketInit::GetData(NetPacketInit::Data &outData) const outData.versionMajor = ntohs(tmpData->requestedVersionMajor); outData.versionMinor = ntohs(tmpData->requestedVersionMinor); + outData.showAvatar = ntohs(tmpData->privacyFlags) & NET_PRIVACY_FLAG_SHOW_AVATAR; + + if (outData.showAvatar) + { + char *avatarPtr = (char *)tmpData + sizeof(NetPacketInitData); + memcpy(outData.avatar.data, avatarPtr, MD5_DATA_SIZE); + } + + int avatarSize = outData.showAvatar ? MD5_DATA_SIZE : 0; u_int16_t passwordLen = ntohs(tmpData->passwordLength); - char *passwordPtr = (char *)tmpData + sizeof(NetPacketInitData); + char *passwordPtr = (char *)tmpData + sizeof(NetPacketInitData) + avatarSize; outData.password = string(passwordPtr, passwordLen); outData.playerName = string(passwordPtr + ADD_PADDING(passwordLen), ntohs(tmpData->playerNameLength)); } @@ -971,12 +996,14 @@ NetPacketInit::InternalCheck(const NetPacketHeader* data) const NetPacketInitData *tmpData = (NetPacketInitData *)data; int passwordLength = ntohs(tmpData->passwordLength); int playerNameLength = ntohs(tmpData->playerNameLength); + int avatarSize = ntohs(tmpData->privacyFlags) & NET_PRIVACY_FLAG_SHOW_AVATAR ? MD5_DATA_SIZE : 0; // Generous checking of dynamic packet size - // larger packets are allowed. // This is because the version number is in this packet, // and later versions might provide larger packets. if (dataLen < sizeof(NetPacketInitData) + + avatarSize + ADD_PADDING(passwordLength) + ADD_PADDING(playerNameLength)) { @@ -990,7 +1017,7 @@ NetPacketInit::InternalCheck(const NetPacketHeader* data) const throw NetException(ERR_SOCK_INVALID_PACKET, 0); } // Check name string. - char *namePtr = (char *)tmpData + sizeof(NetPacketInitData) + ADD_PADDING(passwordLength); + char *namePtr = (char *)tmpData + sizeof(NetPacketInitData) + avatarSize + ADD_PADDING(passwordLength); if (namePtr[0] == 0) { throw NetException(ERR_SOCK_INVALID_PACKET, 0); @@ -1470,17 +1497,27 @@ NetPacketPlayerInfo::SetData(const NetPacketPlayerInfo::Data &inData) if (!playerNameLen || playerNameLen > MAX_NAME_SIZE) throw NetException(ERR_NET_INVALID_PLAYER_NAME, 0); + int avatarSize = inData.playerInfo.hasAvatar ? MD5_DATA_SIZE : 0; // Resize the packet so that the data fits in. Resize((u_int16_t) - (sizeof(NetPacketPlayerInfoData) + ADD_PADDING(playerNameLen))); + (sizeof(NetPacketPlayerInfoData) + avatarSize + ADD_PADDING(playerNameLen))); NetPacketPlayerInfoData *tmpData = (NetPacketPlayerInfoData *)GetRawData(); // Set the data. tmpData->playerId = htonl(inData.playerId); - tmpData->playerFlags = htons(inData.playerInfo.ptype); tmpData->playerNameLength = htons(playerNameLen); - char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerInfoData); + + u_int16_t tmpPlayerFlags = inData.playerInfo.ptype == PLAYER_TYPE_HUMAN ? NET_PLAYER_FLAG_HUMAN : 0; + if (inData.playerInfo.hasAvatar) + { + tmpPlayerFlags |= NET_PLAYER_FLAG_HAS_AVATAR; + char *avatarPtr = (char *)tmpData + sizeof(NetPacketPlayerInfoData); + memcpy(avatarPtr, inData.playerInfo.avatar.data, MD5_DATA_SIZE); + } + tmpData->playerFlags = htons(tmpPlayerFlags); + + char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerInfoData) + avatarSize; memcpy(namePtr, inData.playerInfo.playerName.c_str(), playerNameLen); // Check the packet - just in case. @@ -1494,8 +1531,19 @@ NetPacketPlayerInfo::GetData(NetPacketPlayerInfo::Data &outData) const NetPacketPlayerInfoData *tmpData = (NetPacketPlayerInfoData *)GetRawData(); outData.playerId = ntohl(tmpData->playerId); - outData.playerInfo.ptype = static_cast(ntohs(tmpData->playerFlags)); - char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerInfoData); + u_int16_t tmpPlayerFlags = ntohs(tmpData->playerFlags); + outData.playerInfo.ptype = (tmpPlayerFlags & NET_PLAYER_FLAG_HUMAN) ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER; + outData.playerInfo.hasAvatar = (tmpPlayerFlags & NET_PLAYER_FLAG_HAS_AVATAR) ? true : false; + + if (outData.playerInfo.hasAvatar) + { + char *avatarPtr = (char *)tmpData + sizeof(NetPacketPlayerInfoData); + memcpy(outData.playerInfo.avatar.data, avatarPtr, MD5_DATA_SIZE); + } + + int avatarSize = outData.playerInfo.hasAvatar ? MD5_DATA_SIZE : 0; + + char *namePtr = (char *)tmpData + avatarSize + sizeof(NetPacketPlayerInfoData); outData.playerInfo.playerName = string(namePtr, ntohs(tmpData->playerNameLength)); } @@ -1511,9 +1559,11 @@ NetPacketPlayerInfo::InternalCheck(const NetPacketHeader* data) const u_int16_t dataLen = ntohs(data->length); NetPacketPlayerInfoData *tmpData = (NetPacketPlayerInfoData *)data; int playerNameLength = ntohs(tmpData->playerNameLength); + int avatarSize = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_HAS_AVATAR) ? MD5_DATA_SIZE : 0; // Exact checking this time. if (dataLen != sizeof(NetPacketPlayerInfoData) + + avatarSize + ADD_PADDING(playerNameLength)) { throw NetException(ERR_SOCK_INVALID_PACKET, 0); diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 091651d1..426cd51b 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -157,11 +157,15 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) if (tmpSession.sessionData.get() && tmpSession.playerData.get()) { // Send player info to client. + // TODO this is a copy and paste boost::shared_ptr info(new NetPacketPlayerInfo); NetPacketPlayerInfo::Data infoData; infoData.playerId = tmpSession.playerData->GetUniqueId(); infoData.playerInfo.ptype = tmpSession.playerData->GetType(); infoData.playerInfo.playerName = tmpSession.playerData->GetName(); + infoData.playerInfo.hasAvatar = !tmpSession.playerData->GetAvatarFile().empty(); + if (infoData.playerInfo.hasAvatar) + infoData.playerInfo.avatar.FromString(tmpSession.playerData->GetAvatarFile()); static_cast(info.get())->SetData(infoData); server.GetSender().Send(session.sessionData->GetSocket(), info); } diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 81667440..245af462 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -296,6 +296,8 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketIn new PlayerData(GetNextUniquePlayerId(), 0, PLAYER_TYPE_HUMAN, PLAYER_RIGHTS_NORMAL)); tmpPlayerData->SetName(initData.playerName); tmpPlayerData->SetNetSessionData(session.sessionData); + if (initData.showAvatar) + tmpPlayerData->SetAvatarFile(initData.avatar.ToString()); // Send ACK to client. boost::shared_ptr initAck(new NetPacketInitAck); @@ -344,6 +346,9 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con infoData.playerId = tmpPlayer->GetUniqueId(); infoData.playerInfo.ptype = tmpPlayer->GetType(); infoData.playerInfo.playerName = tmpPlayer->GetName(); + infoData.playerInfo.hasAvatar = !tmpPlayer->GetAvatarFile().empty(); + if (infoData.playerInfo.hasAvatar) + infoData.playerInfo.avatar.FromString(tmpPlayer->GetAvatarFile()); static_cast(info.get())->SetData(infoData); GetSender().Send(session.sessionData->GetSocket(), info); } diff --git a/src/net/netpacket.h b/src/net/netpacket.h index 8bc5892a..29f77269 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -25,6 +25,7 @@ #include #include #include +#include #define NET_VERSION_MAJOR 2 #define NET_VERSION_MINOR 0 @@ -152,6 +153,8 @@ public: int versionMinor; std::string playerName; std::string password; + bool showAvatar; + MD5Buf avatar; }; NetPacketInit(); diff --git a/src/playerdata.h b/src/playerdata.h index ccafc09a..2d16ed27 100644 --- a/src/playerdata.h +++ b/src/playerdata.h @@ -21,6 +21,7 @@ #ifndef _PLAYERDATA_H_ #define _PLAYERDATA_H_ +#include #include #include #include @@ -45,6 +46,8 @@ struct PlayerInfo PlayerInfo() : ptype(PLAYER_TYPE_HUMAN) {} std::string playerName; PlayerType ptype; + bool hasAvatar; + MD5Buf avatar; }; class PlayerData diff --git a/src/session.cpp b/src/session.cpp index b77f20e5..1f755bff 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -119,14 +119,15 @@ void Session::startInternetClient() assert(false); return; } - myNetClient = new ClientThread(*myGui); + myNetClient = new ClientThread(*myGui, *myAvatarManager); myNetClient->Init( myConfig->readConfigString("InternetServerAddress"), myConfig->readConfigInt("InternetServerPort"), myConfig->readConfigInt("InternetServerUseIpv6") == 1, myConfig->readConfigInt("InternetServerUseSctp") == 1, myConfig->readConfigString("InternetServerPassword"), - myConfig->readConfigString("MyName")); + myConfig->readConfigString("MyName"), + myConfig->readConfigString("MyAvatar")); myNetClient->Run(); } @@ -137,14 +138,15 @@ void Session::startNetworkClient(const string &serverAddress, unsigned serverPor assert(false); return; } - myNetClient = new ClientThread(*myGui); + myNetClient = new ClientThread(*myGui, *myAvatarManager); myNetClient->Init( serverAddress, serverPort, ipv6, sctp, pwd, - myConfig->readConfigString("MyName")); + myConfig->readConfigString("MyName"), + myConfig->readConfigString("MyAvatar")); myNetClient->Run(); myNetClient->SendJoinFirstGame(""); } @@ -156,7 +158,7 @@ void Session::startNetworkClientForLocalServer(const GameData &gameData) assert(false); return; } - myNetClient = new ClientThread(*myGui); + myNetClient = new ClientThread(*myGui, *myAvatarManager); bool useIpv6 = myConfig->readConfigInt("ServerUseIpv6") == 1; const char *loopbackAddr = useIpv6 ? "::1" : "127.0.0.1"; myNetClient->Init( @@ -165,7 +167,8 @@ void Session::startNetworkClientForLocalServer(const GameData &gameData) useIpv6, myConfig->readConfigInt("ServerUseSctp") == 1, myConfig->readConfigString("ServerPassword"), - myConfig->readConfigString("MyName")); + myConfig->readConfigString("MyName"), + myConfig->readConfigString("MyAvatar")); myNetClient->Run(); myNetClient->SendCreateGame(gameData, NET_DEFAULT_GAME, ""); }