More preparation towards transferring avatars.
This commit is contained in:
@@ -136,6 +136,17 @@ Server/Client Reply: Avatar File
|
|||||||
[Additional blocks will be sent if data is more than 256 Bytes.]
|
[Additional blocks will be sent if data is more than 256 Bytes.]
|
||||||
|
|
||||||
|
|
||||||
|
Server/Client Reply: End of Avatar
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| Message Type = 6 | Message Length = 8 |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| Request ID |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
|
||||||
Basic Structure: Game Info Block
|
Basic Structure: Game Info Block
|
||||||
|
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|||||||
@@ -24,6 +24,14 @@
|
|||||||
#include <core/crypthelper.h>
|
#include <core/crypthelper.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#define MAX_AVATAR_FILE_SIZE 30720
|
||||||
|
|
||||||
|
struct AvatarFileState;
|
||||||
|
class NetPacket;
|
||||||
|
|
||||||
class AvatarManager
|
class AvatarManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -33,6 +41,11 @@ public:
|
|||||||
|
|
||||||
bool Init(const std::string &dataDir, const std::string &cacheDir);
|
bool Init(const std::string &dataDir, const std::string &cacheDir);
|
||||||
|
|
||||||
|
boost::shared_ptr<AvatarFileState> OpenAvatarFileForChunkRead(const std::string &fileName, unsigned &outFileSize);
|
||||||
|
unsigned ChunkReadAvatarFile(boost::shared_ptr<AvatarFileState> fileState, unsigned char *data, unsigned chunkSize);
|
||||||
|
|
||||||
|
bool SendAvatarFile(const std::string &fileName, unsigned requestId, boost::function<void (boost::shared_ptr<NetPacket>)> sender);
|
||||||
|
|
||||||
bool GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf);
|
bool GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf);
|
||||||
bool GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const;
|
bool GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const;
|
||||||
bool StoreAvatarInCache(const MD5Buf &md5buf, const std::string &fileExtension, const unsigned char *data, unsigned size);
|
bool StoreAvatarInCache(const MD5Buf &md5buf, const std::string &fileExtension, const unsigned char *data, unsigned size);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include "avatarmanager.h"
|
#include "avatarmanager.h"
|
||||||
|
#include <net/netpacket.h>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
@@ -27,6 +28,10 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace boost::filesystem;
|
using namespace boost::filesystem;
|
||||||
|
|
||||||
|
struct AvatarFileState
|
||||||
|
{
|
||||||
|
ifstream inputStream;
|
||||||
|
};
|
||||||
|
|
||||||
AvatarManager::AvatarManager()
|
AvatarManager::AvatarManager()
|
||||||
{
|
{
|
||||||
@@ -53,6 +58,100 @@ AvatarManager::Init(const std::string &dataDir, const std::string &cacheDir)
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<AvatarFileState>
|
||||||
|
AvatarManager::OpenAvatarFileForChunkRead(const std::string &fileName, unsigned &outFileSize)
|
||||||
|
{
|
||||||
|
outFileSize = 0;
|
||||||
|
boost::shared_ptr<AvatarFileState> retVal;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boost::shared_ptr<AvatarFileState> fileState(new AvatarFileState);
|
||||||
|
fileState->inputStream.open(fileName.c_str(), ios_base::in | ios_base::binary);
|
||||||
|
if (!fileState->inputStream.fail())
|
||||||
|
{
|
||||||
|
// Find out file size.
|
||||||
|
// Not fully portable, but works on win/linux/mac.
|
||||||
|
fileState->inputStream.seekg(0, ios_base::beg);
|
||||||
|
std::streampos startPos = fileState->inputStream.tellg();
|
||||||
|
fileState->inputStream.seekg(0, ios_base::end);
|
||||||
|
std::streampos endPos = fileState->inputStream.tellg();
|
||||||
|
fileState->inputStream.seekg(0, ios_base::beg);
|
||||||
|
std::streamoff posDiff(endPos - startPos);
|
||||||
|
outFileSize = (unsigned)posDiff;
|
||||||
|
if (outFileSize <= MAX_AVATAR_FILE_SIZE)
|
||||||
|
retVal = fileState;
|
||||||
|
}
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
AvatarManager::ChunkReadAvatarFile(boost::shared_ptr<AvatarFileState> fileState, unsigned char *data, unsigned chunkSize)
|
||||||
|
{
|
||||||
|
unsigned retVal = 0;
|
||||||
|
if (fileState.get())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!fileState->inputStream.fail() && !fileState->inputStream.eof())
|
||||||
|
{
|
||||||
|
fileState->inputStream.read((char *)data, chunkSize);
|
||||||
|
retVal = fileState->inputStream.gcount();
|
||||||
|
}
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AvatarManager::SendAvatarFile(const string &fileName, unsigned requestId, boost::function<void (boost::shared_ptr<NetPacket>)> sender)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
unsigned fileSize;
|
||||||
|
boost::shared_ptr<AvatarFileState> tmpState = OpenAvatarFileForChunkRead(fileName, fileSize);
|
||||||
|
if (tmpState.get() && fileSize)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<NetPacket> avatarHeader(new NetPacketAvatarHeader);
|
||||||
|
NetPacketAvatarHeader::Data avatarHeaderData;
|
||||||
|
avatarHeaderData.requestId = requestId;
|
||||||
|
avatarHeaderData.avatarFileSize = fileSize;
|
||||||
|
avatarHeaderData.avatarFileType = AVATAR_TYPE_PNG; // TODO
|
||||||
|
static_cast<NetPacketAvatarHeader *>(avatarHeader.get())->SetData(avatarHeaderData);
|
||||||
|
sender(avatarHeader);
|
||||||
|
|
||||||
|
unsigned numBytes = 0;
|
||||||
|
unsigned totalBytesRead = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
boost::shared_ptr<NetPacketAvatarFile> avatarFile(new NetPacketAvatarFile);
|
||||||
|
NetPacketAvatarFile::Data avatarFileData;
|
||||||
|
avatarFileData.fileData.resize(MAX_FILE_DATA_SIZE);
|
||||||
|
numBytes = ChunkReadAvatarFile(tmpState, &avatarFileData.fileData[0], MAX_FILE_DATA_SIZE);
|
||||||
|
if (numBytes)
|
||||||
|
{
|
||||||
|
avatarFileData.fileData.resize(numBytes);
|
||||||
|
avatarFileData.requestId = requestId;
|
||||||
|
totalBytesRead += numBytes;
|
||||||
|
static_cast<NetPacketAvatarFile *>(avatarFile.get())->SetData(avatarFileData);
|
||||||
|
sender(avatarFile);
|
||||||
|
}
|
||||||
|
} while (numBytes);
|
||||||
|
// TODO error handling if numBytes != totalBytesRead
|
||||||
|
boost::shared_ptr<NetPacket> avatarEnd(new NetPacketAvatarEnd);
|
||||||
|
NetPacketAvatarEnd::Data avatarEndData;
|
||||||
|
avatarEndData.requestId = requestId;
|
||||||
|
static_cast<NetPacketAvatarEnd *>(avatarEnd.get())->SetData(avatarEndData);
|
||||||
|
sender(avatarEnd);
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
// else TODO error handling
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AvatarManager::GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf)
|
AvatarManager::GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf)
|
||||||
{
|
{
|
||||||
@@ -106,7 +205,7 @@ AvatarManager::StoreAvatarInCache(const MD5Buf &md5buf, const std::string &fileE
|
|||||||
path tmpPath(m_cacheDir);
|
path tmpPath(m_cacheDir);
|
||||||
tmpPath /= (md5buf.ToString() + "." + fileExtension);
|
tmpPath /= (md5buf.ToString() + "." + fileExtension);
|
||||||
string fileName(tmpPath.file_string());
|
string fileName(tmpPath.file_string());
|
||||||
ofstream o(fileName.c_str());
|
ofstream o(fileName.c_str(), ios_base::out | ios_base::binary);
|
||||||
o.write((const char *)data, size);
|
o.write((const char *)data, size);
|
||||||
m_avatars.insert(AvatarMap::value_type(md5buf, fileName));
|
m_avatars.insert(AvatarMap::value_type(md5buf, fileName));
|
||||||
retVal = true;
|
retVal = true;
|
||||||
|
|||||||
@@ -527,6 +527,13 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr<
|
|||||||
client.SetSessionEstablished(true);
|
client.SetSessionEstablished(true);
|
||||||
retVal = MSG_SOCK_SESSION_DONE;
|
retVal = MSG_SOCK_SESSION_DONE;
|
||||||
}
|
}
|
||||||
|
else if (packet->ToNetPacketRetrieveAvatar())
|
||||||
|
{
|
||||||
|
NetPacketRetrieveAvatar::Data retrieveAvatarData;
|
||||||
|
packet->ToNetPacketRetrieveAvatar()->GetData(retrieveAvatarData);
|
||||||
|
|
||||||
|
// Before letting us join the lobby, the server requests our avatar.
|
||||||
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ using namespace std;
|
|||||||
#define NET_TYPE_RETRIEVE_AVATAR 0x0003
|
#define NET_TYPE_RETRIEVE_AVATAR 0x0003
|
||||||
#define NET_TYPE_AVATAR_HEADER 0x0004
|
#define NET_TYPE_AVATAR_HEADER 0x0004
|
||||||
#define NET_TYPE_AVATAR_FILE 0x0005
|
#define NET_TYPE_AVATAR_FILE 0x0005
|
||||||
|
#define NET_TYPE_AVATAR_END 0x0006
|
||||||
#define NET_TYPE_GAME_LIST_NEW 0x0010
|
#define NET_TYPE_GAME_LIST_NEW 0x0010
|
||||||
#define NET_TYPE_GAME_LIST_UPDATE 0x0011
|
#define NET_TYPE_GAME_LIST_UPDATE 0x0011
|
||||||
#define NET_TYPE_GAME_LIST_PLAYER_JOINED 0x0012
|
#define NET_TYPE_GAME_LIST_PLAYER_JOINED 0x0012
|
||||||
@@ -157,6 +158,12 @@ struct GCC_PACKED NetPacketAvatarFileData
|
|||||||
u_int32_t requestId;
|
u_int32_t requestId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GCC_PACKED NetPacketAvatarEndData
|
||||||
|
{
|
||||||
|
NetPacketHeader head;
|
||||||
|
u_int32_t requestId;
|
||||||
|
};
|
||||||
|
|
||||||
struct GCC_PACKED GameInfoData
|
struct GCC_PACKED GameInfoData
|
||||||
{
|
{
|
||||||
u_int16_t maxNumberOfPlayers;
|
u_int16_t maxNumberOfPlayers;
|
||||||
@@ -587,6 +594,9 @@ NetPacket::Create(char *data, unsigned &dataSize)
|
|||||||
case NET_TYPE_AVATAR_FILE:
|
case NET_TYPE_AVATAR_FILE:
|
||||||
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketAvatarFile);
|
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketAvatarFile);
|
||||||
break;
|
break;
|
||||||
|
case NET_TYPE_AVATAR_END:
|
||||||
|
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketAvatarEnd);
|
||||||
|
break;
|
||||||
case NET_TYPE_GAME_LIST_NEW:
|
case NET_TYPE_GAME_LIST_NEW:
|
||||||
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameListNew);
|
tmpPacket = boost::shared_ptr<NetPacket>(new NetPacketGameListNew);
|
||||||
break;
|
break;
|
||||||
@@ -800,6 +810,12 @@ NetPacket::ToNetPacketAvatarFile() const
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NetPacketAvatarEnd *
|
||||||
|
NetPacket::ToNetPacketAvatarEnd() const
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const NetPacketGameListNew *
|
const NetPacketGameListNew *
|
||||||
NetPacket::ToNetPacketGameListNew() const
|
NetPacket::ToNetPacketGameListNew() const
|
||||||
{
|
{
|
||||||
@@ -1431,6 +1447,62 @@ NetPacketAvatarFile::InternalCheck(const NetPacketHeader*) const
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NetPacketAvatarEnd::NetPacketAvatarEnd()
|
||||||
|
: NetPacket(NET_TYPE_AVATAR_END, sizeof(NetPacketAvatarEndData), sizeof(NetPacketAvatarEndData))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPacketAvatarEnd::~NetPacketAvatarEnd()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<NetPacket>
|
||||||
|
NetPacketAvatarEnd::Clone() const
|
||||||
|
{
|
||||||
|
boost::shared_ptr<NetPacket> newPacket(new NetPacketAvatarEnd);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newPacket->SetRawData(GetRawData());
|
||||||
|
} catch (const NetException &)
|
||||||
|
{
|
||||||
|
// Need to return the new packet anyway.
|
||||||
|
}
|
||||||
|
return newPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetPacketAvatarEnd::SetData(const NetPacketAvatarEnd::Data &inData)
|
||||||
|
{
|
||||||
|
NetPacketAvatarEndData *tmpData = (NetPacketAvatarEndData *)GetRawData();
|
||||||
|
|
||||||
|
tmpData->requestId = htonl(inData.requestId);
|
||||||
|
|
||||||
|
// Check the packet - just in case.
|
||||||
|
Check(GetRawData());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetPacketAvatarEnd::GetData(NetPacketAvatarEnd::Data &outData) const
|
||||||
|
{
|
||||||
|
NetPacketAvatarEndData *tmpData = (NetPacketAvatarEndData *)GetRawData();
|
||||||
|
|
||||||
|
outData.requestId = ntohl(tmpData->requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NetPacketAvatarEnd *
|
||||||
|
NetPacketAvatarEnd::ToNetPacketAvatarEnd() const
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetPacketAvatarEnd::InternalCheck(const NetPacketHeader*) const
|
||||||
|
{
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
NetPacketGameListNew::NetPacketGameListNew()
|
NetPacketGameListNew::NetPacketGameListNew()
|
||||||
: NetPacket(NET_TYPE_GAME_LIST_NEW, sizeof(NetPacketGameListNewData), MAX_PACKET_SIZE)
|
: NetPacket(NET_TYPE_GAME_LIST_NEW, sizeof(NetPacketGameListNewData), MAX_PACKET_SIZE)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class NetPacketInitAck;
|
|||||||
class NetPacketRetrieveAvatar;
|
class NetPacketRetrieveAvatar;
|
||||||
class NetPacketAvatarHeader;
|
class NetPacketAvatarHeader;
|
||||||
class NetPacketAvatarFile;
|
class NetPacketAvatarFile;
|
||||||
|
class NetPacketAvatarEnd;
|
||||||
class NetPacketGameListNew;
|
class NetPacketGameListNew;
|
||||||
class NetPacketGameListUpdate;
|
class NetPacketGameListUpdate;
|
||||||
class NetPacketGameListPlayerJoined;
|
class NetPacketGameListPlayerJoined;
|
||||||
@@ -106,6 +107,7 @@ public:
|
|||||||
virtual const NetPacketRetrieveAvatar *ToNetPacketRetrieveAvatar() const;
|
virtual const NetPacketRetrieveAvatar *ToNetPacketRetrieveAvatar() const;
|
||||||
virtual const NetPacketAvatarHeader *ToNetPacketAvatarHeader() const;
|
virtual const NetPacketAvatarHeader *ToNetPacketAvatarHeader() const;
|
||||||
virtual const NetPacketAvatarFile *ToNetPacketAvatarFile() const;
|
virtual const NetPacketAvatarFile *ToNetPacketAvatarFile() const;
|
||||||
|
virtual const NetPacketAvatarEnd *ToNetPacketAvatarEnd() const;
|
||||||
virtual const NetPacketGameListNew *ToNetPacketGameListNew() const;
|
virtual const NetPacketGameListNew *ToNetPacketGameListNew() const;
|
||||||
virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const;
|
virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const;
|
||||||
virtual const NetPacketGameListPlayerJoined *ToNetPacketGameListPlayerJoined() const;
|
virtual const NetPacketGameListPlayerJoined *ToNetPacketGameListPlayerJoined() const;
|
||||||
@@ -281,6 +283,29 @@ protected:
|
|||||||
virtual void InternalCheck(const NetPacketHeader* data) const;
|
virtual void InternalCheck(const NetPacketHeader* data) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NetPacketAvatarEnd : public NetPacket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
u_int32_t requestId;
|
||||||
|
};
|
||||||
|
|
||||||
|
NetPacketAvatarEnd();
|
||||||
|
virtual ~NetPacketAvatarEnd();
|
||||||
|
|
||||||
|
virtual boost::shared_ptr<NetPacket> Clone() const;
|
||||||
|
|
||||||
|
void SetData(const Data &inData);
|
||||||
|
void GetData(Data &outData) const;
|
||||||
|
|
||||||
|
virtual const NetPacketAvatarEnd *ToNetPacketAvatarEnd() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void InternalCheck(const NetPacketHeader* data) const;
|
||||||
|
};
|
||||||
|
|
||||||
class NetPacketGameListNew : public NetPacket
|
class NetPacketGameListNew : public NetPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user