FeatherMC/src/NetworkMessage.h

163 lines
4.3 KiB
C
Raw Permalink Normal View History

2020-07-25 19:28:32 +01:00
#pragma once
2020-08-01 02:10:43 +01:00
#include "util/ByteUtil.h"
2020-08-04 02:39:09 +01:00
#include "Types.h"
2020-08-01 02:10:43 +01:00
2020-07-25 19:28:32 +01:00
#include <cstdint>
#include <cstring>
#include <vector>
#include <string>
2020-07-26 04:19:14 +01:00
#include <cassert>
#define VARINT_MAX_SIZE 5
2020-07-25 19:28:32 +01:00
namespace Feather
2020-07-25 19:28:32 +01:00
{
2020-08-01 01:49:42 +01:00
class NetworkMessage
2020-07-25 19:28:32 +01:00
{
public:
2020-08-01 01:49:42 +01:00
NetworkMessage(int32_t expectedSize)
2020-07-25 19:28:32 +01:00
{
m_data.reserve(expectedSize);
2020-08-01 01:49:42 +01:00
m_data.resize(VARINT_MAX_SIZE);
2020-07-25 19:28:32 +01:00
}
2020-08-01 01:49:42 +01:00
template <typename T>
inline void WriteData(const T* data, size_t size)
2020-07-25 19:28:32 +01:00
{
2020-08-01 01:49:42 +01:00
size_t offset = m_data.size();
2020-07-25 19:28:32 +01:00
2020-08-01 01:49:42 +01:00
m_data.resize(offset + size);
std::memcpy(&m_data[offset], data, size);
2020-07-25 19:28:32 +01:00
}
2020-08-01 02:10:43 +01:00
// Writes a value, converting to big endian by default
template <typename T, Endian asEndian = Endian::Big>
2020-08-01 01:49:42 +01:00
inline void Write(const T& value)
{
2020-08-01 02:10:43 +01:00
if constexpr (asEndian == Endian::Big && sizeof(T) > 1)
{
T valueReversed = ReverseBytes(value);
2020-08-01 02:10:43 +01:00
WriteData(&valueReversed, sizeof(T));
}
else
{
WriteData(&value, sizeof(T));
}
2020-07-25 19:28:32 +01:00
}
// Write bool as 1 byte
template <>
inline void Write<bool>(const bool& value)
{
Write<uint8_t>(value ? 0x01 : 0x00);
}
template <typename Int = int32_t>
2020-08-01 02:55:41 +01:00
inline void WriteVarInt(Int val)
2020-07-25 19:28:32 +01:00
{
2020-08-01 02:55:41 +01:00
int32_t value = static_cast<int32_t>(val);
2020-07-25 19:28:32 +01:00
do {
uint8_t temp = uint8_t(value & 0b01111111);
value >>= 7;
if (value != 0)
temp |= 0b10000000;
2020-08-01 01:49:42 +01:00
Write(temp);
2020-07-25 19:28:32 +01:00
} while (value != 0);
}
inline void WriteString(const char* string, int32_t length)
{
2020-08-01 06:58:16 +01:00
int32_t stringSize = length;
2020-07-25 19:28:32 +01:00
WriteVarInt(stringSize);
2020-08-01 01:49:42 +01:00
WriteData(string, stringSize);
2020-07-25 19:28:32 +01:00
}
// Write string using std::string reference
inline void WriteString(const std::string& string)
{
WriteString(string.c_str(), string.length());
}
// Write string using string_view
inline void WriteString(std::string_view view)
{
WriteString(view.data(), view.size());
}
2020-08-04 02:39:09 +01:00
inline void WritePosition(BlockPos pos)
{
Write<int64_t>(pos.Encode());
}
2020-08-13 15:56:24 +01:00
inline void WriteSubMessage(const NetworkMessage& message)
{
WriteData(message.GetData(), message.GetDataSize());
}
2020-08-01 01:49:42 +01:00
inline void Finalize()
2020-07-26 04:19:14 +01:00
{
PrependVarIntSize();
2020-08-01 01:49:42 +01:00
#ifdef _DEBUG
2020-07-26 04:19:14 +01:00
m_finalized = true;
2020-08-01 01:49:42 +01:00
#endif
2020-07-26 04:19:14 +01:00
}
2020-08-01 01:49:42 +01:00
inline const uint8_t* GetData() const
2020-07-26 04:19:14 +01:00
{
2020-08-01 01:49:42 +01:00
#ifdef _DEBUG
2020-07-26 04:19:14 +01:00
// You must call Finalize() first
2020-08-23 02:44:28 +01:00
Assert(m_finalized, "NetworkMessage sent or resolved before Finalize() was called.");
2020-08-01 01:49:42 +01:00
#endif
return &m_data[m_startOffset];
2020-07-26 04:19:14 +01:00
}
2020-08-01 01:49:42 +01:00
inline size_t GetDataSize() const
2020-07-26 04:19:14 +01:00
{
2020-08-01 01:49:42 +01:00
#ifdef _DEBUG
2020-07-26 04:19:14 +01:00
// You must call Finalize() first
2020-08-23 02:44:28 +01:00
Assert(m_finalized, "NetworkMessage sent or resolved before Finalize() was called.");
2020-08-01 01:49:42 +01:00
#endif
2020-07-26 04:19:14 +01:00
return m_data.size() - m_startOffset;
}
2020-08-01 01:49:42 +01:00
2020-07-26 04:19:14 +01:00
private:
2020-08-01 01:49:42 +01:00
std::vector<uint8_t> m_data;
size_t m_startOffset = 0;
#ifdef _DEBUG
2020-07-26 04:19:14 +01:00
bool m_finalized = false;
2020-08-01 01:49:42 +01:00
#endif
2020-07-26 04:19:14 +01:00
void PrependVarIntSize()
{
uint8_t sizeBytes[VARINT_MAX_SIZE];
// compute the size of the packet excluding the size marker
2020-08-01 01:49:42 +01:00
int32_t value = static_cast<int32_t>(m_data.size() - VARINT_MAX_SIZE);
size_t index = 0;
2020-07-26 04:19:14 +01:00
// perform WriteVarInt into the static buffer sizeBytes
do {
uint8_t temp = uint8_t(value & 0b01111111);
value >>= 7;
if (value != 0)
temp |= 0b10000000;
sizeBytes[index++] = temp;
} while (value != 0 && index < VARINT_MAX_SIZE);
// where to start writing the size marker
// if we used all 5 bytes, this is zero
// if we used 3 bytes, this would be 2
2020-08-01 01:49:42 +01:00
size_t startIndex = VARINT_MAX_SIZE - index;
2020-07-26 04:19:14 +01:00
// Copy sizeBytes into our actual buffer, but align it to the right
2020-08-01 01:49:42 +01:00
for (size_t i = 0; i < index; i++)
2020-07-26 04:19:14 +01:00
m_data[startIndex + i] = sizeBytes[i];
m_startOffset = startIndex;
}
};
2020-08-01 00:57:33 +01:00
}