Show avatars in network games. User defined avatars are not transfered yet, but this is already prepared for integration.
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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<unsigned, GameInfo> GameInfoMap;
|
||||
@@ -133,6 +136,7 @@ private:
|
||||
std::auto_ptr<ClientSenderCallback> m_senderCallback;
|
||||
ClientState *m_curState;
|
||||
GuiInterface &m_gui;
|
||||
AvatarManager &m_avatarManager;
|
||||
|
||||
std::auto_ptr<SenderThread> m_sender;
|
||||
std::auto_ptr<ReceiverHelper> m_receiver;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <net/clientexception.h>
|
||||
#include <net/socket_helper.h>
|
||||
#include <net/socket_msg.h>
|
||||
#include <core/avatarmanager.h>
|
||||
|
||||
#include <game.h>
|
||||
#include <playerinterface.h>
|
||||
@@ -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<NetPacket> packet(new NetPacketInit);
|
||||
((NetPacketInit *)packet.get())->SetData(initData);
|
||||
@@ -549,6 +556,7 @@ ClientStateWaitJoin::InternalProcess(ClientThread &client, boost::shared_ptr<Net
|
||||
boost::shared_ptr<PlayerData> 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_ptr<Net
|
||||
playerData.reset(
|
||||
new PlayerData(netPlayerData.playerId, 0, info.ptype, netPlayerData.prights));
|
||||
playerData->SetName(info.playerName);
|
||||
if (info.hasAvatar)
|
||||
{
|
||||
string avatarFile;
|
||||
if (client.GetAvatarManager().GetAvatarFileName(info.avatar, avatarFile))
|
||||
playerData->SetAvatarFile(avatarFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <net/receiverhelper.h>
|
||||
#include <net/clientexception.h>
|
||||
#include <net/socket_msg.h>
|
||||
#include <core/avatarmanager.h>
|
||||
#include <clientenginefactory.h>
|
||||
#include <game.h>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<PlayerType>(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);
|
||||
|
||||
@@ -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<NetPacket> 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<NetPacketPlayerInfo *>(info.get())->SetData(infoData);
|
||||
server.GetSender().Send(session.sessionData->GetSocket(), info);
|
||||
}
|
||||
|
||||
@@ -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<NetPacket> 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<NetPacketPlayerInfo *>(info.get())->SetData(infoData);
|
||||
GetSender().Send(session.sessionData->GetSocket(), info);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <game_defs.h>
|
||||
#include <gamedata.h>
|
||||
#include <net/socket_helper.h>
|
||||
#include <core/crypthelper.h>
|
||||
|
||||
#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();
|
||||
|
||||
Reference in New Issue
Block a user