From 5d974a6450747d5051047b54c9dfdf98d4c81268 Mon Sep 17 00:00:00 2001 From: lotodore Date: Fri, 5 Oct 2007 14:23:36 +0000 Subject: [PATCH] More preparation towards transferring avatars. --- docs/net_protocol.txt | 11 ++++ src/core/avatarmanager.h | 13 ++++ src/core/common/avatarmanager.cpp | 101 +++++++++++++++++++++++++++++- src/net/common/clientstate.cpp | 7 +++ src/net/common/netpacket.cpp | 72 +++++++++++++++++++++ src/net/netpacket.h | 25 ++++++++ 6 files changed, 228 insertions(+), 1 deletion(-) diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt index 6ff01fb0..5ecad32e 100644 --- a/docs/net_protocol.txt +++ b/docs/net_protocol.txt @@ -136,6 +136,17 @@ Server/Client Reply: Avatar File [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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ diff --git a/src/core/avatarmanager.h b/src/core/avatarmanager.h index 94a6fe2b..9e4d1e67 100644 --- a/src/core/avatarmanager.h +++ b/src/core/avatarmanager.h @@ -24,6 +24,14 @@ #include #include +#include +#include + +#define MAX_AVATAR_FILE_SIZE 30720 + +struct AvatarFileState; +class NetPacket; + class AvatarManager { public: @@ -33,6 +41,11 @@ public: bool Init(const std::string &dataDir, const std::string &cacheDir); + boost::shared_ptr OpenAvatarFileForChunkRead(const std::string &fileName, unsigned &outFileSize); + unsigned ChunkReadAvatarFile(boost::shared_ptr fileState, unsigned char *data, unsigned chunkSize); + + bool SendAvatarFile(const std::string &fileName, unsigned requestId, boost::function)> sender); + bool GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf); bool GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const; bool StoreAvatarInCache(const MD5Buf &md5buf, const std::string &fileExtension, const unsigned char *data, unsigned size); diff --git a/src/core/common/avatarmanager.cpp b/src/core/common/avatarmanager.cpp index c04d3fec..e539ec11 100644 --- a/src/core/common/avatarmanager.cpp +++ b/src/core/common/avatarmanager.cpp @@ -18,6 +18,7 @@ ***************************************************************************/ #include "avatarmanager.h" +#include #include #include @@ -27,6 +28,10 @@ using namespace std; using namespace boost::filesystem; +struct AvatarFileState +{ + ifstream inputStream; +}; AvatarManager::AvatarManager() { @@ -53,6 +58,100 @@ AvatarManager::Init(const std::string &dataDir, const std::string &cacheDir) return retVal; } +boost::shared_ptr +AvatarManager::OpenAvatarFileForChunkRead(const std::string &fileName, unsigned &outFileSize) +{ + outFileSize = 0; + boost::shared_ptr retVal; + try + { + boost::shared_ptr 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 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)> sender) +{ + bool retVal = false; + unsigned fileSize; + boost::shared_ptr tmpState = OpenAvatarFileForChunkRead(fileName, fileSize); + if (tmpState.get() && fileSize) + { + boost::shared_ptr avatarHeader(new NetPacketAvatarHeader); + NetPacketAvatarHeader::Data avatarHeaderData; + avatarHeaderData.requestId = requestId; + avatarHeaderData.avatarFileSize = fileSize; + avatarHeaderData.avatarFileType = AVATAR_TYPE_PNG; // TODO + static_cast(avatarHeader.get())->SetData(avatarHeaderData); + sender(avatarHeader); + + unsigned numBytes = 0; + unsigned totalBytesRead = 0; + do + { + boost::shared_ptr 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(avatarFile.get())->SetData(avatarFileData); + sender(avatarFile); + } + } while (numBytes); + // TODO error handling if numBytes != totalBytesRead + boost::shared_ptr avatarEnd(new NetPacketAvatarEnd); + NetPacketAvatarEnd::Data avatarEndData; + avatarEndData.requestId = requestId; + static_cast(avatarEnd.get())->SetData(avatarEndData); + sender(avatarEnd); + retVal = true; + } + // else TODO error handling + return retVal; +} + bool 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); tmpPath /= (md5buf.ToString() + "." + fileExtension); 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); m_avatars.insert(AvatarMap::value_type(md5buf, fileName)); retVal = true; diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 9b6bc5a7..ce313ac0 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -527,6 +527,13 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr< client.SetSessionEstablished(true); 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; } diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index 99efec2c..5da475af 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -32,6 +32,7 @@ using namespace std; #define NET_TYPE_RETRIEVE_AVATAR 0x0003 #define NET_TYPE_AVATAR_HEADER 0x0004 #define NET_TYPE_AVATAR_FILE 0x0005 +#define NET_TYPE_AVATAR_END 0x0006 #define NET_TYPE_GAME_LIST_NEW 0x0010 #define NET_TYPE_GAME_LIST_UPDATE 0x0011 #define NET_TYPE_GAME_LIST_PLAYER_JOINED 0x0012 @@ -157,6 +158,12 @@ struct GCC_PACKED NetPacketAvatarFileData u_int32_t requestId; }; +struct GCC_PACKED NetPacketAvatarEndData +{ + NetPacketHeader head; + u_int32_t requestId; +}; + struct GCC_PACKED GameInfoData { u_int16_t maxNumberOfPlayers; @@ -587,6 +594,9 @@ NetPacket::Create(char *data, unsigned &dataSize) case NET_TYPE_AVATAR_FILE: tmpPacket = boost::shared_ptr(new NetPacketAvatarFile); break; + case NET_TYPE_AVATAR_END: + tmpPacket = boost::shared_ptr(new NetPacketAvatarEnd); + break; case NET_TYPE_GAME_LIST_NEW: tmpPacket = boost::shared_ptr(new NetPacketGameListNew); break; @@ -800,6 +810,12 @@ NetPacket::ToNetPacketAvatarFile() const return NULL; } +const NetPacketAvatarEnd * +NetPacket::ToNetPacketAvatarEnd() const +{ + return NULL; +} + const NetPacketGameListNew * 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 +NetPacketAvatarEnd::Clone() const +{ + boost::shared_ptr 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() : NetPacket(NET_TYPE_GAME_LIST_NEW, sizeof(NetPacketGameListNewData), MAX_PACKET_SIZE) { diff --git a/src/net/netpacket.h b/src/net/netpacket.h index ecdee382..a0e0e804 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -50,6 +50,7 @@ class NetPacketInitAck; class NetPacketRetrieveAvatar; class NetPacketAvatarHeader; class NetPacketAvatarFile; +class NetPacketAvatarEnd; class NetPacketGameListNew; class NetPacketGameListUpdate; class NetPacketGameListPlayerJoined; @@ -106,6 +107,7 @@ public: virtual const NetPacketRetrieveAvatar *ToNetPacketRetrieveAvatar() const; virtual const NetPacketAvatarHeader *ToNetPacketAvatarHeader() const; virtual const NetPacketAvatarFile *ToNetPacketAvatarFile() const; + virtual const NetPacketAvatarEnd *ToNetPacketAvatarEnd() const; virtual const NetPacketGameListNew *ToNetPacketGameListNew() const; virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const; virtual const NetPacketGameListPlayerJoined *ToNetPacketGameListPlayerJoined() const; @@ -281,6 +283,29 @@ protected: 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 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 { public: