feat: implement entity packet parsing and handling in OverteClient
This commit is contained in:
@@ -164,9 +164,120 @@ void OverteClient::poll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OverteClient::parseNetworkPackets() {
|
void OverteClient::parseNetworkPackets() {
|
||||||
// Placeholder: implement Overte standards parsing.
|
// Read from EntityServer socket
|
||||||
// Strategy: maintain input buffers per mixer; decode entity add/update/remove messages.
|
if (m_entityServerReady && m_entityFd != -1) {
|
||||||
// For now, no real network ingestion; this will be replaced by actual protocol integration.
|
char buf[1500];
|
||||||
|
sockaddr_storage from{}; socklen_t fromlen = sizeof(from);
|
||||||
|
ssize_t r = ::recvfrom(m_entityFd, buf, sizeof(buf), 0, reinterpret_cast<sockaddr*>(&from), &fromlen);
|
||||||
|
if (r > 0) {
|
||||||
|
parseEntityPacket(buf, static_cast<size_t>(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverteClient::parseEntityPacket(const char* data, size_t len) {
|
||||||
|
// Overte packet structure (simplified):
|
||||||
|
// - Byte 0: PacketType
|
||||||
|
// - Following bytes: payload (varies by type)
|
||||||
|
|
||||||
|
if (len < 1) return;
|
||||||
|
|
||||||
|
unsigned char packetType = static_cast<unsigned char>(data[0]);
|
||||||
|
|
||||||
|
// Overte PacketType enum values (reference from protocol documentation)
|
||||||
|
// EntityAdd = 0x10, EntityEdit = 0x11, EntityErase = 0x12, etc.
|
||||||
|
const unsigned char PACKET_TYPE_ENTITY_ADD = 0x10;
|
||||||
|
const unsigned char PACKET_TYPE_ENTITY_EDIT = 0x11;
|
||||||
|
const unsigned char PACKET_TYPE_ENTITY_ERASE = 0x12;
|
||||||
|
const unsigned char PACKET_TYPE_DOMAIN_LIST = 0x03;
|
||||||
|
|
||||||
|
switch (packetType) {
|
||||||
|
case PACKET_TYPE_DOMAIN_LIST:
|
||||||
|
handleDomainListReply(data + 1, len - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PACKET_TYPE_ENTITY_ADD: {
|
||||||
|
// EntityAdd packet structure (simplified):
|
||||||
|
// u64 entityID, string name, vec3 position, quat rotation, vec3 dimensions, ...
|
||||||
|
if (len < 9) break; // need at least 1+8 bytes
|
||||||
|
|
||||||
|
std::uint64_t entityId;
|
||||||
|
std::memcpy(&entityId, data + 1, 8);
|
||||||
|
|
||||||
|
// Parse name (null-terminated string after ID)
|
||||||
|
size_t offset = 9;
|
||||||
|
std::string name;
|
||||||
|
while (offset < len && data[offset] != '\0') {
|
||||||
|
name += data[offset++];
|
||||||
|
}
|
||||||
|
if (name.empty()) name = "Entity_" + std::to_string(entityId);
|
||||||
|
|
||||||
|
// For now, default transform (will parse full properties later)
|
||||||
|
OverteEntity entity{entityId, name, glm::mat4(1.0f)};
|
||||||
|
m_entities[entityId] = entity;
|
||||||
|
m_updateQueue.push_back(entityId);
|
||||||
|
|
||||||
|
std::cout << "[OverteClient] Entity added: " << name << " (id=" << entityId << ")" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PACKET_TYPE_ENTITY_EDIT: {
|
||||||
|
// EntityEdit packet: u64 entityID, property flags, property data...
|
||||||
|
if (len < 9) break;
|
||||||
|
|
||||||
|
std::uint64_t entityId;
|
||||||
|
std::memcpy(&entityId, data + 1, 8);
|
||||||
|
|
||||||
|
auto it = m_entities.find(entityId);
|
||||||
|
if (it != m_entities.end()) {
|
||||||
|
// TODO: parse property flags and update transform
|
||||||
|
// For now, mark as updated
|
||||||
|
m_updateQueue.push_back(entityId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PACKET_TYPE_ENTITY_ERASE: {
|
||||||
|
// EntityErase packet: u64 entityID
|
||||||
|
if (len < 9) break;
|
||||||
|
|
||||||
|
std::uint64_t entityId;
|
||||||
|
std::memcpy(&entityId, data + 1, 8);
|
||||||
|
|
||||||
|
auto it = m_entities.find(entityId);
|
||||||
|
if (it != m_entities.end()) {
|
||||||
|
m_entities.erase(it);
|
||||||
|
m_deleteQueue.push_back(entityId);
|
||||||
|
std::cout << "[OverteClient] Entity erased: id=" << entityId << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unknown or unhandled packet type
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverteClient::handleDomainListReply(const char* data, size_t len) {
|
||||||
|
// DomainList packet contains mixer endpoints
|
||||||
|
// Format varies; for now just log receipt
|
||||||
|
std::cout << "[OverteClient] DomainList reply received (" << len << " bytes)" << std::endl;
|
||||||
|
// TODO: parse mixer sockaddr structures and update entity/avatar endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverteClient::sendDomainListRequest() {
|
||||||
|
// Send DomainList request packet (PacketType 0x02 typically)
|
||||||
|
if (!m_udpReady || m_udpFd == -1) return;
|
||||||
|
|
||||||
|
const unsigned char PACKET_TYPE_DOMAIN_LIST_REQUEST = 0x02;
|
||||||
|
char packet[1] = { static_cast<char>(PACKET_TYPE_DOMAIN_LIST_REQUEST) };
|
||||||
|
|
||||||
|
ssize_t s = ::sendto(m_udpFd, packet, sizeof(packet), 0,
|
||||||
|
reinterpret_cast<sockaddr*>(&m_udpAddr), m_udpAddrLen);
|
||||||
|
if (s > 0) {
|
||||||
|
std::cout << "[OverteClient] DomainList request sent" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverteClient::sendMovementInput(const glm::vec3& linearVelocity) {
|
void OverteClient::sendMovementInput(const glm::vec3& linearVelocity) {
|
||||||
|
|||||||
Reference in New Issue
Block a user