2021-10-20 10:11:40 +02:00
|
|
|
#include "ClientNetwork.h"
|
2021-10-22 09:06:58 +02:00
|
|
|
#include "ClientDetours.h"
|
2021-10-20 10:11:40 +02:00
|
|
|
|
2021-10-20 20:31:14 +02:00
|
|
|
#include "CustomPacketBuffer.h"
|
2021-10-20 10:11:40 +02:00
|
|
|
#include "Logger.h"
|
|
|
|
|
#include "ClientLua.h"
|
|
|
|
|
|
2021-10-20 20:31:14 +02:00
|
|
|
#include "CustomPacketDefines.h"
|
2021-10-20 17:22:11 +02:00
|
|
|
|
2021-10-20 10:11:40 +02:00
|
|
|
#include <map>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
// note: most of the mess here is because I didn't
|
|
|
|
|
// figure out how to register userdata yet
|
|
|
|
|
|
2021-10-21 12:33:48 +02:00
|
|
|
struct ClientPacket;
|
|
|
|
|
|
2021-10-24 12:23:43 +02:00
|
|
|
CLIENT_FUNCTION(InitializePacket, 0x00401050, __thiscall, void, (ClientPacket* packet))
|
|
|
|
|
CLIENT_FUNCTION(FinalizePacket, 0x00401130, __thiscall, void, (ClientPacket* packet))
|
|
|
|
|
CLIENT_FUNCTION(SendPacket, 0x006B0B50, __cdecl, void, (ClientPacket* packet))
|
2021-10-21 12:33:48 +02:00
|
|
|
|
2021-10-21 09:11:56 +02:00
|
|
|
// The raw client packet
|
|
|
|
|
struct ClientPacket {
|
2021-10-23 12:09:38 +02:00
|
|
|
uint32_t m_padding;
|
|
|
|
|
uint8_t* m_buffer;
|
|
|
|
|
uint32_t m_base;
|
|
|
|
|
uint32_t m_alloc;
|
|
|
|
|
uint32_t m_size;
|
|
|
|
|
uint32_t m_read;
|
|
|
|
|
ClientPacket(uint8_t* buffer, size_t size)
|
|
|
|
|
: m_padding(0)
|
|
|
|
|
, m_buffer(0)
|
|
|
|
|
, m_size(0)
|
|
|
|
|
, m_alloc(0)
|
|
|
|
|
, m_base(0)
|
|
|
|
|
, m_read(0)
|
|
|
|
|
{
|
|
|
|
|
InitializePacket(this);
|
|
|
|
|
m_buffer = buffer;
|
|
|
|
|
m_size = size;
|
|
|
|
|
m_alloc = size;
|
|
|
|
|
}
|
2021-10-21 09:11:56 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2021-10-20 20:35:46 +02:00
|
|
|
class ClientMessageWrite : public CustomPacketWrite
|
2021-10-20 10:11:40 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2021-10-23 12:09:38 +02:00
|
|
|
ClientMessageWrite()
|
|
|
|
|
: CustomPacketWrite(0, MAX_FRAGMENT_SIZE,0)
|
|
|
|
|
{}
|
|
|
|
|
ClientMessageWrite(opcode_t opcode, totalSize_t size)
|
|
|
|
|
: CustomPacketWrite(opcode, MAX_FRAGMENT_SIZE,size)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void Send()
|
|
|
|
|
{
|
|
|
|
|
std::vector<CustomPacketChunk>& chunks = buildMessages();
|
|
|
|
|
for (auto& chunk : chunks)
|
|
|
|
|
{
|
|
|
|
|
// the API assumes the opcode is not a part of the payload,
|
|
|
|
|
// because TrinityCore WorldPackets do not include it.
|
|
|
|
|
//
|
|
|
|
|
// This means just a single copy on the client.
|
|
|
|
|
// Getting rid of it would be very cumbersome to almost no benefit.
|
|
|
|
|
|
|
|
|
|
size_t fullSize = sizeof(uint32_t) + chunk.FullSize();
|
|
|
|
|
char* c = new char[fullSize];
|
2021-10-21 12:33:48 +02:00
|
|
|
#pragma warning(push)
|
|
|
|
|
#pragma warning(disable: 6001)
|
2021-10-23 12:09:38 +02:00
|
|
|
(*(uint32_t*)c) = CLIENT_TO_SERVER_OPCODE;
|
2021-10-21 12:33:48 +02:00
|
|
|
#pragma warning(pop)
|
2021-10-23 12:09:38 +02:00
|
|
|
memcpy(c + sizeof(uint32_t), chunk.Data(), chunk.FullSize());
|
|
|
|
|
ClientPacket* p = new ClientPacket((uint8_t*)c, fullSize);
|
|
|
|
|
FinalizePacket(p);
|
|
|
|
|
SendPacket(p);
|
|
|
|
|
chunk.Destroy();
|
|
|
|
|
}
|
|
|
|
|
Clear(); // we already destroyed each chunk individually
|
|
|
|
|
}
|
2021-10-20 10:11:40 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
class MessageRegistry {
|
2021-10-23 12:09:38 +02:00
|
|
|
// if you store 4 billion messages at once you'll have other problems
|
|
|
|
|
uint32_t m_cur = 0;
|
2021-10-20 10:11:40 +02:00
|
|
|
public:
|
2021-10-23 12:09:38 +02:00
|
|
|
std::map<uint32_t, T> m_map;
|
|
|
|
|
uint32_t freeId()
|
|
|
|
|
{
|
|
|
|
|
while (m_map.find(m_cur) != m_map.end())
|
|
|
|
|
{
|
|
|
|
|
++m_cur;
|
|
|
|
|
}
|
|
|
|
|
return m_cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t add(T& value, T** ptr)
|
|
|
|
|
{
|
|
|
|
|
*ptr = &(m_map[freeId()] = value);
|
|
|
|
|
return m_cur++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
T* get(uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
auto itr = m_map.find(id);
|
|
|
|
|
if (itr == m_map.end())
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return &itr->second;
|
|
|
|
|
}
|
2021-10-20 10:11:40 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
MessageRegistry<ClientMessageWrite> writes;
|
2021-10-22 09:06:58 +02:00
|
|
|
CustomPacketRead* curRead = nullptr;
|
2021-10-20 10:11:40 +02:00
|
|
|
|
2021-10-25 11:00:48 +02:00
|
|
|
std::map < opcode_t, std::vector<std::function<void(CustomPacketRead*)>>> cppListeners;
|
|
|
|
|
|
2021-10-20 20:35:46 +02:00
|
|
|
class ClientMessageBuffer : public CustomPacketBuffer {
|
2021-10-22 09:06:58 +02:00
|
|
|
public:
|
2021-10-23 12:09:38 +02:00
|
|
|
ClientMessageBuffer()
|
|
|
|
|
: CustomPacketBuffer(MIN_FRAGMENT_SIZE, BUFFER_QUOTA, MAX_FRAGMENT_SIZE)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
virtual void OnPacket(CustomPacketRead* value) override final
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG << "Client receive full packet with opcode" << value->Opcode();
|
|
|
|
|
curRead = value;
|
|
|
|
|
ClientLua::DoString(
|
|
|
|
|
("__FireCustomPacket(" + std::to_string(value->Opcode()) + ")").c_str()
|
|
|
|
|
, ClientLua::State()
|
|
|
|
|
);
|
|
|
|
|
curRead = nullptr;
|
2021-10-25 11:00:48 +02:00
|
|
|
auto itr = cppListeners.find(value->Opcode());
|
|
|
|
|
if (itr != cppListeners.end())
|
|
|
|
|
{
|
|
|
|
|
for (auto const& cb : itr->second)
|
|
|
|
|
{
|
|
|
|
|
cb(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-23 12:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void OnError(CustomPacketResult error) override final
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR << "Packet reading error " << uint32_t(error);
|
|
|
|
|
}
|
2021-10-20 10:11:40 +02:00
|
|
|
};
|
|
|
|
|
|
2021-10-25 11:00:48 +02:00
|
|
|
int ClientNetwork::OnCustomPacket(
|
|
|
|
|
opcode_t opcode
|
|
|
|
|
, std::function<void(CustomPacketRead*)> callback
|
|
|
|
|
) {
|
|
|
|
|
auto itr = cppListeners.find(opcode);
|
|
|
|
|
if (itr != cppListeners.end())
|
|
|
|
|
{
|
|
|
|
|
itr->second.push_back(callback);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cppListeners[opcode] = { callback };
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-10-22 09:06:58 +02:00
|
|
|
namespace
|
|
|
|
|
{
|
2021-10-23 12:09:38 +02:00
|
|
|
ClientMessageBuffer clientBuffer;
|
2021-10-22 09:06:58 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-20 10:11:40 +02:00
|
|
|
template <typename T>
|
|
|
|
|
int WriteNum(lua_State* L)
|
|
|
|
|
{
|
2021-11-26 15:10:53 +01:00
|
|
|
uint32_t id = uint32_t(ClientLua::GetNumber(L, 2, 0));
|
|
|
|
|
T val = T(ClientLua::GetNumber(L, 3, 0));
|
2021-10-23 12:09:38 +02:00
|
|
|
|
|
|
|
|
auto itr = writes.m_map.find(id);
|
|
|
|
|
if (itr == writes.m_map.end())
|
|
|
|
|
{
|
|
|
|
|
// todo: error message
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
itr->second.Write(val);
|
|
|
|
|
return 0;
|
2021-10-20 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-22 09:06:58 +02:00
|
|
|
template <typename T>
|
|
|
|
|
int ReadNum(lua_State* L)
|
|
|
|
|
{
|
2021-11-26 15:10:53 +01:00
|
|
|
T def = T(ClientLua::GetNumber(L, 2, 0));
|
2021-10-23 12:09:38 +02:00
|
|
|
ClientLua::PushNumber(
|
|
|
|
|
L,
|
|
|
|
|
curRead == nullptr
|
|
|
|
|
? def
|
|
|
|
|
: curRead->Read<T>(def)
|
|
|
|
|
);
|
|
|
|
|
return 1;
|
2021-10-22 09:06:58 +02:00
|
|
|
}
|
|
|
|
|
|
2021-11-26 15:10:53 +01:00
|
|
|
enum class LuaNetworkOpcode {
|
|
|
|
|
WRITE_SIZE = 0,
|
|
|
|
|
READ_SIZE = 1,
|
|
|
|
|
WRITE_UINT8 = 2,
|
|
|
|
|
WRITE_INT8 = 3,
|
|
|
|
|
WRITE_UINT16 = 4,
|
|
|
|
|
WRITE_INT16 = 5,
|
|
|
|
|
WRITE_UINT32 = 6,
|
|
|
|
|
WRITE_INT32 = 7,
|
2022-06-21 15:25:56 -04:00
|
|
|
WRITE_UINT64 = 8,
|
|
|
|
|
WRITE_INT64 = 9,
|
|
|
|
|
WRITE_FLOAT = 10,
|
|
|
|
|
WRITE_DOUBLE = 11,
|
|
|
|
|
WRITE_STRING = 12,
|
2021-11-26 15:10:53 +01:00
|
|
|
|
2022-06-21 15:25:56 -04:00
|
|
|
READ_UINT8 = 13,
|
|
|
|
|
READ_INT8 = 14,
|
|
|
|
|
READ_UINT16 = 15,
|
|
|
|
|
READ_INT16 = 16,
|
|
|
|
|
READ_UINT32 = 17,
|
|
|
|
|
READ_INT32 = 18,
|
|
|
|
|
READ_UINT64 = 19,
|
|
|
|
|
READ_INT64 = 20,
|
|
|
|
|
READ_FLOAT = 21,
|
|
|
|
|
READ_DOUBLE = 22,
|
|
|
|
|
READ_STRING = 23,
|
|
|
|
|
MAKE_CUSTOM_PACKET = 24,
|
|
|
|
|
SEND_CUSTOM_PACKET = 25,
|
|
|
|
|
RESET_CUSTOM_PACKET = 26,
|
2021-11-26 15:10:53 +01:00
|
|
|
};
|
|
|
|
|
|
2021-10-23 12:05:48 +02:00
|
|
|
void ClientNetwork::initialize()
|
|
|
|
|
{
|
2021-10-23 12:41:53 +02:00
|
|
|
ClientLua::AddFunction(
|
2021-11-26 15:10:53 +01:00
|
|
|
"_CLIENT_NETWORK"
|
2021-10-23 12:09:38 +02:00
|
|
|
, [](lua_State* L) {
|
2021-11-26 15:10:53 +01:00
|
|
|
LuaNetworkOpcode opcode = (LuaNetworkOpcode) ClientLua::GetNumber(L, 1);
|
|
|
|
|
switch (opcode) {
|
|
|
|
|
case LuaNetworkOpcode::WRITE_SIZE: {
|
|
|
|
|
auto itr = writes.m_map.find(ClientLua::GetNumber(L, 2, 0));
|
|
|
|
|
ClientLua::PushNumber(L, itr == writes.m_map.end() ? 0 : itr->second.Size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_SIZE: {
|
|
|
|
|
ClientLua::PushNumber(L, curRead ? curRead->Size() : 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_UINT8: {
|
|
|
|
|
return WriteNum<uint8_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_INT8: {
|
|
|
|
|
return WriteNum<int8_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_UINT16: {
|
|
|
|
|
return WriteNum<uint16_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_INT16: {
|
|
|
|
|
return WriteNum<int16_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_UINT32: {
|
|
|
|
|
return WriteNum<uint32_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_INT32: {
|
|
|
|
|
return WriteNum<int32_t>(L);
|
|
|
|
|
}
|
2022-06-21 15:25:56 -04:00
|
|
|
case LuaNetworkOpcode::WRITE_UINT64: {
|
|
|
|
|
return WriteNum<uint64_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_INT64: {
|
|
|
|
|
return WriteNum<int64_t>(L);
|
|
|
|
|
}
|
2021-11-26 15:10:53 +01:00
|
|
|
case LuaNetworkOpcode::WRITE_FLOAT: {
|
|
|
|
|
return WriteNum<float>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::WRITE_DOUBLE: {
|
|
|
|
|
return WriteNum<double>(L);
|
|
|
|
|
}
|
2021-10-23 12:09:38 +02:00
|
|
|
|
2021-11-26 15:10:53 +01:00
|
|
|
case LuaNetworkOpcode::WRITE_STRING: {
|
|
|
|
|
uint32_t id = uint32_t(ClientLua::GetNumber(L, 2, 0));
|
|
|
|
|
std::string str = ClientLua::GetString(L, 3, "");
|
|
|
|
|
auto itr = writes.m_map.find(id);
|
|
|
|
|
if (itr == writes.m_map.end())
|
|
|
|
|
{
|
|
|
|
|
// todo: error message
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
itr->second.WriteString(str);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_UINT8: {
|
|
|
|
|
return ReadNum<uint8_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_INT8: {
|
|
|
|
|
return ReadNum<int8_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_UINT16: {
|
|
|
|
|
return ReadNum<uint16_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_INT16: {
|
|
|
|
|
return ReadNum<int16_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_UINT32: {
|
|
|
|
|
return ReadNum<uint32_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_INT32: {
|
|
|
|
|
return ReadNum<int32_t>(L);
|
|
|
|
|
}
|
2022-06-21 15:25:56 -04:00
|
|
|
case LuaNetworkOpcode::READ_UINT64: {
|
|
|
|
|
return ReadNum<uint64_t>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_INT64: {
|
|
|
|
|
return ReadNum<int64_t>(L);
|
|
|
|
|
}
|
2021-11-26 15:10:53 +01:00
|
|
|
case LuaNetworkOpcode::READ_FLOAT: {
|
|
|
|
|
return ReadNum<float>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_DOUBLE: {
|
|
|
|
|
return ReadNum<double>(L);
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::READ_STRING: {
|
|
|
|
|
ClientLua::PushString(L, curRead == nullptr
|
|
|
|
|
? ""
|
|
|
|
|
: curRead->ReadString().c_str());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::MAKE_CUSTOM_PACKET: {
|
|
|
|
|
opcode_t opcode{ opcode_t(ClientLua::GetNumber(L, 2, 0)) };
|
|
|
|
|
totalSize_t size{ totalSize_t(ClientLua::GetNumber(L, 3, 0)) };
|
|
|
|
|
uint32_t id = writes.freeId();
|
|
|
|
|
writes.m_map[id] = ClientMessageWrite{ opcode, size };
|
|
|
|
|
ClientLua::PushNumber(L, id);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::SEND_CUSTOM_PACKET: {
|
|
|
|
|
uint32_t id{ uint32_t(ClientLua::GetNumber(L, 2)) };
|
|
|
|
|
ClientMessageWrite* write = writes.get(id);
|
|
|
|
|
if (write == nullptr)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR << "Failed to send message: no such write message";
|
|
|
|
|
// todo error message
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
write->Send();
|
|
|
|
|
writes.m_map.erase(id);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
case LuaNetworkOpcode::RESET_CUSTOM_PACKET: {
|
|
|
|
|
if (curRead == nullptr) return 0;
|
|
|
|
|
curRead->Reset();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
LOG_ERROR << "Received invalid LuaNetworkOpcode: " << int(opcode);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-23 12:09:38 +02:00
|
|
|
}
|
|
|
|
|
}, __FILE__, __LINE__);
|
2021-10-22 09:06:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef bool(* ClientPacketHandler)
|
|
|
|
|
(
|
2021-10-23 12:09:38 +02:00
|
|
|
void* unk
|
|
|
|
|
, uint32_t opcode
|
|
|
|
|
, int time
|
|
|
|
|
, ClientPacket* msg
|
2021-10-22 09:06:58 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CLIENT_DETOUR(
|
2021-10-24 11:47:49 +02:00
|
|
|
OnSetMessageHandler
|
2021-10-23 12:09:38 +02:00
|
|
|
, 0x006B0B80
|
2021-10-24 11:47:49 +02:00
|
|
|
, __cdecl
|
2021-10-23 12:09:38 +02:00
|
|
|
, int
|
|
|
|
|
, (uint32_t opcode, ClientPacketHandler handler, void* param)
|
2021-10-22 09:06:58 +02:00
|
|
|
) {
|
2021-10-23 12:09:38 +02:00
|
|
|
// the last opcodes in each batch that seems to register them
|
|
|
|
|
if (opcode == 253 || opcode == 50 || opcode == 532)
|
|
|
|
|
{
|
|
|
|
|
OnSetMessageHandler(
|
|
|
|
|
SERVER_TO_CLIENT_OPCODE
|
|
|
|
|
, [](void* a, uint32_t b, int time, ClientPacket* c) {
|
|
|
|
|
if (c->m_size <= 2) return true; // can this ever happen?
|
|
|
|
|
// -2 is ok, we already safety checked
|
|
|
|
|
clientBuffer.ReceivePacket(c->m_size - 2, (char*)c->m_buffer + 2);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
, nullptr
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return OnSetMessageHandler(opcode, handler, param);
|
2021-10-20 10:11:40 +02:00
|
|
|
}
|