Core/Packets: Port packet handling rework from 335 branch

This commit is contained in:
Ovahlord
2019-05-30 16:59:37 +02:00
parent 5501502a03
commit dfbf50234d
21 changed files with 1867 additions and 1497 deletions

View File

@@ -28114,10 +28114,10 @@ bool Player::CanUseMastery() const
void Player::ReadMovementInfo(WorldPacket& data, MovementInfo* mi, Movement::ExtraMovementStatusElement* extras /*= nullptr*/)
{
MovementStatusElements const* sequence = GetMovementStatusElementsSequence(data.GetOpcode());
MovementStatusElements const* sequence = GetMovementStatusElementsSequence(static_cast<OpcodeClient>(data.GetOpcode()));
if (!sequence)
{
TC_LOG_ERROR("network", "Player::ReadMovementInfo: No movement sequence found for opcode %s", GetOpcodeNameForLogging(data.GetOpcode()).c_str());
TC_LOG_ERROR("network", "Player::ReadMovementInfo: No movement sequence found for opcode %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(data.GetOpcode())).c_str());
return;
}

View File

@@ -13647,10 +13647,10 @@ void Unit::WriteMovementInfo(WorldPacket& data, Movement::ExtraMovementStatusEle
bool hasFallData = hasFallDirection || m_movementInfo.jump.fallTime != 0;
bool hasSplineElevation = HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION);
MovementStatusElements const* sequence = GetMovementStatusElementsSequence(data.GetOpcode());
MovementStatusElements const* sequence = GetMovementStatusElementsSequence(static_cast<OpcodeClient>(data.GetOpcode()));
if (!sequence)
{
TC_LOG_ERROR("network", "Unit::WriteMovementInfo: No movement sequence found for opcode %s", GetOpcodeNameForLogging(data.GetOpcode()).c_str());
TC_LOG_ERROR("network", "Unit::WriteMovementInfo: No movement sequence found for opcode %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(data.GetOpcode())).c_str());
return;
}

View File

@@ -575,8 +575,6 @@ void Trinity::LocalizedPacketDo<Builder>::operator()(Player* p)
i_builder(*data, loc_idx);
ASSERT(data->GetOpcode() != NULL_OPCODE);
i_data_cache[cache_idx] = data;
}
else

View File

@@ -41,10 +41,10 @@
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/)
{
TC_LOG_DEBUG("network", "WORLD: got MSG_MOVE_WORLDPORT_ACK.");
HandleMoveWorldportAckOpcode();
HandleMoveWorldportAck();
}
void WorldSession::HandleMoveWorldportAckOpcode()
void WorldSession::HandleMoveWorldportAck()
{
// ignore unexpected far teleports
if (!GetPlayer()->IsBeingTeleportedFar())

View File

@@ -5500,7 +5500,7 @@ bool Movement::PrintInvalidSequenceElement(MovementStatusElements const element,
return false;
}
Movement::PacketSender::PacketSender(Unit* unit, Opcodes serverControl, Opcodes playerControl, Opcodes broadcast /*= SMSG_PLAYER_MOVE*/, ExtraMovementStatusElement* extras /*= nullptr*/)
Movement::PacketSender::PacketSender(Unit* unit, uint16 serverControl, uint16 playerControl, uint16 broadcast /*= SMSG_PLAYER_MOVE*/, ExtraMovementStatusElement* extras /*= nullptr*/)
: _extraElements(extras), _unit(unit)
{
if (unit->GetTypeId() == TYPEID_PLAYER && unit->ToPlayer()->m_unitMovedByMe->GetTypeId() == TYPEID_PLAYER)

View File

@@ -139,15 +139,15 @@ namespace Movement
class PacketSender
{
public:
PacketSender(Unit* unit, Opcodes serverControl, Opcodes playerControl, Opcodes broadcast = SMSG_PLAYER_MOVE, ExtraMovementStatusElement* extras = nullptr);
PacketSender(Unit* unit, uint16 serverControl, uint16 playerControl, uint16 broadcast = SMSG_PLAYER_MOVE, ExtraMovementStatusElement* extras = nullptr);
void Send() const;
private:
ExtraMovementStatusElement* _extraElements;
Unit* _unit;
Opcodes _selfOpcode;
Opcodes _broadcast;
uint16 _selfOpcode;
uint16 _broadcast;
};
bool PrintInvalidSequenceElement(MovementStatusElements element, char const* function);

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Packet.h"
#include "Errors.h"
WorldPackets::Packet::Packet(WorldPacket&& worldPacket) : _worldPacket(std::move(worldPacket))
{
}
WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize /*= 200*/) : Packet(WorldPacket(opcode, initialSize))
{
}
void WorldPackets::ServerPacket::Read()
{
ASSERT(!"Read not implemented for server packets.");
}
WorldPackets::ClientPacket::ClientPacket(OpcodeClient expectedOpcode, WorldPacket&& packet) : Packet(std::move(packet))
{
ASSERT(GetOpcode() == expectedOpcode);
}
WorldPackets::ClientPacket::ClientPacket(WorldPacket&& packet)
: Packet(std::move(packet))
{
}
WorldPacket const* WorldPackets::ClientPacket::Write()
{
ASSERT(!"Write not allowed for client packets.");
// Shut up some compilers
return nullptr;
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PacketBaseWorld_h__
#define PacketBaseWorld_h__
#include "WorldPacket.h"
namespace WorldPackets
{
class TC_GAME_API Packet
{
public:
Packet(WorldPacket&& worldPacket);
virtual ~Packet() = default;
Packet(Packet const& right) = delete;
Packet& operator=(Packet const& right) = delete;
virtual WorldPacket const* Write() = 0;
virtual void Read() = 0;
WorldPacket const* GetRawPacket() const { return &_worldPacket; }
size_t GetSize() const { return _worldPacket.size(); }
protected:
WorldPacket _worldPacket;
};
class TC_GAME_API ServerPacket : public Packet
{
public:
ServerPacket(OpcodeServer opcode, size_t initialSize = 200);
void Read() override final;
void Clear() { _worldPacket.clear(); }
WorldPacket&& Move() { return std::move(_worldPacket); }
void ShrinkToFit() { _worldPacket.shrink_to_fit(); }
OpcodeServer GetOpcode() const { return OpcodeServer(_worldPacket.GetOpcode()); }
};
class TC_GAME_API ClientPacket : public Packet
{
public:
ClientPacket(WorldPacket&& packet);
ClientPacket(OpcodeClient expectedOpcode, WorldPacket&& packet);
WorldPacket const* Write() override final;
OpcodeClient GetOpcode() const { return OpcodeClient(_worldPacket.GetOpcode()); }
};
}
#endif // PacketBaseWorld_h__

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AllPackets_h__
#define AllPackets_h__
#endif // AllPackets_h__

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PacketUtilities.h"
#include "Errors.h"
#include <sstream>
#include <array>
WorldPackets::PacketArrayMaxCapacityException::PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit)
{
std::ostringstream builder;
builder << "Attempted to read more array elements from packet " << requestedSize << " than allowed " << sizeLimit;
message().assign(builder.str());
}
void WorldPackets::CheckCompactArrayMaskOverflow(std::size_t index, std::size_t limit)
{
ASSERT(index < limit, "Attempted to insert " SZFMTD " values into CompactArray but it can only hold " SZFMTD, index, limit);
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PacketUtilities_h__
#define PacketUtilities_h__
#include "ByteBuffer.h"
namespace WorldPackets
{
class PacketArrayMaxCapacityException : public ByteBufferException
{
public:
PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit);
};
/**
* Utility class for automated prevention of loop counter spoofing in client packets
*/
template<typename T, std::size_t N = 1000 /*select a sane default limit*/>
class Array
{
typedef std::vector<T> storage_type;
typedef typename storage_type::value_type value_type;
typedef typename storage_type::size_type size_type;
typedef typename storage_type::reference reference;
typedef typename storage_type::const_reference const_reference;
typedef typename storage_type::iterator iterator;
typedef typename storage_type::const_iterator const_iterator;
public:
Array() : _limit(N) { }
Array(size_type limit) : _limit(limit) { }
iterator begin() { return _storage.begin(); }
const_iterator begin() const { return _storage.begin(); }
iterator end() { return _storage.end(); }
const_iterator end() const { return _storage.end(); }
size_type size() const { return _storage.size(); }
bool empty() const { return _storage.empty(); }
reference operator[](size_type i) { return _storage[i]; }
const_reference operator[](size_type i) const { return _storage[i]; }
void resize(size_type newSize)
{
if (newSize > _limit)
throw PacketArrayMaxCapacityException(newSize, _limit);
_storage.resize(newSize);
}
void reserve(size_type newSize)
{
if (newSize > _limit)
throw PacketArrayMaxCapacityException(newSize, _limit);
_storage.reserve(newSize);
}
void push_back(value_type const& value)
{
if (_storage.size() >= _limit)
throw PacketArrayMaxCapacityException(_storage.size() + 1, _limit);
_storage.push_back(value);
}
void push_back(value_type&& value)
{
if (_storage.size() >= _limit)
throw PacketArrayMaxCapacityException(_storage.size() + 1, _limit);
_storage.push_back(std::forward<value_type>(value));
}
private:
storage_type _storage;
size_type _limit;
};
void CheckCompactArrayMaskOverflow(std::size_t index, std::size_t limit);
template <typename T>
class CompactArray
{
public:
CompactArray() : _mask(0) { }
CompactArray(CompactArray const& right)
: _mask(right._mask), _contents(right._contents) { }
CompactArray(CompactArray&& right)
: _mask(right._mask), _contents(std::move(right._contents))
{
right._mask = 0;
}
CompactArray& operator=(CompactArray const& right)
{
_mask = right._mask;
_contents = right._contents;
return *this;
}
CompactArray& operator=(CompactArray&& right)
{
_mask = right._mask;
right._mask = 0;
_contents = std::move(right._contents);
return *this;
}
uint32 GetMask() const { return _mask; }
T const& operator[](std::size_t index) const { return _contents.at(index); }
std::size_t GetSize() const { return _contents.size(); }
void Insert(std::size_t index, T const& value)
{
CheckCompactArrayMaskOverflow(index, sizeof(_mask) * 8);
_mask |= 1 << index;
if (_contents.size() <= index)
_contents.resize(index + 1);
_contents[index] = value;
}
void Clear()
{
_mask = 0;
_contents.clear();
}
bool operator==(CompactArray const& r) const
{
if (_mask != r._mask)
return false;
return _contents == r._contents;
}
bool operator!=(CompactArray const& r) const { return !(*this == r); }
private:
uint32 _mask;
std::vector<T> _contents;
};
template <typename T>
ByteBuffer& operator<<(ByteBuffer& data, CompactArray<T> const& v)
{
uint32 mask = v.GetMask();
data << uint32(mask);
for (std::size_t i = 0; i < v.GetSize(); ++i)
if (mask & (1 << i))
data << v[i];
return data;
}
template <typename T>
ByteBuffer& operator>>(ByteBuffer& data, CompactArray<T>& v)
{
uint32 mask;
data >> mask;
for (std::size_t index = 0; mask != 0; mask >>= 1, ++index)
if ((mask & 1) != 0)
v.Insert(index, data.read<T>());
return data;
}
}
#endif // PacketUtilities_h__

File diff suppressed because it is too large Load Diff

View File

@@ -26,14 +26,8 @@
#include "Define.h"
#include <string>
/// List of Opcodes
enum Opcodes
enum Opcodes : uint16
{
NUM_OPCODE_HANDLERS = (0x7FFF+1),
UNKNOWN_OPCODE = (0xFFFF+1),
NULL_OPCODE = 0,
COMPRESSED_OPCODE_MASK = 0x8000,
CMSG_ACCEPT_LEVEL_GRANT = 0x0205,
CMSG_ACCEPT_TRADE = 0x7110,
CMSG_ACTIVATETAXI = 0x6E06,
@@ -1384,6 +1378,15 @@ enum Opcodes
SMSG_ZONE_UNDER_ATTACK = 0x0A06,
};
enum OpcodeMisc : uint16
{
NUM_OPCODE_HANDLERS = (0x7FFF + 1),
NULL_OPCODE = 0x0000
};
typedef Opcodes OpcodeClient;
typedef Opcodes OpcodeServer;
/// Player state
enum SessionStatus
{
@@ -1403,51 +1406,66 @@ enum PacketProcessing
};
class WorldSession;
class WorldPacket;
class WorldSession;
typedef void(WorldSession::*pOpcodeHandler)(WorldPacket& recvPacket);
struct OpcodeHandler
class OpcodeHandler
{
OpcodeHandler() { }
OpcodeHandler(char const* _name, SessionStatus _status, PacketProcessing _processing, pOpcodeHandler _handler)
: Handler(_handler), Name(_name), Status(_status), ProcessingPlace(_processing) {}
public:
OpcodeHandler(char const* name, SessionStatus status) : Name(name), Status(status) { }
virtual ~OpcodeHandler() { }
pOpcodeHandler Handler;
char const* Name;
SessionStatus Status;
};
class ClientOpcodeHandler : public OpcodeHandler
{
public:
ClientOpcodeHandler(char const* name, SessionStatus status, PacketProcessing processing)
: OpcodeHandler(name, status), ProcessingPlace(processing) { }
virtual void Call(WorldSession* session, WorldPacket& packet) const = 0;
PacketProcessing ProcessingPlace;
};
class ServerOpcodeHandler : public OpcodeHandler
{
public:
ServerOpcodeHandler(char const* name, SessionStatus status)
: OpcodeHandler(name, status) { }
};
class OpcodeTable
{
public:
OpcodeTable();
~OpcodeTable();
public:
OpcodeTable();
void Initialize();
OpcodeTable(OpcodeTable const&) = delete;
OpcodeTable& operator=(OpcodeTable const&) = delete;
OpcodeHandler const* operator[](uint32 index) const
{
return _internalTable[index];
}
~OpcodeTable();
private:
template<bool isInValidRange, bool isNonZero>
void ValidateAndSetOpcode(uint16 opcode, char const* name, SessionStatus status, PacketProcessing processing, pOpcodeHandler handler);
void Initialize();
// Prevent copying this structure
OpcodeTable(OpcodeTable const&) = delete;
OpcodeTable& operator=(OpcodeTable const&) = delete;
ClientOpcodeHandler const* operator[](Opcodes index) const
{
return _internalTableClient[index];
}
OpcodeHandler* _internalTable[NUM_OPCODE_HANDLERS];
private:
template<typename Handler, Handler HandlerFunction>
void ValidateAndSetClientOpcode(OpcodeClient opcode, char const* name, SessionStatus status, PacketProcessing processing);
void ValidateAndSetServerOpcode(OpcodeServer opcode, char const* name, SessionStatus status);
ClientOpcodeHandler* _internalTableClient[NUM_OPCODE_HANDLERS];
};
extern OpcodeTable opcodeTable;
/// Lookup opcode name for human understandable logging
std::string GetOpcodeNameForLogging(uint32 id);
std::string GetOpcodeNameForLogging(Opcodes opcode);
#endif
/// @}

View File

@@ -1,108 +0,0 @@
/*
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldPacket.h"
#include "Errors.h"
#include "Log.h"
#include "World.h"
#include <zlib.h>
//! Compresses packet in place
void WorldPacket::Compress(z_stream* compressionStream)
{
Opcodes uncompressedOpcode = GetOpcode();
if (uncompressedOpcode & COMPRESSED_OPCODE_MASK)
{
TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode);
return;
}
Opcodes opcode = Opcodes(uncompressedOpcode | COMPRESSED_OPCODE_MASK);
uint32 size = wpos();
uint32 destsize = compressBound(size);
std::vector<uint8> storage(destsize);
_compressionStream = compressionStream;
Compress(static_cast<void*>(&storage[0]), &destsize, static_cast<const void*>(contents()), size);
if (destsize == 0)
return;
clear();
reserve(destsize + sizeof(uint32));
*this << uint32(size);
append(&storage[0], destsize);
SetOpcode(opcode);
TC_LOG_INFO("network", "%s (len %u) successfully compressed to %04X (len %u)", GetOpcodeNameForLogging(uncompressedOpcode).c_str(), size, opcode, destsize);
}
//! Compresses another packet and stores it in self (source left intact)
void WorldPacket::Compress(z_stream* compressionStream, WorldPacket const* source)
{
ASSERT(source != this);
Opcodes uncompressedOpcode = source->GetOpcode();
if (uncompressedOpcode & COMPRESSED_OPCODE_MASK)
{
TC_LOG_ERROR("network", "Packet with opcode 0x%04X is already compressed!", uncompressedOpcode);
return;
}
Opcodes opcode = Opcodes(uncompressedOpcode | COMPRESSED_OPCODE_MASK);
uint32 size = source->size();
uint32 destsize = compressBound(size);
size_t sizePos = 0;
resize(destsize + sizeof(uint32));
_compressionStream = compressionStream;
Compress(static_cast<void*>(&_storage[0] + sizeof(uint32)), &destsize, static_cast<const void*>(source->contents()), size);
if (destsize == 0)
return;
put<uint32>(sizePos, size);
resize(destsize + sizeof(uint32));
SetOpcode(opcode);
TC_LOG_INFO("network", "%s (len %u) successfully compressed to %04X (len %u)", GetOpcodeNameForLogging(uncompressedOpcode).c_str(), size, opcode, destsize);
}
void WorldPacket::Compress(void* dst, uint32 *dst_size, const void* src, int src_size)
{
_compressionStream->next_out = (Bytef*)dst;
_compressionStream->avail_out = *dst_size;
_compressionStream->next_in = (Bytef*)src;
_compressionStream->avail_in = (uInt)src_size;
int32 z_res = deflate(_compressionStream, Z_SYNC_FLUSH);
if (z_res != Z_OK)
{
TC_LOG_ERROR("network", "Can't compress packet (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg);
*dst_size = 0;
return;
}
if (_compressionStream->avail_in != 0)
{
TC_LOG_ERROR("network", "Can't compress packet (zlib: deflate not greedy)");
*dst_size = 0;
return;
}
*dst_size -= _compressionStream->avail_out;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
@@ -24,17 +24,16 @@
#include "ByteBuffer.h"
#include <chrono>
struct z_stream_s;
class WorldPacket : public ByteBuffer
{
public:
// just container for later use
WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE)
WorldPacket() : ByteBuffer(0), m_opcode(NULL_OPCODE)
{
}
explicit WorldPacket(Opcodes opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { }
WorldPacket(uint16 opcode, size_t res = 200) : ByteBuffer(res),
m_opcode(opcode) { }
WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode)
{
@@ -53,33 +52,39 @@ class WorldPacket : public ByteBuffer
if (this != &right)
{
m_opcode = right.m_opcode;
ByteBuffer::operator =(right);
ByteBuffer::operator=(right);
}
return *this;
}
WorldPacket(Opcodes opcode, MessageBuffer&& buffer) : ByteBuffer(std::move(buffer)), m_opcode(opcode) { }
WorldPacket& operator=(WorldPacket&& right)
{
if (this != &right)
{
m_opcode = right.m_opcode;
ByteBuffer::operator=(std::move(right));
}
void Initialize(Opcodes opcode, size_t newres=200)
return *this;
}
WorldPacket(uint16 opcode, MessageBuffer&& buffer) : ByteBuffer(std::move(buffer)), m_opcode(opcode) { }
void Initialize(uint16 opcode, size_t newres = 200)
{
clear();
_storage.reserve(newres);
m_opcode = opcode;
}
Opcodes GetOpcode() const { return m_opcode; }
void SetOpcode(Opcodes opcode) { m_opcode = opcode; }
bool IsCompressed() const { return (m_opcode & COMPRESSED_OPCODE_MASK) != 0; }
void Compress(z_stream_s* compressionStream);
void Compress(z_stream_s* compressionStream, WorldPacket const* source);
uint16 GetOpcode() const { return m_opcode; }
void SetOpcode(uint16 opcode) { m_opcode = opcode; }
std::chrono::steady_clock::time_point GetReceivedTime() const { return m_receivedTime; }
protected:
Opcodes m_opcode;
void Compress(void* dst, uint32 *dst_size, const void* src, int src_size);
z_stream_s* _compressionStream;
uint16 m_opcode;
std::chrono::steady_clock::time_point m_receivedTime; // only set for a specific set of opcodes, for performance reasons.
};

View File

@@ -38,6 +38,7 @@
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "OutdoorPvPMgr.h"
#include "PacketUtilities.h"
#include "Player.h"
#include "QueryCallback.h"
#include "QueryHolder.h"
@@ -61,7 +62,7 @@ std::string const DefaultPlayerName = "<none>";
bool MapSessionFilter::Process(WorldPacket* packet)
{
OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()];
ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())];
//let's check if our opcode can be really processed in Map::Update()
if (opHandle->ProcessingPlace == PROCESS_INPLACE)
@@ -83,7 +84,8 @@ bool MapSessionFilter::Process(WorldPacket* packet)
//OR packet handler is not thread-safe!
bool WorldSessionFilter::Process(WorldPacket* packet)
{
OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()];
ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())];
//check if packet handler is supposed to be safe
if (opHandle->ProcessingPlace == PROCESS_INPLACE)
return true;
@@ -220,23 +222,17 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/
if (!m_Socket)
return;
if (packet->GetOpcode() == NULL_OPCODE)
{
TC_LOG_ERROR("network.opcode", "Prevented sending of NULL_OPCODE to %s", GetPlayerInfo().c_str());
ASSERT(packet->GetOpcode() != NULL_OPCODE);
if (!m_Socket)
return;
}
else if (packet->GetOpcode() == UNKNOWN_OPCODE)
{
TC_LOG_ERROR("network.opcode", "Prevented sending of UNKNOWN_OPCODE to %s", GetPlayerInfo().c_str());
return;
}
if (!forced)
{
OpcodeHandler const* handler = opcodeTable[packet->GetOpcode()];
OpcodeHandler const* handler = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())];
if (!handler || handler->Status == STATUS_UNHANDLED)
{
TC_LOG_ERROR("network.opcode", "Prevented sending disabled opcode %s to %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str(), GetPlayerInfo().c_str());
TC_LOG_ERROR("network.opcode", "Prevented sending disabled opcode %s to %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
return;
}
}
@@ -277,7 +273,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/
sScriptMgr->OnPacketSend(this, *packet);
TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetPlayerInfo().c_str(), GetOpcodeNameForLogging(packet->GetOpcode()).c_str());
TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetPlayerInfo().c_str(), GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str());
m_Socket->SendPacket(*packet);
}
@@ -291,7 +287,7 @@ void WorldSession::QueuePacket(WorldPacket* new_packet)
void WorldSession::LogUnexpectedOpcode(WorldPacket* packet, char const* status, const char *reason)
{
TC_LOG_ERROR("network.opcode", "Received unexpected opcode %s Status: %s Reason: %s from %s",
GetOpcodeNameForLogging(packet->GetOpcode()).c_str(), status, reason, GetPlayerInfo().c_str());
GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), status, reason, GetPlayerInfo().c_str());
}
/// Logging helper for unexpected opcodes
@@ -301,7 +297,7 @@ void WorldSession::LogUnprocessedTail(WorldPacket* packet)
return;
TC_LOG_TRACE("network.opcode", "Unprocessed tail data (read stop at %u from %u) Opcode %s from %s",
uint32(packet->rpos()), uint32(packet->wpos()), GetOpcodeNameForLogging(packet->GetOpcode()).c_str(), GetPlayerInfo().c_str());
uint32(packet->rpos()), uint32(packet->wpos()), GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
packet->print_storage();
}
@@ -327,7 +323,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
while (m_Socket && _recvQueue.next(packet, updater))
{
OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()];
ClientOpcodeHandler const* opHandle = opcodeTable[static_cast<OpcodeClient>(packet->GetOpcode())];
try
{
switch (opHandle->Status)
@@ -343,13 +339,13 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
requeuePackets.push_back(packet);
deletePacket = false;
TC_LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
"Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str());
"Player is currently not in world yet.", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str());
}
}
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
{
sScriptMgr->OnPacketReceive(this, *packet);
(this->*opHandle->Handler)(*packet);
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
@@ -362,7 +358,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
{
// not expected _player or must checked in packet hanlder
sScriptMgr->OnPacketReceive(this, *packet);
(this->*opHandle->Handler)(*packet);
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
}
break;
@@ -374,7 +370,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
else if(AntiDOS.EvaluateOpcode(*packet, currentTime))
{
sScriptMgr->OnPacketReceive(this, *packet);
(this->*opHandle->Handler)(*packet);
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
}
break;
@@ -394,20 +390,25 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
{
sScriptMgr->OnPacketReceive(this, *packet);
(this->*opHandle->Handler)(*packet);
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
}
break;
case STATUS_NEVER:
TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
TC_LOG_ERROR("network.opcode", "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str()
, GetPlayerInfo().c_str());
break;
case STATUS_UNHANDLED:
TC_LOG_ERROR("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
TC_LOG_ERROR("network.opcode", "Received not handled opcode %s from %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str()
, GetPlayerInfo().c_str());
break;
}
}
catch (WorldPackets::PacketArrayMaxCapacityException const& pamce)
{
TC_LOG_ERROR("network", "PacketArrayMaxCapacityException: %s while parsing %s from %s.",
pamce.what(), GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())).c_str(), GetPlayerInfo().c_str());
}
catch (ByteBufferException const&)
{
TC_LOG_ERROR("network", "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
@@ -484,7 +485,7 @@ void WorldSession::LogoutPlayer(bool save)
{
// finish pending transfers before starting the logout
while (_player && _player->IsBeingTeleportedFar())
HandleMoveWorldportAckOpcode();
HandleMoveWorldportAck();
m_playerLogout = true;
m_playerSave = save;
@@ -547,7 +548,7 @@ void WorldSession::LogoutPlayer(bool save)
// Repop at Graveyard or other player far teleport will prevent saving player because of not present map
// Teleport player immediately for correct player save
while (_player->IsBeingTeleportedFar())
HandleMoveWorldportAckOpcode();
HandleMoveWorldportAck();
///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId()))
@@ -695,28 +696,28 @@ void WorldSession::ResetTimeOutTime()
m_timeOutTime = int32(sWorld->getIntConfig(CONFIG_SOCKET_TIMEOUTTIME));
}
void WorldSession::Handle_NULL(WorldPacket& recvPacket)
void WorldSession::Handle_NULL(WorldPacket& null)
{
TC_LOG_ERROR("network.opcode", "Received unhandled opcode %s from %s"
, GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
, GetOpcodeNameForLogging(static_cast<OpcodeClient>(null.GetOpcode())).c_str(), GetPlayerInfo().c_str());
}
void WorldSession::Handle_EarlyProccess(WorldPacket& recvPacket)
{
TC_LOG_ERROR("network.opcode", "Received opcode %s that must be processed in WorldSocket::OnRead from %s"
, GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
, GetOpcodeNameForLogging(static_cast<OpcodeClient>(recvPacket.GetOpcode())).c_str(), GetPlayerInfo().c_str());
}
void WorldSession::Handle_ServerSide(WorldPacket& recvPacket)
{
TC_LOG_ERROR("network.opcode", "Received server-side opcode %s from %s"
, GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
, GetOpcodeNameForLogging(static_cast<OpcodeClient>(recvPacket.GetOpcode())).c_str(), GetPlayerInfo().c_str());
}
void WorldSession::Handle_Deprecated(WorldPacket& recvPacket)
{
TC_LOG_ERROR("network.opcode", "Received deprecated opcode %s from %s"
, GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
, GetOpcodeNameForLogging(static_cast<OpcodeClient>(recvPacket.GetOpcode())).c_str(), GetPlayerInfo().c_str());
}
void WorldSession::SendAuthWaitQue(uint32 position)
@@ -1214,7 +1215,7 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co
TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)",
Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(),
opcodeTable[p.GetOpcode()]->Name, p.GetOpcode(), packetCounter.amountCounter);
opcodeTable[static_cast<OpcodeClient>(p.GetOpcode())]->Name, p.GetOpcode(), packetCounter.amountCounter);
switch (_policy)
{

View File

@@ -27,6 +27,7 @@
#include "DatabaseEnvFwd.h"
#include "LockedQueue.h"
#include "ObjectGuid.h"
#include "Packet.h"
#include "QueryCallbackProcessor.h"
#include "SharedDefines.h"
#include <map>
@@ -73,6 +74,10 @@ namespace rbac
class RBACData;
}
namespace WorldPackets
{
}
enum AccountDataType
{
GLOBAL_CONFIG_CACHE = 0, // 0x01 g
@@ -607,7 +612,7 @@ class TC_GAME_API WorldSession
void HandleGameObjectQueryOpcode(WorldPacket& recvPacket);
void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket);
void HandleMoveWorldportAckOpcode(); // for server-side calls
void HandleMoveWorldportAck(); // for server-side calls
void HandleMovementOpcodes(WorldPacket& recvPacket);
void HandleSetActiveMoverOpcode(WorldPacket& recvData);

View File

@@ -104,9 +104,6 @@ bool WorldSocket::Update()
MessageBuffer buffer(_sendBufferSize);
while (_bufferQueue.Dequeue(queued))
{
if (_worldSession && queued->size() > 0x400 && !queued->IsCompressed())
queued->Compress(_worldSession->GetCompressionStream());
ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
if (queued->NeedsEncryption())
_authCrypt.EncryptSend(header.header, header.getHeaderLength());
@@ -335,8 +332,8 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler()
if (_initialized)
{
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
OpcodeClient opcode = static_cast<OpcodeClient>(header->cmd);
Opcodes opcode = Opcodes(header->cmd);
WorldPacket packet(opcode, std::move(_packetBuffer));
WorldPacket* packetToQueue;
@@ -426,7 +423,7 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler()
OpcodeHandler const* handler = opcodeTable[opcode];
if (!handler)
{
TC_LOG_ERROR("network.opcode", "No defined handler for opcode %s sent by %s", GetOpcodeNameForLogging(packet.GetOpcode()).c_str(), _worldSession->GetPlayerInfo().c_str());
TC_LOG_ERROR("network.opcode", "No defined handler for opcode %s sent by %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet.GetOpcode())).c_str(), _worldSession->GetPlayerInfo().c_str());
return ReadDataHandlerResult::Error;
}
@@ -455,7 +452,7 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler()
return ReadDataHandlerResult::Ok;
}
void WorldSocket::LogOpcodeText(uint16 opcode, std::unique_lock<std::mutex> const& guard) const
void WorldSocket::LogOpcodeText(OpcodeClient opcode, std::unique_lock<std::mutex> const& guard) const
{
if (!guard)
{
@@ -470,7 +467,7 @@ void WorldSocket::LogOpcodeText(uint16 opcode, std::unique_lock<std::mutex> cons
void WorldSocket::SendPacketAndLogOpcode(WorldPacket& packet)
{
TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetRemoteIpAddress().to_string().c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str());
TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetRemoteIpAddress().to_string().c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str());
SendPacket(packet);
}

View File

@@ -33,6 +33,11 @@
using boost::asio::ip::tcp;
class EncryptablePacket;
namespace WorldPackets
{
class ServerPacket;
}
#pragma pack(push, 1)
struct ClientPktHeader
@@ -88,7 +93,7 @@ private:
/// writes network.opcode log
/// accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock
void LogOpcodeText(uint16 opcode, std::unique_lock<std::mutex> const& guard) const;
void LogOpcodeText(OpcodeClient opcode, std::unique_lock<std::mutex> const& guard) const;
/// sends and logs network.opcode without accessing WorldSession
void SendPacketAndLogOpcode(WorldPacket& packet);
void HandleSendAuthSession();

View File

@@ -2179,6 +2179,9 @@ void World::SetInitialWorldSettings()
// Delete all custom channels which haven't been used for PreserveCustomChannelDuration days.
Channel::CleanOldChannelsInDB();
TC_LOG_INFO("server.loading", "Initializing Opcodes...");
opcodeTable.Initialize();
TC_LOG_INFO("server.loading", "Starting Arena Season...");
sGameEventMgr->StartArenaSeason();
@@ -2240,9 +2243,6 @@ void World::SetInitialWorldSettings()
});
}
TC_LOG_INFO("misc", "Initializing Opcodes...");
opcodeTable.Initialize();
TC_LOG_INFO("misc", "Loading hotfix info...");
sObjectMgr->LoadHotfixData();

View File

@@ -76,7 +76,11 @@ class TC_SHARED_API ByteBuffer
}
ByteBuffer(ByteBuffer&& buf) : _rpos(buf._rpos), _wpos(buf._wpos),
_bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(std::move(buf._storage)) { }
_bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(std::move(buf._storage))
{
buf._rpos = 0;
buf._wpos = 0;
}
ByteBuffer(ByteBuffer const& right) : _rpos(right._rpos), _wpos(right._wpos),
_bitpos(right._bitpos), _curbitval(right._curbitval), _storage(right._storage) { }
@@ -97,6 +101,20 @@ class TC_SHARED_API ByteBuffer
return *this;
}
ByteBuffer& operator=(ByteBuffer&& right)
{
if (this != &right)
{
_rpos = right._rpos;
right._rpos = 0;
_wpos = right._wpos;
right._wpos = 0;
_storage = std::move(right._storage);
}
return *this;
}
virtual ~ByteBuffer() { }
void clear()
@@ -528,6 +546,11 @@ class TC_SHARED_API ByteBuffer
_storage.reserve(ressize);
}
void shrink_to_fit()
{
_storage.shrink_to_fit();
}
void append(const char *src, size_t cnt)
{
return append((const uint8 *)src, cnt);