Core/Network: Optimized packet sending by removing unneccessary memory copying

This commit is contained in:
Shauren
2014-07-27 17:46:46 +02:00
parent 8a05231994
commit 6f272ea5b7
18 changed files with 162 additions and 53 deletions
+1 -1
View File
@@ -20,9 +20,9 @@
#define __AUTHSESSION_H__
#include "Common.h"
#include "ByteBuffer.h"
#include "Socket.h"
#include "BigNumber.h"
#include "ByteBuffer.h"
#include <memory>
#include <boost/asio/ip/tcp.hpp>
+1 -1
View File
@@ -636,7 +636,7 @@ void CalendarMgr::SendCalendarCommandResult(uint64 guid, CalendarError err, char
}
}
void CalendarMgr::SendPacketToAllEventRelatives(WorldPacket packet, CalendarEvent const& calendarEvent)
void CalendarMgr::SendPacketToAllEventRelatives(WorldPacket& packet, CalendarEvent const& calendarEvent)
{
// Send packet to all guild members
if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement())
+1 -1
View File
@@ -329,7 +329,7 @@ class CalendarMgr
void SendCalendarClearPendingAction(uint64 guid);
void SendCalendarCommandResult(uint64 guid, CalendarError err, char const* param = NULL);
void SendPacketToAllEventRelatives(WorldPacket packet, CalendarEvent const& calendarEvent);
void SendPacketToAllEventRelatives(WorldPacket& packet, CalendarEvent const& calendarEvent);
};
#define sCalendarMgr CalendarMgr::instance()
+1 -1
View File
@@ -548,7 +548,7 @@ void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) cons
if (iter == data_map.end())
{
std::pair<UpdateDataMapType::iterator, bool> p = data_map.insert(UpdateDataMapType::value_type(player, UpdateData()));
std::pair<UpdateDataMapType::iterator, bool> p = data_map.emplace(player, UpdateData());
ASSERT(p.second);
iter = p.first;
}
@@ -53,6 +53,11 @@ class UpdateData
{
public:
UpdateData();
UpdateData(UpdateData&& right) : m_blockCount(right.m_blockCount),
m_outOfRangeGUIDs(std::move(right.m_outOfRangeGUIDs)),
m_data(std::move(right.m_data))
{
}
void AddOutOfRangeGUID(std::set<uint64>& guids);
void AddOutOfRangeGUID(uint64 guid);
@@ -69,6 +74,9 @@ class UpdateData
ByteBuffer m_data;
void Compress(void* dst, uint32 *dst_size, void* src, int src_size);
UpdateData(UpdateData const& right) = delete;
UpdateData& operator=(UpdateData const& right) = delete;
};
#endif
+5 -1
View File
@@ -2223,7 +2223,11 @@ void Unit::SendMeleeAttackStop(Unit* victim)
{
WorldPacket data(SMSG_ATTACKSTOP, (8+8+4));
data.append(GetPackGUID());
data.append(victim ? victim->GetPackGUID() : 0);
if (victim)
data.append(victim->GetPackGUID());
else
data << uint8(0);
data << uint32(0); //! Can also take the value 0x01, which seems related to updating rotation
SendMessageToSet(&data, true);
TC_LOG_DEBUG("entities.unit", "WORLD: Sent SMSG_ATTACKSTOP");
+5 -1
View File
@@ -93,7 +93,11 @@ void WorldSession::SendAttackStop(Unit const* enemy)
{
WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); // we guess size
data.append(GetPlayer()->GetPackGUID());
data.append(enemy ? enemy->GetPackGUID() : 0); // must be packed guid
if (enemy)
data.append(enemy->GetPackGUID());
else
data << uint8(0);
data << uint32(0); // unk, can be 1 also
SendPacket(&data);
}
+1 -1
View File
@@ -2682,7 +2682,7 @@ uint32 Map::GetPlayersCountExceptGMs() const
return count;
}
void Map::SendToPlayers(WorldPacket const* data) const
void Map::SendToPlayers(WorldPacket* data) const
{
for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
itr->GetSource()->GetSession()->SendPacket(data);
+1 -1
View File
@@ -423,7 +423,7 @@ class Map : public GridRefManager<NGridType>
void AddWorldObject(WorldObject* obj) { i_worldObjects.insert(obj); }
void RemoveWorldObject(WorldObject* obj) { i_worldObjects.erase(obj); }
void SendToPlayers(WorldPacket const* data) const;
void SendToPlayers(WorldPacket* data) const;
typedef MapRefManager PlayerList;
PlayerList const& GetPlayers() const { return m_mapRefManager; }
+18 -6
View File
@@ -414,25 +414,37 @@ void ScriptMgr::OnSocketClose(std::shared_ptr<WorldSocket> socket, bool wasNew)
FOREACH_SCRIPT(ServerScript)->OnSocketClose(socket, wasNew);
}
void ScriptMgr::OnPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet)
void ScriptMgr::OnPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket const& packet)
{
ASSERT(socket);
FOREACH_SCRIPT(ServerScript)->OnPacketReceive(socket, packet);
if (SCR_REG_LST(ServerScript).empty())
return;
WorldPacket copy(packet);
FOREACH_SCRIPT(ServerScript)->OnPacketReceive(socket, copy);
}
void ScriptMgr::OnPacketSend(std::shared_ptr<WorldSocket> socket, WorldPacket packet)
void ScriptMgr::OnPacketSend(std::shared_ptr<WorldSocket> socket, WorldPacket const& packet)
{
ASSERT(socket);
FOREACH_SCRIPT(ServerScript)->OnPacketSend(socket, packet);
if (SCR_REG_LST(ServerScript).empty())
return;
WorldPacket copy(packet);
FOREACH_SCRIPT(ServerScript)->OnPacketSend(socket, copy);
}
void ScriptMgr::OnUnknownPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet)
void ScriptMgr::OnUnknownPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket const& packet)
{
ASSERT(socket);
FOREACH_SCRIPT(ServerScript)->OnUnknownPacketReceive(socket, packet);
if (SCR_REG_LST(ServerScript).empty())
return;
WorldPacket copy(packet);
FOREACH_SCRIPT(ServerScript)->OnUnknownPacketReceive(socket, copy);
}
void ScriptMgr::OnOpenStateChange(bool open)
+3 -3
View File
@@ -910,9 +910,9 @@ class ScriptMgr
void OnNetworkStop();
void OnSocketOpen(std::shared_ptr<WorldSocket> socket);
void OnSocketClose(std::shared_ptr<WorldSocket> socket, bool wasNew);
void OnPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet);
void OnPacketSend(std::shared_ptr<WorldSocket> socket, WorldPacket packet);
void OnUnknownPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet);
void OnPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket const& packet);
void OnPacketSend(std::shared_ptr<WorldSocket> socket, WorldPacket const& packet);
void OnUnknownPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket const& packet);
public: /* WorldScript */
+6 -6
View File
@@ -186,7 +186,7 @@ uint32 WorldSession::GetGuidLow() const
}
/// Send a packet to the client
void WorldSession::SendPacket(WorldPacket const* packet)
void WorldSession::SendPacket(WorldPacket* packet)
{
if (!m_Socket)
return;
@@ -288,7 +288,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
{
TC_LOG_ERROR("network.opcode", "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
, GetPlayerInfo().c_str());
sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet));
sScriptMgr->OnUnknownPacketReceive(m_Socket, *packet);
}
else
{
@@ -318,7 +318,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
}
else if (_player->IsInWorld())
{
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
sScriptMgr->OnPacketReceive(m_Socket, *packet);
(this->*opHandle.handler)(*packet);
LogUnprocessedTail(packet);
}
@@ -331,7 +331,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
else
{
// not expected _player or must checked in packet handler
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
sScriptMgr->OnPacketReceive(m_Socket, *packet);
(this->*opHandle.handler)(*packet);
LogUnprocessedTail(packet);
}
@@ -343,7 +343,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world");
else
{
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
sScriptMgr->OnPacketReceive(m_Socket, *packet);
(this->*opHandle.handler)(*packet);
LogUnprocessedTail(packet);
}
@@ -361,7 +361,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
if (packet->GetOpcode() == CMSG_CHAR_ENUM)
m_playerRecentlyLogout = false;
sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
sScriptMgr->OnPacketReceive(m_Socket, *packet);
(this->*opHandle.handler)(*packet);
LogUnprocessedTail(packet);
break;
+2 -2
View File
@@ -178,7 +178,7 @@ class CharacterCreateInfo
protected:
CharacterCreateInfo(std::string const& name, uint8 race, uint8 cclass, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId,
WorldPacket& data) : Name(name), Race(race), Class(cclass), Gender(gender), Skin(skin), Face(face), HairStyle(hairStyle), HairColor(hairColor), FacialHair(facialHair),
OutfitId(outfitId), Data(data), CharCount(0)
OutfitId(outfitId), Data(std::move(data)), CharCount(0)
{ }
/// User specified variables
@@ -222,7 +222,7 @@ class WorldSession
void ReadMovementInfo(WorldPacket& data, MovementInfo* mi);
void WriteMovementInfo(WorldPacket* data, MovementInfo* mi);
void SendPacket(WorldPacket const* packet);
void SendPacket(WorldPacket* packet);
void SendNotification(const char *format, ...) ATTR_PRINTF(2, 3);
void SendNotification(uint32 string_id, ...);
void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName);
+3 -10
View File
@@ -18,7 +18,6 @@
#include <memory>
#include "WorldSocket.h"
#include "ServerPktHeader.h"
#include "BigNumber.h"
#include "Opcodes.h"
#include "ScriptMgr.h"
@@ -140,7 +139,7 @@ void WorldSocket::ReadDataHandler(boost::system::error_code error, size_t transf
CloseSocket();
}
void WorldSocket::AsyncWrite(WorldPacket const& packet)
void WorldSocket::AsyncWrite(WorldPacket& packet)
{
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, SERVER_TO_CLIENT);
@@ -149,18 +148,12 @@ void WorldSocket::AsyncWrite(WorldPacket const& packet)
ServerPktHeader header(packet.size() + 2, packet.GetOpcode());
std::vector<uint8> data(header.getHeaderLength() + packet.size());
std::memcpy(data.data(), header.header, header.getHeaderLength());
if (!packet.empty())
std::memcpy(&data[header.getHeaderLength()], packet.contents(), packet.size());
std::lock_guard<std::mutex> guard(_writeLock);
bool needsWriteStart = _writeQueue.empty();
_authCrypt.EncryptSend(data.data(), header.getHeaderLength());
_authCrypt.EncryptSend(header.header, header.getHeaderLength());
_writeQueue.push(std::move(data));
_writeQueue.emplace(header, std::move(packet));
if (needsWriteStart)
AsyncWrite(_writeQueue.front());
+55 -3
View File
@@ -19,14 +19,26 @@
#ifndef __WORLDSOCKET_H__
#define __WORLDSOCKET_H__
// Forward declare buffer function here - Socket.h must know about it
struct WorldPacketBuffer;
namespace boost
{
namespace asio
{
WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf);
}
}
#include "Common.h"
#include "AuthCrypt.h"
#include "ServerPktHeader.h"
#include "Socket.h"
#include "Util.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include <chrono>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/buffer.hpp>
using boost::asio::ip::tcp;
@@ -40,9 +52,49 @@ struct ClientPktHeader
#pragma pack(pop)
class WorldSocket : public Socket<WorldSocket, std::vector<uint8> >
struct WorldPacketBuffer
{
typedef Socket<WorldSocket, std::vector<uint8> > Base;
typedef boost::asio::const_buffer value_type;
typedef boost::asio::const_buffer const* const_iterator;
WorldPacketBuffer(ServerPktHeader header, WorldPacket&& packet) : _header(header), _packet(std::move(packet))
{
_buffers[0] = boost::asio::const_buffer(_header.header, _header.getHeaderLength());
if (!_packet.empty())
_buffers[1] = boost::asio::const_buffer(_packet.contents(), _packet.size());
}
const_iterator begin() const
{
return _buffers;
}
const_iterator end() const
{
return _buffers + (_packet.empty() ? 1 : 2);
}
private:
boost::asio::const_buffer _buffers[2];
ServerPktHeader _header;
WorldPacket _packet;
};
namespace boost
{
namespace asio
{
inline WorldPacketBuffer const& buffer(WorldPacketBuffer const& buf)
{
return buf;
}
}
}
class WorldSocket : public Socket<WorldSocket, WorldPacketBuffer>
{
typedef Socket<WorldSocket, WorldPacketBuffer> Base;
public:
WorldSocket(tcp::socket&& socket);
@@ -53,7 +105,7 @@ public:
void Start() override;
using Base::AsyncWrite;
void AsyncWrite(WorldPacket const& packet);
void AsyncWrite(WorldPacket& packet);
protected:
void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) override;
+23 -7
View File
@@ -81,12 +81,28 @@ class ByteBuffer
_storage.reserve(reserve);
}
// copy constructor
ByteBuffer(const ByteBuffer &buf) : _rpos(buf._rpos), _wpos(buf._wpos),
_storage(buf._storage)
ByteBuffer(ByteBuffer&& buf) : _rpos(buf._rpos), _wpos(buf._wpos),
_storage(std::move(buf._storage))
{
}
ByteBuffer(ByteBuffer const& right) : _rpos(right._rpos), _wpos(right._wpos),
_storage(right._storage)
{
}
ByteBuffer& operator=(ByteBuffer const& right)
{
if (this != &right)
{
_rpos = right._rpos;
_wpos = right._wpos;
_storage = right._storage;
}
return *this;
}
virtual ~ByteBuffer() { }
void clear()
@@ -383,18 +399,18 @@ class ByteBuffer
return *this;
}
uint8 * contents()
uint8* contents()
{
if (_storage.empty())
throw ByteBufferException();
return &_storage[0];
return _storage.data();
}
const uint8 *contents() const
uint8 const* contents() const
{
if (_storage.empty())
throw ByteBufferException();
return &_storage[0];
return _storage.data();
}
size_t size() const { return _storage.size(); }
+19 -3
View File
@@ -29,12 +29,28 @@ class WorldPacket : public ByteBuffer
WorldPacket() : ByteBuffer(0), m_opcode(0)
{
}
explicit WorldPacket(uint16 opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { }
// copy constructor
WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode)
WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode)
{
}
WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode)
{
}
WorldPacket& operator=(WorldPacket const& right)
{
if (this != &right)
{
m_opcode = right.m_opcode;
ByteBuffer::operator =(right);
}
return *this;
}
void Initialize(uint16 opcode, size_t newres=200)
{
clear();
@@ -48,5 +64,5 @@ class WorldPacket : public ByteBuffer
protected:
uint16 m_opcode;
};
#endif
#endif
@@ -22,12 +22,11 @@
#include <mutex>
#include <queue>
#include <atomic>
#include <type_traits>
template <typename T>
class ProducerConsumerQueue
{
static_assert(std::is_pointer<T>::value, "T for ProducerConsumerQueue must be a pointer");
private:
std::mutex _queueLock;
std::queue<T> _queue;
@@ -94,7 +93,7 @@ public:
{
T& value = _queue.front();
delete value;
DeleteQueuedObject(value);
_queue.pop();
}
@@ -105,8 +104,13 @@ public:
_condition.notify_all();
}
private:
template<typename E = T>
typename std::enable_if<std::is_pointer<E>::value>::type DeleteQueuedObject(E& obj) { delete obj; }
template<typename E = T>
typename std::enable_if<!std::is_pointer<E>::value>::type DeleteQueuedObject(E const& /*packet*/) { }
};
#endif