feat: add NLPacket protocol implementation for Overte domain communication
This commit is contained in:
149
src/NLPacketCodec.cpp
Normal file
149
src/NLPacketCodec.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// NLPacketCodec.cpp
|
||||
#include "NLPacketCodec.hpp"
|
||||
#include <arpa/inet.h>
|
||||
|
||||
namespace Overte {
|
||||
|
||||
// Control bit masks for sequence number field
|
||||
static constexpr uint32_t CONTROL_BIT_MASK = 0x80000000; // Bit 31
|
||||
static constexpr uint32_t RELIABLE_BIT_MASK = 0x40000000; // Bit 30
|
||||
static constexpr uint32_t MESSAGE_BIT_MASK = 0x20000000; // Bit 29
|
||||
static constexpr uint32_t OBFUSCATION_MASK = 0x18000000; // Bits 27-28
|
||||
static constexpr uint32_t SEQUENCE_NUMBER_MASK = 0x07FFFFFF; // Bits 0-26
|
||||
|
||||
NLPacket::NLPacket(PacketType type, PacketVersion version, bool isReliable)
|
||||
: m_type(type)
|
||||
, m_version(version)
|
||||
, m_isReliable(isReliable)
|
||||
{
|
||||
// Determine header size (sourced packets have LocalID)
|
||||
m_isSourced = false; // Most client packets aren't sourced
|
||||
m_headerSize = m_isSourced ? SOURCED_HEADER_SIZE : BASE_HEADER_SIZE;
|
||||
|
||||
// Reserve space for header
|
||||
m_data.resize(m_headerSize);
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
void NLPacket::writeHeader() {
|
||||
size_t offset = 0;
|
||||
|
||||
// Write sequence number and flags
|
||||
uint32_t seqAndFlags = m_sequenceNumber & SEQUENCE_NUMBER_MASK;
|
||||
if (m_isReliable) {
|
||||
seqAndFlags |= RELIABLE_BIT_MASK;
|
||||
}
|
||||
// Convert to network byte order
|
||||
uint32_t netSeqAndFlags = htonl(seqAndFlags);
|
||||
std::memcpy(m_data.data() + offset, &netSeqAndFlags, sizeof(uint32_t));
|
||||
offset += sizeof(uint32_t);
|
||||
|
||||
// Write packet type
|
||||
m_data[offset++] = static_cast<uint8_t>(m_type);
|
||||
|
||||
// Write version
|
||||
m_data[offset++] = m_version;
|
||||
|
||||
// Write source ID if sourced
|
||||
if (m_isSourced) {
|
||||
uint16_t netSourceID = htons(m_sourceID);
|
||||
std::memcpy(m_data.data() + offset, &netSourceID, sizeof(uint16_t));
|
||||
offset += sizeof(uint16_t);
|
||||
}
|
||||
}
|
||||
|
||||
void NLPacket::write(const void* data, size_t size) {
|
||||
const uint8_t* bytes = static_cast<const uint8_t*>(data);
|
||||
m_data.insert(m_data.end(), bytes, bytes + size);
|
||||
}
|
||||
|
||||
void NLPacket::writeUInt8(uint8_t value) {
|
||||
m_data.push_back(value);
|
||||
}
|
||||
|
||||
void NLPacket::writeUInt16(uint16_t value) {
|
||||
uint16_t netValue = htons(value);
|
||||
write(&netValue, sizeof(netValue));
|
||||
}
|
||||
|
||||
void NLPacket::writeUInt32(uint32_t value) {
|
||||
uint32_t netValue = htonl(value);
|
||||
write(&netValue, sizeof(netValue));
|
||||
}
|
||||
|
||||
void NLPacket::writeUInt64(uint64_t value) {
|
||||
// Network byte order for 64-bit (big-endian)
|
||||
uint64_t netValue =
|
||||
((value & 0xFF00000000000000ULL) >> 56) |
|
||||
((value & 0x00FF000000000000ULL) >> 40) |
|
||||
((value & 0x0000FF0000000000ULL) >> 24) |
|
||||
((value & 0x000000FF00000000ULL) >> 8) |
|
||||
((value & 0x00000000FF000000ULL) << 8) |
|
||||
((value & 0x0000000000FF0000ULL) << 24) |
|
||||
((value & 0x000000000000FF00ULL) << 40) |
|
||||
((value & 0x00000000000000FFULL) << 56);
|
||||
write(&netValue, sizeof(netValue));
|
||||
}
|
||||
|
||||
void NLPacket::writeString(const std::string& str, bool nullTerminated) {
|
||||
write(str.data(), str.size());
|
||||
if (nullTerminated) {
|
||||
writeUInt8(0);
|
||||
}
|
||||
}
|
||||
|
||||
void NLPacket::setSequenceNumber(SequenceNumber seq) {
|
||||
m_sequenceNumber = seq & SEQUENCE_NUMBER_MASK;
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
void NLPacket::setSourceID(LocalID id) {
|
||||
m_sourceID = id;
|
||||
m_isSourced = true;
|
||||
// Resize if needed
|
||||
if (m_headerSize != SOURCED_HEADER_SIZE) {
|
||||
m_headerSize = SOURCED_HEADER_SIZE;
|
||||
m_data.resize(m_headerSize);
|
||||
}
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
bool NLPacket::parseHeader(const uint8_t* data, size_t size, Header& header) {
|
||||
if (size < BASE_HEADER_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
// Read sequence and flags
|
||||
uint32_t netSeqAndFlags;
|
||||
std::memcpy(&netSeqAndFlags, data + offset, sizeof(uint32_t));
|
||||
header.sequenceAndFlags = ntohl(netSeqAndFlags);
|
||||
offset += sizeof(uint32_t);
|
||||
|
||||
// Read packet type
|
||||
header.type = static_cast<PacketType>(data[offset++]);
|
||||
|
||||
// Read version
|
||||
header.version = data[offset++];
|
||||
|
||||
// Read source ID if present (check if packet is sourced)
|
||||
if (size >= SOURCED_HEADER_SIZE) {
|
||||
uint16_t netSourceID;
|
||||
std::memcpy(&netSourceID, data + offset, sizeof(uint16_t));
|
||||
header.sourceID = ntohs(netSourceID);
|
||||
} else {
|
||||
header.sourceID = NULL_LOCAL_ID;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PacketType NLPacket::getType(const uint8_t* data, size_t size) {
|
||||
if (size < sizeof(uint32_t) + 1) {
|
||||
return PacketType::Unknown;
|
||||
}
|
||||
return static_cast<PacketType>(data[sizeof(uint32_t)]);
|
||||
}
|
||||
|
||||
} // namespace Overte
|
||||
91
src/NLPacketCodec.hpp
Normal file
91
src/NLPacketCodec.hpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// NLPacketCodec.hpp
|
||||
// Minimal NLPacket protocol implementation for Overte domain communication
|
||||
// Based on Overte's NLPacket.h specification
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
namespace Overte {
|
||||
|
||||
// Packet types from Overte protocol
|
||||
enum class PacketType : uint8_t {
|
||||
Unknown = 0,
|
||||
Ping = 1,
|
||||
PingReply = 2,
|
||||
DomainList = 3,
|
||||
DomainListRequest = 4,
|
||||
DomainConnectionDenied = 6,
|
||||
DomainServerRequireDTLS = 7,
|
||||
DomainConnectRequest = 8,
|
||||
DomainServerPathQuery = 9,
|
||||
DomainServerPathResponse = 10,
|
||||
DomainServerAddedNode = 11,
|
||||
DomainServerConnectionToken = 12,
|
||||
DomainSettingsRequest = 13,
|
||||
DomainSettings = 14,
|
||||
// ... many more packet types
|
||||
EntityAdd = 0x41,
|
||||
EntityEdit = 0x42,
|
||||
EntityErase = 0x43,
|
||||
EntityQuery = 0x44,
|
||||
EntityData = 0x45,
|
||||
};
|
||||
|
||||
using PacketVersion = uint8_t;
|
||||
using LocalID = uint16_t;
|
||||
using SequenceNumber = uint32_t;
|
||||
|
||||
// NLPacket structure (minimal implementation)
|
||||
class NLPacket {
|
||||
public:
|
||||
// Packet header components
|
||||
struct Header {
|
||||
uint32_t sequenceAndFlags; // Sequence number (29 bits) + flags (3 bits)
|
||||
PacketType type;
|
||||
PacketVersion version;
|
||||
LocalID sourceID; // Only for sourced packets
|
||||
};
|
||||
|
||||
static constexpr LocalID NULL_LOCAL_ID = 0;
|
||||
static constexpr size_t BASE_HEADER_SIZE = sizeof(uint32_t) + sizeof(PacketType) + sizeof(PacketVersion);
|
||||
static constexpr size_t SOURCED_HEADER_SIZE = BASE_HEADER_SIZE + sizeof(LocalID);
|
||||
|
||||
NLPacket(PacketType type, PacketVersion version = 0, bool isReliable = false);
|
||||
|
||||
// Write data to packet payload
|
||||
void write(const void* data, size_t size);
|
||||
void writeUInt8(uint8_t value);
|
||||
void writeUInt16(uint16_t value);
|
||||
void writeUInt32(uint32_t value);
|
||||
void writeUInt64(uint64_t value);
|
||||
void writeString(const std::string& str, bool nullTerminated = true);
|
||||
|
||||
// Get packet data for sending
|
||||
const std::vector<uint8_t>& getData() const { return m_data; }
|
||||
size_t getSize() const { return m_data.size(); }
|
||||
|
||||
// Parse received packet
|
||||
static bool parseHeader(const uint8_t* data, size_t size, Header& header);
|
||||
static PacketType getType(const uint8_t* data, size_t size);
|
||||
|
||||
void setSequenceNumber(SequenceNumber seq);
|
||||
void setSourceID(LocalID id);
|
||||
|
||||
private:
|
||||
void writeHeader();
|
||||
|
||||
PacketType m_type;
|
||||
PacketVersion m_version;
|
||||
SequenceNumber m_sequenceNumber{0};
|
||||
LocalID m_sourceID{NULL_LOCAL_ID};
|
||||
bool m_isReliable;
|
||||
bool m_isSourced{false};
|
||||
|
||||
std::vector<uint8_t> m_data;
|
||||
size_t m_headerSize;
|
||||
};
|
||||
|
||||
} // namespace Overte
|
||||
Reference in New Issue
Block a user