mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-23 23:20:09 -04:00
Core/Network: Optimized packet sending by removing unneccessary memory copying
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user