mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 18:44:00 +02:00
Merge branch 'master' of https://github.com/worklist/hifi
This commit is contained in:
commit
f5bbdc2c65
90 changed files with 1118 additions and 814 deletions
|
@ -830,12 +830,16 @@ void AnimationServer::readPendingDatagrams() {
|
|||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
nodeSockAddr.getAddressPointer(), nodeSockAddr.getPortPointer());
|
||||
if (packetVersionMatch(receivedPacket)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeJurisdiction) {
|
||||
int headerBytes = numBytesForPacketHeader(receivedPacket);
|
||||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
if (receivedPacket.data()[headerBytes] == NodeType::VoxelServer && ::jurisdictionListener) {
|
||||
::jurisdictionListener->queueReceivedPacket(nodeSockAddr, receivedPacket);
|
||||
|
||||
SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(receivedPacket);
|
||||
if (matchedNode) {
|
||||
::jurisdictionListener->queueReceivedPacket(matchedNode, receivedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
NodeList::getInstance()->processNodeData(nodeSockAddr, receivedPacket);
|
||||
|
|
|
@ -31,29 +31,43 @@ Agent::Agent(const QByteArray& packet) :
|
|||
_scriptEngine.getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
|
||||
}
|
||||
|
||||
void Agent::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
||||
PacketType datagramPacketType = packetTypeForPacket(dataByteArray);
|
||||
if (datagramPacketType == PacketTypeJurisdiction) {
|
||||
int headerBytes = numBytesForPacketHeader(dataByteArray);
|
||||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
switch (dataByteArray[headerBytes]) {
|
||||
case NodeType::VoxelServer:
|
||||
_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
|
||||
dataByteArray);
|
||||
break;
|
||||
case NodeType::ParticleServer:
|
||||
_scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(senderSockAddr,
|
||||
dataByteArray);
|
||||
break;
|
||||
void Agent::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType datagramPacketType = packetTypeForPacket(receivedPacket);
|
||||
if (datagramPacketType == PacketTypeJurisdiction) {
|
||||
int headerBytes = numBytesForPacketHeader(receivedPacket);
|
||||
|
||||
SharedNodePointer matchedNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
|
||||
if (matchedNode) {
|
||||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
switch (receivedPacket[headerBytes]) {
|
||||
case NodeType::VoxelServer:
|
||||
_scriptEngine.getVoxelsScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(matchedNode,
|
||||
receivedPacket);
|
||||
break;
|
||||
case NodeType::ParticleServer:
|
||||
_scriptEngine.getParticlesScriptingInterface()->getJurisdictionListener()->queueReceivedPacket(matchedNode,
|
||||
receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (datagramPacketType == PacketTypeParticleAddResponse) {
|
||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
Particle::handleAddParticleResponse(receivedPacket);
|
||||
|
||||
// also give our local particle tree a chance to remap any internal locally created particles
|
||||
_particleTree.handleAddParticleResponse(receivedPacket);
|
||||
} else {
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
} else if (datagramPacketType == PacketTypeParticleAddResponse) {
|
||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
||||
Particle::handleAddParticleResponse(dataByteArray);
|
||||
|
||||
// also give our local particle tree a chance to remap any internal locally created particles
|
||||
_particleTree.handleAddParticleResponse(dataByteArray);
|
||||
} else {
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, dataByteArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,10 +107,6 @@ void Agent::run() {
|
|||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
||||
|
||||
QTimer* pingNodesTimer = new QTimer(this);
|
||||
connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes()));
|
||||
pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000);
|
||||
|
||||
// tell our script engine about our local particle tree
|
||||
_scriptEngine.getParticlesScriptingInterface()->setParticleTree(&_particleTree);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
public slots:
|
||||
void run();
|
||||
|
||||
void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
|
||||
void readPendingDatagrams();
|
||||
signals:
|
||||
void willSendAudioDataCallback();
|
||||
void willSendVisualDataCallback();
|
||||
|
|
|
@ -90,8 +90,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
|||
timer->start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
|
||||
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams,
|
||||
Qt::QueuedConnection);
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendAssignmentRequest() {
|
||||
|
@ -111,50 +110,45 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
if (packetVersionMatch(receivedPacket)) {
|
||||
if (_currentAssignment) {
|
||||
// have the threaded current assignment handle this datagram
|
||||
QMetaObject::invokeMethod(_currentAssignment, "processDatagram", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, receivedPacket),
|
||||
Q_ARG(HifiSockAddr, senderSockAddr));
|
||||
} else if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
|
||||
// construct the deployed assignment from the packet data
|
||||
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
|
||||
|
||||
if (_currentAssignment) {
|
||||
qDebug() << "Dropping received assignment since we are currently running one.";
|
||||
} else {
|
||||
// construct the deployed assignment from the packet data
|
||||
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
|
||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||
|
||||
if (_currentAssignment) {
|
||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||
|
||||
// switch our nodelist domain IP and port to whoever sent us the assignment
|
||||
|
||||
nodeList->setDomainSockAddr(senderSockAddr);
|
||||
nodeList->setOwnerUUID(_currentAssignment->getUUID());
|
||||
|
||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainIP().toString();
|
||||
|
||||
// start the deployed assignment
|
||||
QThread* workerThread = new QThread(this);
|
||||
|
||||
connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run()));
|
||||
|
||||
connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted()));
|
||||
connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit()));
|
||||
connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater()));
|
||||
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
||||
|
||||
_currentAssignment->moveToThread(workerThread);
|
||||
|
||||
// move the NodeList to the thread used for the _current assignment
|
||||
nodeList->moveToThread(workerThread);
|
||||
|
||||
// Starts an event loop, and emits workerThread->started()
|
||||
workerThread->start();
|
||||
} else {
|
||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
// switch our nodelist domain IP and port to whoever sent us the assignment
|
||||
|
||||
nodeList->setDomainSockAddr(senderSockAddr);
|
||||
nodeList->setSessionUUID(_currentAssignment->getUUID());
|
||||
|
||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainIP().toString();
|
||||
|
||||
// start the deployed assignment
|
||||
QThread* workerThread = new QThread(this);
|
||||
|
||||
connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run()));
|
||||
|
||||
connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted()));
|
||||
connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit()));
|
||||
connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater()));
|
||||
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
|
||||
|
||||
_currentAssignment->moveToThread(workerThread);
|
||||
|
||||
// move the NodeList to the thread used for the _current assignment
|
||||
nodeList->moveToThread(workerThread);
|
||||
|
||||
// let the assignment handle the incoming datagrams for its duration
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment,
|
||||
&ThreadedAssignment::readPendingDatagrams);
|
||||
|
||||
// Starts an event loop, and emits workerThread->started()
|
||||
workerThread->start();
|
||||
} else {
|
||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
|
@ -170,10 +164,14 @@ void AssignmentClient::assignmentCompleted() {
|
|||
|
||||
qDebug("Assignment finished or never started - waiting for new assignment.");
|
||||
|
||||
_currentAssignment = NULL;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
// have us handle incoming NodeList datagrams again
|
||||
disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0);
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
|
||||
_currentAssignment = NULL;
|
||||
|
||||
// reset our NodeList by switching back to unassigned and clearing the list
|
||||
nodeList->setOwnerType(NodeType::Unassigned);
|
||||
nodeList->reset();
|
||||
|
|
|
@ -207,31 +207,25 @@ void AudioMixer::prepareMixForListeningNode(Node* node) {
|
|||
}
|
||||
|
||||
|
||||
void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
PacketType mixerPacketType = packetTypeForPacket(dataByteArray);
|
||||
if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
|
||||
|| mixerPacketType == PacketTypeMicrophoneAudioWithEcho
|
||||
|| mixerPacketType == PacketTypeInjectAudio) {
|
||||
QUuid nodeUUID;
|
||||
deconstructPacketHeader(dataByteArray, nodeUUID);
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
SharedNodePointer matchingNode = nodeList->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (matchingNode) {
|
||||
nodeList->updateNodeWithData(matchingNode.data(), senderSockAddr, dataByteArray);
|
||||
|
||||
if (!matchingNode->getActiveSocket()) {
|
||||
// we don't have an active socket for this node, but they're talking to us
|
||||
// this means they've heard from us and can reply, let's assume public is active
|
||||
matchingNode->activatePublicSocket();
|
||||
void AudioMixer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
PacketType mixerPacketType = packetTypeForPacket(receivedPacket);
|
||||
if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho
|
||||
|| mixerPacketType == PacketTypeMicrophoneAudioWithEcho
|
||||
|| mixerPacketType == PacketTypeInjectAudio) {
|
||||
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, dataByteArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,9 +273,7 @@ void AudioMixer::run() {
|
|||
prepareMixForListeningNode(node.data());
|
||||
|
||||
memcpy(clientPacket + numBytesPacketHeader, _clientSamples, sizeof(_clientSamples));
|
||||
nodeList->getNodeSocket().writeDatagram((char*) clientPacket, sizeof(clientPacket),
|
||||
node->getActiveSocket()->getAddress(),
|
||||
node->getActiveSocket()->getPort());
|
||||
nodeList->writeDatagram((char*) clientPacket, sizeof(clientPacket), node);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ public slots:
|
|||
/// threaded run of assignment
|
||||
void run();
|
||||
|
||||
void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
|
||||
void readPendingDatagrams();
|
||||
private:
|
||||
/// adds one buffer to the mix for a listening node
|
||||
void addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// nodes, and broadcasts that data back to them, every BROADCAST_INTERVAL ms.
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <Logging.h>
|
||||
|
@ -19,7 +20,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
#include "AvatarMixer.h"
|
||||
|
||||
|
@ -36,7 +37,7 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) :
|
|||
|
||||
void attachAvatarDataToNode(Node* newNode) {
|
||||
if (newNode->getLinkedData() == NULL) {
|
||||
newNode->setLinkedData(new AvatarData());
|
||||
newNode->setLinkedData(new AvatarMixerClientData());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,8 +53,6 @@ void broadcastAvatarData() {
|
|||
|
||||
int numPacketHeaderBytes = populatePacketHeader(mixedAvatarByteArray, PacketTypeBulkAvatarData);
|
||||
|
||||
int packetsSent = 0;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
|
@ -70,15 +69,11 @@ void broadcastAvatarData() {
|
|||
QByteArray avatarByteArray;
|
||||
avatarByteArray.append(otherNode->getUUID().toRfc4122());
|
||||
|
||||
AvatarData* nodeData = (AvatarData*) otherNode->getLinkedData();
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||
avatarByteArray.append(nodeData->toByteArray());
|
||||
|
||||
if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) {
|
||||
packetsSent++;
|
||||
//printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
|
||||
nodeList->getNodeSocket().writeDatagram(mixedAvatarByteArray,
|
||||
node->getActiveSocket()->getAddress(),
|
||||
node->getActiveSocket()->getPort());
|
||||
nodeList->writeDatagram(mixedAvatarByteArray, node);
|
||||
|
||||
// reset the packet
|
||||
mixedAvatarByteArray.resize(numPacketHeaderBytes);
|
||||
|
@ -89,15 +84,45 @@ void broadcastAvatarData() {
|
|||
}
|
||||
}
|
||||
|
||||
packetsSent++;
|
||||
//printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
|
||||
nodeList->getNodeSocket().writeDatagram(mixedAvatarByteArray,
|
||||
node->getActiveSocket()->getAddress(),
|
||||
node->getActiveSocket()->getPort());
|
||||
nodeList->writeDatagram(mixedAvatarByteArray, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void broadcastIdentityPacket() {
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
QByteArray avatarIdentityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity);
|
||||
int numPacketHeaderBytes = avatarIdentityPacket.size();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (node->getLinkedData() && node->getType() == NodeType::Agent) {
|
||||
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
QByteArray individualData = nodeData->identityByteArray();
|
||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, node->getUUID().toRfc4122());
|
||||
|
||||
if (avatarIdentityPacket.size() + individualData.size() > MAX_PACKET_SIZE) {
|
||||
// we've hit MTU, send out the current packet before appending
|
||||
nodeList->broadcastToNodes(avatarIdentityPacket, NodeSet() << NodeType::Agent);
|
||||
avatarIdentityPacket.resize(numPacketHeaderBytes);
|
||||
}
|
||||
|
||||
// append the individual data to the current the avatarIdentityPacket
|
||||
avatarIdentityPacket.append(individualData);
|
||||
|
||||
// re-set the bool in AvatarMixerClientData so a change between key frames gets sent out
|
||||
nodeData->setHasSentIdentityBetweenKeyFrames(false);
|
||||
}
|
||||
}
|
||||
|
||||
// send out the final packet
|
||||
if (avatarIdentityPacket.size() > numPacketHeaderBytes) {
|
||||
nodeList->broadcastToNodes(avatarIdentityPacket, NodeSet() << NodeType::Agent);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
||||
if (killedNode->getType() == NodeType::Agent
|
||||
&& killedNode->getLinkedData()) {
|
||||
|
@ -111,37 +136,56 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
||||
void AvatarMixer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
switch (packetTypeForPacket(dataByteArray)) {
|
||||
case PacketTypeAvatarData: {
|
||||
QUuid nodeUUID;
|
||||
deconstructPacketHeader(dataByteArray, nodeUUID);
|
||||
|
||||
// add or update the node in our list
|
||||
SharedNodePointer avatarNode = nodeList->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (avatarNode) {
|
||||
// parse positional data from an node
|
||||
nodeList->updateNodeWithData(avatarNode.data(), senderSockAddr, dataByteArray);
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
switch (packetTypeForPacket(receivedPacket)) {
|
||||
case PacketTypeAvatarData: {
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
break;
|
||||
}
|
||||
case PacketTypeAvatarIdentity: {
|
||||
|
||||
// check if we have a matching node in our list
|
||||
SharedNodePointer avatarNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
|
||||
if (avatarNode && avatarNode->getLinkedData()) {
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||
if (nodeData->hasIdentityChangedAfterParsing(receivedPacket)
|
||||
&& !nodeData->hasSentIdentityBetweenKeyFrames()) {
|
||||
// this avatar changed their identity in some way and we haven't sent a packet in this keyframe
|
||||
QByteArray identityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity);
|
||||
|
||||
QByteArray individualByteArray = nodeData->identityByteArray();
|
||||
individualByteArray.replace(0, NUM_BYTES_RFC4122_UUID, avatarNode->getUUID().toRfc4122());
|
||||
|
||||
identityPacket.append(individualByteArray);
|
||||
|
||||
nodeData->setHasSentIdentityBetweenKeyFrames(true);
|
||||
nodeList->broadcastToNodes(identityPacket, NodeSet() << NodeType::Agent);
|
||||
}
|
||||
}
|
||||
}
|
||||
case PacketTypeKillAvatar: {
|
||||
nodeList->processKillNode(receivedPacket);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// hand this off to the NodeList
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketTypeKillAvatar: {
|
||||
nodeList->processKillNode(dataByteArray);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// hand this off to the NodeList
|
||||
nodeList->processNodeData(senderSockAddr, dataByteArray);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const qint64 AVATAR_IDENTITY_KEYFRAME_MSECS = 5000;
|
||||
|
||||
void AvatarMixer::run() {
|
||||
commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer);
|
||||
|
||||
|
@ -155,6 +199,9 @@ void AvatarMixer::run() {
|
|||
|
||||
gettimeofday(&startTime, NULL);
|
||||
|
||||
QElapsedTimer identityTimer;
|
||||
identityTimer.start();
|
||||
|
||||
while (!_isFinished) {
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
|
@ -165,6 +212,14 @@ void AvatarMixer::run() {
|
|||
|
||||
broadcastAvatarData();
|
||||
|
||||
if (identityTimer.elapsed() >= AVATAR_IDENTITY_KEYFRAME_MSECS) {
|
||||
// it's time to broadcast the keyframe identity packets
|
||||
broadcastIdentityPacket();
|
||||
|
||||
// restart the timer so we do it again in AVATAR_IDENTITY_KEYFRAME_MSECS
|
||||
identityTimer.restart();
|
||||
}
|
||||
|
||||
int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow();
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
|
|
|
@ -20,9 +20,10 @@ public slots:
|
|||
/// runs the avatar mixer
|
||||
void run();
|
||||
|
||||
void nodeAdded(SharedNodePointer nodeAdded);
|
||||
void nodeKilled(SharedNodePointer killedNode);
|
||||
|
||||
void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
|
||||
void readPendingDatagrams();
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AvatarMixer__) */
|
||||
|
|
15
assignment-client/src/avatars/AvatarMixerClientData.cpp
Normal file
15
assignment-client/src/avatars/AvatarMixerClientData.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// AvatarMixerClientData.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/4/2014.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
AvatarMixerClientData::AvatarMixerClientData() :
|
||||
_hasSentIdentityBetweenKeyFrames(false)
|
||||
{
|
||||
|
||||
}
|
29
assignment-client/src/avatars/AvatarMixerClientData.h
Normal file
29
assignment-client/src/avatars/AvatarMixerClientData.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// AvatarMixerClientData.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/4/2014.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__AvatarMixerClientData__
|
||||
#define __hifi__AvatarMixerClientData__
|
||||
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
#include <AvatarData.h>
|
||||
|
||||
class AvatarMixerClientData : public AvatarData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AvatarMixerClientData();
|
||||
|
||||
bool hasSentIdentityBetweenKeyFrames() const { return _hasSentIdentityBetweenKeyFrames; }
|
||||
void setHasSentIdentityBetweenKeyFrames(bool hasSentIdentityBetweenKeyFrames)
|
||||
{ _hasSentIdentityBetweenKeyFrames = hasSentIdentityBetweenKeyFrames; }
|
||||
private:
|
||||
|
||||
bool _hasSentIdentityBetweenKeyFrames;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AvatarMixerClientData__) */
|
|
@ -41,15 +41,27 @@ void MetavoxelServer::run() {
|
|||
_sendTimer.start(SEND_INTERVAL);
|
||||
}
|
||||
|
||||
void MetavoxelServer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
||||
switch (dataByteArray.at(0)) {
|
||||
case PacketTypeMetavoxelData:
|
||||
processData(dataByteArray, senderSockAddr);
|
||||
break;
|
||||
|
||||
default:
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, dataByteArray);
|
||||
break;
|
||||
void MetavoxelServer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
switch (packetTypeForPacket(receivedPacket)) {
|
||||
case PacketTypeMetavoxelData: {
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (matchingNode) {
|
||||
processData(receivedPacket, matchingNode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,10 +79,10 @@ void MetavoxelServer::sendDeltas() {
|
|||
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - elapsed));
|
||||
}
|
||||
|
||||
void MetavoxelServer::processData(const QByteArray& data, const HifiSockAddr& sender) {
|
||||
void MetavoxelServer::processData(const QByteArray& data, const SharedNodePointer& sendingNode) {
|
||||
// read the session id
|
||||
int headerPlusIDSize;
|
||||
QUuid sessionID = readSessionID(data, sender, headerPlusIDSize);
|
||||
QUuid sessionID = readSessionID(data, sendingNode, headerPlusIDSize);
|
||||
if (sessionID.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
@ -78,18 +90,19 @@ void MetavoxelServer::processData(const QByteArray& data, const HifiSockAddr& se
|
|||
// forward to session, creating if necessary
|
||||
MetavoxelSession*& session = _sessions[sessionID];
|
||||
if (!session) {
|
||||
session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize), sender);
|
||||
session = new MetavoxelSession(this, sessionID, QByteArray::fromRawData(data.constData(), headerPlusIDSize),
|
||||
sendingNode);
|
||||
}
|
||||
session->receivedData(data, sender);
|
||||
session->receivedData(data, sendingNode);
|
||||
}
|
||||
|
||||
MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId,
|
||||
const QByteArray& datagramHeader, const HifiSockAddr& sender) :
|
||||
const QByteArray& datagramHeader, const SharedNodePointer& sendingNode) :
|
||||
QObject(server),
|
||||
_server(server),
|
||||
_sessionId(sessionId),
|
||||
_sequencer(datagramHeader),
|
||||
_sender(sender) {
|
||||
_sendingNode(sendingNode) {
|
||||
|
||||
const int TIMEOUT_INTERVAL = 30 * 1000;
|
||||
_timeoutTimer.setInterval(TIMEOUT_INTERVAL);
|
||||
|
@ -105,15 +118,15 @@ MetavoxelSession::MetavoxelSession(MetavoxelServer* server, const QUuid& session
|
|||
SendRecord record = { 0 };
|
||||
_sendRecords.append(record);
|
||||
|
||||
qDebug() << "Opened session [sessionId=" << _sessionId << ", sender=" << _sender << "]";
|
||||
qDebug() << "Opened session [sessionId=" << _sessionId << ", sendingNode=" << sendingNode << "]";
|
||||
}
|
||||
|
||||
void MetavoxelSession::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
|
||||
void MetavoxelSession::receivedData(const QByteArray& data, const SharedNodePointer& sendingNode) {
|
||||
// reset the timeout timer
|
||||
_timeoutTimer.start();
|
||||
|
||||
// save the most recent sender
|
||||
_sender = sender;
|
||||
_sendingNode = sendingNode;
|
||||
|
||||
// process through sequencer
|
||||
_sequencer.receivedDatagram(data);
|
||||
|
@ -131,12 +144,12 @@ void MetavoxelSession::sendDelta() {
|
|||
}
|
||||
|
||||
void MetavoxelSession::timedOut() {
|
||||
qDebug() << "Session timed out [sessionId=" << _sessionId << ", sender=" << _sender << "]";
|
||||
qDebug() << "Session timed out [sessionId=" << _sessionId << ", sendingNode=" << _sendingNode << "]";
|
||||
_server->removeSession(_sessionId);
|
||||
}
|
||||
|
||||
void MetavoxelSession::sendData(const QByteArray& data) {
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram(data, _sender.getAddress(), _sender.getPort());
|
||||
NodeList::getInstance()->writeDatagram(data, _sendingNode);
|
||||
}
|
||||
|
||||
void MetavoxelSession::readPacket(Bitstream& in) {
|
||||
|
@ -152,7 +165,7 @@ void MetavoxelSession::clearSendRecordsBefore(int index) {
|
|||
void MetavoxelSession::handleMessage(const QVariant& message) {
|
||||
int userType = message.userType();
|
||||
if (userType == CloseSessionMessage::Type) {
|
||||
qDebug() << "Session closed [sessionId=" << _sessionId << ", sender=" << _sender << "]";
|
||||
qDebug() << "Session closed [sessionId=" << _sessionId << ", sendingNode=" << _sendingNode << "]";
|
||||
_server->removeSession(_sessionId);
|
||||
|
||||
} else if (userType == ClientStateMessage::Type) {
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
|
||||
virtual void run();
|
||||
|
||||
virtual void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
|
||||
virtual void readPendingDatagrams();
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -47,7 +47,7 @@ private slots:
|
|||
|
||||
private:
|
||||
|
||||
void processData(const QByteArray& data, const HifiSockAddr& sender);
|
||||
void processData(const QByteArray& data, const SharedNodePointer& sendingNode);
|
||||
|
||||
QTimer _sendTimer;
|
||||
qint64 _lastSend;
|
||||
|
@ -64,9 +64,9 @@ class MetavoxelSession : public QObject {
|
|||
public:
|
||||
|
||||
MetavoxelSession(MetavoxelServer* server, const QUuid& sessionId,
|
||||
const QByteArray& datagramHeader, const HifiSockAddr& sender);
|
||||
const QByteArray& datagramHeader, const SharedNodePointer& sendingNode);
|
||||
|
||||
void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
||||
void receivedData(const QByteArray& data, const SharedNodePointer& sendingNode);
|
||||
|
||||
void sendDelta();
|
||||
|
||||
|
@ -96,7 +96,7 @@ private:
|
|||
QTimer _timeoutTimer;
|
||||
DatagramSequencer _sequencer;
|
||||
|
||||
HifiSockAddr _sender;
|
||||
SharedNodePointer _sendingNode;
|
||||
|
||||
glm::vec3 _position;
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ void OctreeInboundPacketProcessor::resetStats() {
|
|||
}
|
||||
|
||||
|
||||
void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||
void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
|
||||
bool debugProcessPacket = _myServer->wantsVerboseDebug();
|
||||
|
||||
|
@ -55,8 +55,6 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
|
|||
if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
|
||||
PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket);
|
||||
_receivedPacketCount++;
|
||||
|
||||
SharedNodePointer senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
|
||||
|
||||
const unsigned char* packetData = reinterpret_cast<const unsigned char*>(packet.data());
|
||||
|
||||
|
@ -90,7 +88,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
|
|||
int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType,
|
||||
reinterpret_cast<const unsigned char*>(packet.data()),
|
||||
packet.size(),
|
||||
editData, maxSize, senderNode.data());
|
||||
editData, maxSize, sendingNode);
|
||||
_myServer->getOctree()->unlock();
|
||||
quint64 endProcess = usecTimestampNow();
|
||||
|
||||
|
@ -113,9 +111,9 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA
|
|||
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
QUuid& nodeUUID = DEFAULT_NODE_ID_REF;
|
||||
if (senderNode) {
|
||||
senderNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
nodeUUID = senderNode->getUUID();
|
||||
if (sendingNode) {
|
||||
sendingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
nodeUUID = sendingNode->getUUID();
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << "sender has uuid=" << nodeUUID;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; }
|
||||
|
||||
protected:
|
||||
virtual void processPacket(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
|
||||
private:
|
||||
void trackInboundPackets(const QUuid& nodeUUID, int sequence, quint64 transitTime,
|
||||
|
|
|
@ -48,7 +48,7 @@ bool OctreeSendThread::process() {
|
|||
if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) {
|
||||
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
||||
}
|
||||
packetsSent = packetDistributor(node.data(), nodeData, viewFrustumChanged);
|
||||
packetsSent = packetDistributor(node, nodeData, viewFrustumChanged);
|
||||
}
|
||||
|
||||
node->getMutex().unlock(); // we're done with this node for now.
|
||||
|
@ -86,7 +86,7 @@ quint64 OctreeSendThread::_totalBytes = 0;
|
|||
quint64 OctreeSendThread::_totalWastedBytes = 0;
|
||||
quint64 OctreeSendThread::_totalPackets = 0;
|
||||
|
||||
int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) {
|
||||
int OctreeSendThread::handlePacketSend(const SharedNodePointer& node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) {
|
||||
bool debug = _myServer->wantsDebugSending();
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
|
@ -142,15 +142,11 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
|||
}
|
||||
|
||||
// actually send it
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
|
||||
nodeAddress->getAddress(),
|
||||
nodeAddress->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, SharedNodePointer(node));
|
||||
packetSent = true;
|
||||
} else {
|
||||
// not enough room in the packet, send two packets
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) statsMessage, statsMessageLength,
|
||||
nodeAddress->getAddress(),
|
||||
nodeAddress->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, SharedNodePointer(node));
|
||||
|
||||
// since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since
|
||||
// there was nothing else to send.
|
||||
|
@ -168,9 +164,8 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
|||
truePacketsSent++;
|
||||
packetsSent++;
|
||||
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
|
||||
nodeAddress->getAddress(),
|
||||
nodeAddress->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
|
||||
SharedNodePointer(node));
|
||||
|
||||
packetSent = true;
|
||||
|
||||
|
@ -189,9 +184,8 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
|||
// If there's actually a packet waiting, then send it.
|
||||
if (nodeData->isPacketWaiting()) {
|
||||
// just send the voxel packet
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
|
||||
nodeAddress->getAddress(),
|
||||
nodeAddress->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
|
||||
SharedNodePointer(node));
|
||||
packetSent = true;
|
||||
|
||||
int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();
|
||||
|
@ -218,7 +212,7 @@ int OctreeSendThread::handlePacketSend(Node* node, OctreeQueryNode* nodeData, in
|
|||
}
|
||||
|
||||
/// Version of voxel distributor that sends the deepest LOD level at once
|
||||
int OctreeSendThread::packetDistributor(Node* node, OctreeQueryNode* nodeData, bool viewFrustumChanged) {
|
||||
int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged) {
|
||||
bool forceDebugging = false;
|
||||
|
||||
int truePacketsSent = 0;
|
||||
|
|
|
@ -36,8 +36,8 @@ private:
|
|||
QUuid _nodeUUID;
|
||||
OctreeServer* _myServer;
|
||||
|
||||
int handlePacketSend(Node* node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
|
||||
int packetDistributor(Node* node, OctreeQueryNode* nodeData, bool viewFrustumChanged);
|
||||
int handlePacketSend(const SharedNodePointer& node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
|
||||
int packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged);
|
||||
|
||||
OctreePacketData _packetData;
|
||||
};
|
||||
|
|
|
@ -458,43 +458,43 @@ void OctreeServer::parsePayload() {
|
|||
}
|
||||
}
|
||||
|
||||
void OctreeServer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) {
|
||||
void OctreeServer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
PacketType packetType = packetTypeForPacket(dataByteArray);
|
||||
|
||||
if (packetType == getMyQueryMessageType()) {
|
||||
bool debug = false;
|
||||
if (debug) {
|
||||
qDebug() << "Got PacketType_VOXEL_QUERY at" << usecTimestampNow();
|
||||
}
|
||||
|
||||
// If we got a PacketType_VOXEL_QUERY, then we're talking to an NodeType_t_AVATAR, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
QUuid nodeUUID;
|
||||
deconstructPacketHeader(dataByteArray, nodeUUID);
|
||||
|
||||
SharedNodePointer node = nodeList->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (node) {
|
||||
nodeList->updateNodeWithData(node.data(), senderSockAddr, dataByteArray);
|
||||
if (!node->getActiveSocket()) {
|
||||
// we don't have an active socket for this node, but they're talking to us
|
||||
// this means they've heard from us and can reply, let's assume public is active
|
||||
node->activatePublicSocket();
|
||||
}
|
||||
OctreeQueryNode* nodeData = (OctreeQueryNode*) node->getLinkedData();
|
||||
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
|
||||
nodeData->initializeOctreeSendThread(this, nodeUUID);
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType packetType = packetTypeForPacket(receivedPacket);
|
||||
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
|
||||
if (packetType == getMyQueryMessageType()) {
|
||||
bool debug = false;
|
||||
if (debug) {
|
||||
qDebug() << "Got PacketTypeVoxelQuery at" << usecTimestampNow();
|
||||
}
|
||||
|
||||
// If we got a PacketType_VOXEL_QUERY, then we're talking to an NodeType_t_AVATAR, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
if (matchingNode) {
|
||||
nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
|
||||
|
||||
OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();
|
||||
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
|
||||
nodeData->initializeOctreeSendThread(this, matchingNode->getUUID());
|
||||
}
|
||||
}
|
||||
} else if (packetType == PacketTypeJurisdictionRequest) {
|
||||
_jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket);
|
||||
} else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
|
||||
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
} else if (packetType == PacketTypeJurisdictionRequest) {
|
||||
_jurisdictionSender->queueReceivedPacket(senderSockAddr, dataByteArray);
|
||||
} else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
|
||||
_octreeInboundPacketProcessor->queueReceivedPacket(senderSockAddr, dataByteArray);
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, dataByteArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,8 +655,4 @@ void OctreeServer::run() {
|
|||
QTimer* silentNodeTimer = new QTimer(this);
|
||||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
||||
|
||||
QTimer* pingNodesTimer = new QTimer(this);
|
||||
connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes()));
|
||||
pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000);
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ public:
|
|||
|
||||
// subclass may implement these method
|
||||
virtual void beforeRun() { };
|
||||
virtual bool hasSpecialPacketToSend(Node* node) { return false; }
|
||||
virtual int sendSpecialPacket(Node* node) { return 0; }
|
||||
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node) { return false; }
|
||||
virtual int sendSpecialPacket(const SharedNodePointer& node) { return 0; }
|
||||
|
||||
static void attachQueryNodeToNode(Node* newNode);
|
||||
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
public slots:
|
||||
/// runs the voxel server assignment
|
||||
void run();
|
||||
void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr);
|
||||
void readPendingDatagrams();
|
||||
|
||||
protected:
|
||||
void parsePayload();
|
||||
|
|
|
@ -43,7 +43,7 @@ void ParticleServer::beforeRun() {
|
|||
pruneDeletedParticlesTimer->start(PRUNE_DELETED_PARTICLES_INTERVAL_MSECS);
|
||||
}
|
||||
|
||||
void ParticleServer::particleCreated(const Particle& newParticle, Node* node) {
|
||||
void ParticleServer::particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode) {
|
||||
unsigned char outputBuffer[MAX_PACKET_SIZE];
|
||||
unsigned char* copyAt = outputBuffer;
|
||||
|
||||
|
@ -63,14 +63,12 @@ void ParticleServer::particleCreated(const Particle& newParticle, Node* node) {
|
|||
copyAt += sizeof(particleID);
|
||||
packetLength += sizeof(particleID);
|
||||
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) outputBuffer, packetLength,
|
||||
node->getActiveSocket()->getAddress(),
|
||||
node->getActiveSocket()->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
||||
}
|
||||
|
||||
|
||||
// ParticleServer will use the "special packets" to send list of recently deleted particles
|
||||
bool ParticleServer::hasSpecialPacketToSend(Node* node) {
|
||||
bool ParticleServer::hasSpecialPacketToSend(const SharedNodePointer& node) {
|
||||
bool shouldSendDeletedParticles = false;
|
||||
|
||||
// check to see if any new particles have been added since we last sent to this node...
|
||||
|
@ -85,7 +83,7 @@ bool ParticleServer::hasSpecialPacketToSend(Node* node) {
|
|||
return shouldSendDeletedParticles;
|
||||
}
|
||||
|
||||
int ParticleServer::sendSpecialPacket(Node* node) {
|
||||
int ParticleServer::sendSpecialPacket(const SharedNodePointer& node) {
|
||||
unsigned char outputBuffer[MAX_PACKET_SIZE];
|
||||
size_t packetLength = 0;
|
||||
|
||||
|
@ -104,9 +102,7 @@ int ParticleServer::sendSpecialPacket(Node* node) {
|
|||
|
||||
//qDebug() << "sending PacketType_PARTICLE_ERASE packetLength:" << packetLength;
|
||||
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) outputBuffer, packetLength,
|
||||
node->getActiveSocket()->getAddress(),
|
||||
node->getActiveSocket()->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node));
|
||||
}
|
||||
|
||||
nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt);
|
||||
|
|
|
@ -34,10 +34,10 @@ public:
|
|||
|
||||
// subclass may implement these method
|
||||
virtual void beforeRun();
|
||||
virtual bool hasSpecialPacketToSend(Node* node);
|
||||
virtual int sendSpecialPacket(Node* node);
|
||||
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node);
|
||||
virtual int sendSpecialPacket(const SharedNodePointer& node);
|
||||
|
||||
virtual void particleCreated(const Particle& newParticle, Node* senderNode);
|
||||
virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode);
|
||||
|
||||
public slots:
|
||||
void pruneDeletedParticles();
|
||||
|
|
|
@ -32,12 +32,12 @@ Octree* VoxelServer::createTree() {
|
|||
return new VoxelTree(true);
|
||||
}
|
||||
|
||||
bool VoxelServer::hasSpecialPacketToSend(Node* node) {
|
||||
bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) {
|
||||
bool shouldSendEnvironments = _sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, OCTREE_SEND_INTERVAL_USECS);
|
||||
return shouldSendEnvironments;
|
||||
}
|
||||
|
||||
int VoxelServer::sendSpecialPacket(Node* node) {
|
||||
int VoxelServer::sendSpecialPacket(const SharedNodePointer& node) {
|
||||
int numBytesPacketHeader = populatePacketHeader(reinterpret_cast<char*>(_tempOutputBuffer), PacketTypeEnvironmentData);
|
||||
int envPacketLength = numBytesPacketHeader;
|
||||
int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount();
|
||||
|
@ -46,9 +46,7 @@ int VoxelServer::sendSpecialPacket(Node* node) {
|
|||
envPacketLength += getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength);
|
||||
}
|
||||
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram((char*) _tempOutputBuffer, envPacketLength,
|
||||
node->getActiveSocket()->getAddress(),
|
||||
node->getActiveSocket()->getPort());
|
||||
NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node));
|
||||
return envPacketLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ public:
|
|||
|
||||
// subclass may implement these method
|
||||
virtual void beforeRun();
|
||||
virtual bool hasSpecialPacketToSend(Node* node);
|
||||
virtual int sendSpecialPacket(Node* node);
|
||||
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node);
|
||||
virtual int sendSpecialPacket(const SharedNodePointer& node);
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -66,7 +66,7 @@ void DataServer::readPendingDatagrams() {
|
|||
PacketType requestType = packetTypeForPacket(receivedPacket);
|
||||
|
||||
if ((requestType == PacketTypeDataServerPut || requestType == PacketTypeDataServerGet) &&
|
||||
packetVersionMatch(receivedPacket)) {
|
||||
receivedPacket[numBytesArithmeticCodingFromBuffer(receivedPacket.data())] == versionForPacketType(requestType)) {
|
||||
|
||||
QDataStream packetStream(receivedPacket);
|
||||
int numReceivedHeaderBytes = numBytesForPacketHeader(receivedPacket);
|
||||
|
|
|
@ -23,8 +23,8 @@ $(document).ready(function(){
|
|||
|
||||
$.each(json.queued, function (uuid, data) {
|
||||
queuedTableBody += "<tr>";
|
||||
queuedTableBody += "<td>" + uuid + "</td>";
|
||||
queuedTableBody += "<td>" + data.type + "</td>";
|
||||
queuedTableBody += "<td>" + uuid + "</td>";
|
||||
queuedTableBody += "<td>" + (data.pool ? data.pool : "") + "</td>";
|
||||
queuedTableBody += "</tr>";
|
||||
});
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
#include "DomainServer.h"
|
||||
|
||||
const int RESTART_HOLD_TIME_MSECS = 5 * 1000;
|
||||
|
@ -57,8 +59,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
populateDefaultStaticAssignmentsExcludingTypes(parsedTypes);
|
||||
|
||||
NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort);
|
||||
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), this, SLOT(nodeKilled(SharedNodePointer)));
|
||||
|
||||
connect(nodeList, &NodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
||||
connect(nodeList, &NodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
||||
|
||||
QTimer* silentNodeTimer = new QTimer(this);
|
||||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||
|
@ -209,6 +212,10 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
}
|
||||
}
|
||||
|
||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer
|
||||
<< NodeType::MetavoxelServer;
|
||||
|
||||
void DomainServer::readAvailableDatagrams() {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
|
@ -222,14 +229,14 @@ void DomainServer::readAvailableDatagrams() {
|
|||
|
||||
QByteArray receivedPacket;
|
||||
NodeType_t nodeType;
|
||||
QUuid nodeUUID;
|
||||
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
if (packetVersionMatch(receivedPacket)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType requestType = packetTypeForPacket(receivedPacket);
|
||||
if (requestType == PacketTypeDomainListRequest) {
|
||||
|
||||
|
@ -237,7 +244,7 @@ void DomainServer::readAvailableDatagrams() {
|
|||
QDataStream packetStream(receivedPacket);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||
|
||||
deconstructPacketHeader(receivedPacket, nodeUUID);
|
||||
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
|
||||
|
||||
packetStream >> nodeType;
|
||||
packetStream >> nodePublicAddress >> nodeLocalAddress;
|
||||
|
@ -255,18 +262,20 @@ void DomainServer::readAvailableDatagrams() {
|
|||
}
|
||||
}
|
||||
|
||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer
|
||||
<< NodeType::MetavoxelServer;
|
||||
|
||||
SharedAssignmentPointer matchingStaticAssignment;
|
||||
|
||||
// check if this is a non-statically assigned node, a node that is assigned and checking in for the first time
|
||||
// or a node that has already checked in and is continuing to report for duty
|
||||
if (!STATICALLY_ASSIGNED_NODES.contains(nodeType)
|
||||
|| (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
|
||||
|| nodeList->getInstance()->nodeWithUUID(nodeUUID))
|
||||
{
|
||||
|| nodeList->getInstance()->nodeWithUUID(nodeUUID)) {
|
||||
|
||||
if (nodeUUID.isNull()) {
|
||||
// this is a check in from an unidentified node
|
||||
// we need to generate a session UUID for this node
|
||||
nodeUUID = QUuid::createUuid();
|
||||
}
|
||||
|
||||
SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID,
|
||||
nodeType,
|
||||
nodePublicAddress,
|
||||
|
@ -291,16 +300,37 @@ void DomainServer::readAvailableDatagrams() {
|
|||
NodeType_t* nodeTypesOfInterest = reinterpret_cast<NodeType_t*>(receivedPacket.data()
|
||||
+ packetStream.device()->pos());
|
||||
|
||||
// always send the node their own UUID back
|
||||
QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append);
|
||||
broadcastDataStream << checkInNode->getUUID();
|
||||
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(checkInNode->getLinkedData());
|
||||
|
||||
if (numInterestTypes > 0) {
|
||||
QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append);
|
||||
|
||||
// if the node has sent no types of interest, assume they want nothing but their own ID back
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (node->getUUID() != nodeUUID &&
|
||||
memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) {
|
||||
// if the node has any interest types, send back those nodes as well
|
||||
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
||||
if (otherNode->getUUID() != nodeUUID &&
|
||||
memchr(nodeTypesOfInterest, otherNode->getType(), numInterestTypes)) {
|
||||
|
||||
// don't send avatar nodes to other avatars, that will come from avatar mixer
|
||||
broadcastDataStream << *node.data();
|
||||
broadcastDataStream << *otherNode.data();
|
||||
|
||||
// pack the secret that these two nodes will use to communicate with each other
|
||||
QUuid secretUUID = nodeData->getSessionSecretHash().value(otherNode->getUUID());
|
||||
if (secretUUID.isNull()) {
|
||||
// generate a new secret UUID these two nodes can use
|
||||
secretUUID = QUuid::createUuid();
|
||||
|
||||
// set that on the current Node's sessionSecretHash
|
||||
nodeData->getSessionSecretHash().insert(otherNode->getUUID(), secretUUID);
|
||||
|
||||
// set it on the other Node's sessionSecretHash
|
||||
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())
|
||||
->getSessionSecretHash().insert(nodeUUID, secretUUID);
|
||||
|
||||
}
|
||||
|
||||
broadcastDataStream << secretUUID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +374,7 @@ void DomainServer::readAvailableDatagrams() {
|
|||
}
|
||||
}
|
||||
|
||||
QJsonObject jsonForSocket(const HifiSockAddr& socket) {
|
||||
QJsonObject DomainServer::jsonForSocket(const HifiSockAddr& socket) {
|
||||
QJsonObject socketJSON;
|
||||
|
||||
socketJSON["ip"] = socket.getAddress().toString();
|
||||
|
@ -358,7 +388,7 @@ const char JSON_KEY_PUBLIC_SOCKET[] = "public";
|
|||
const char JSON_KEY_LOCAL_SOCKET[] = "local";
|
||||
const char JSON_KEY_POOL[] = "pool";
|
||||
|
||||
QJsonObject jsonObjectForNode(Node* node) {
|
||||
QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) {
|
||||
QJsonObject nodeJson;
|
||||
|
||||
// re-format the type name so it matches the target name
|
||||
|
@ -372,12 +402,13 @@ QJsonObject jsonObjectForNode(Node* node) {
|
|||
// add the node socket information
|
||||
nodeJson[JSON_KEY_PUBLIC_SOCKET] = jsonForSocket(node->getPublicSocket());
|
||||
nodeJson[JSON_KEY_LOCAL_SOCKET] = jsonForSocket(node->getLocalSocket());
|
||||
|
||||
|
||||
// if the node has pool information, add it
|
||||
if (node->getLinkedData() && !((Assignment*) node->getLinkedData())->getPool().isEmpty()) {
|
||||
nodeJson[JSON_KEY_POOL] = ((Assignment*) node->getLinkedData())->getPool();
|
||||
SharedAssignmentPointer matchingAssignment = _staticAssignmentHash.value(node->getUUID());
|
||||
if (matchingAssignment) {
|
||||
nodeJson[JSON_KEY_POOL] = matchingAssignment->getPool();
|
||||
}
|
||||
|
||||
|
||||
return nodeJson;
|
||||
}
|
||||
|
||||
|
@ -397,10 +428,10 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString&
|
|||
|
||||
// enumerate the NodeList to find the assigned nodes
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getLinkedData()) {
|
||||
if (_staticAssignmentHash.value(node->getUUID())) {
|
||||
// add the node using the UUID as the key
|
||||
QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
|
||||
assignedNodesJSON[uuidString] = jsonObjectForNode(node.data());
|
||||
assignedNodesJSON[uuidString] = jsonObjectForNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,7 +474,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString&
|
|||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
// add the node using the UUID as the key
|
||||
QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
|
||||
nodesJSON[uuidString] = jsonObjectForNode(node.data());
|
||||
nodesJSON[uuidString] = jsonObjectForNode(node);
|
||||
}
|
||||
|
||||
rootJSON["nodes"] = nodesJSON;
|
||||
|
@ -546,6 +577,11 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer&
|
|||
_staticAssignmentHash.remove(oldUUID);
|
||||
}
|
||||
|
||||
void DomainServer::nodeAdded(SharedNodePointer node) {
|
||||
// we don't use updateNodeWithData, so add the DomainServerNodeData to the node here
|
||||
node->setLinkedData(new DomainServerNodeData());
|
||||
}
|
||||
|
||||
void DomainServer::nodeKilled(SharedNodePointer node) {
|
||||
// if this node's UUID matches a static assignment we need to throw it back in the assignment queue
|
||||
SharedAssignmentPointer matchedAssignment = _staticAssignmentHash.value(node->getUUID());
|
||||
|
@ -553,6 +589,15 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
|
|||
if (matchedAssignment) {
|
||||
refreshStaticAssignmentAndAddToQueue(matchedAssignment);
|
||||
}
|
||||
|
||||
// cleanup the connection secrets that we set up for this node (on the other nodes)
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
foreach (const QUuid& otherNodeSessionUUID, nodeData->getSessionSecretHash().keys()) {
|
||||
SharedNodePointer otherNode = NodeList::getInstance()->nodeWithUUID(otherNodeSessionUUID);
|
||||
if (otherNode) {
|
||||
reinterpret_cast<DomainServerNodeData*>(otherNode->getLinkedData())->getSessionSecretHash().remove(node->getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) {
|
||||
|
|
|
@ -30,7 +30,9 @@ public:
|
|||
void exit(int retCode = 0);
|
||||
|
||||
public slots:
|
||||
/// Called by NodeList to inform us that a node has been killed.
|
||||
/// Called by NodeList to inform us a node has been added
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
/// Called by NodeList to inform us a node has been killed
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
|
||||
private:
|
||||
|
@ -46,6 +48,9 @@ private:
|
|||
void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment);
|
||||
void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment);
|
||||
|
||||
QJsonObject jsonForSocket(const HifiSockAddr& socket);
|
||||
QJsonObject jsonObjectForNode(const SharedNodePointer& node);
|
||||
|
||||
HTTPManager _HTTPManager;
|
||||
|
||||
QHash<QUuid, SharedAssignmentPointer> _staticAssignmentHash;
|
||||
|
|
26
domain-server/src/DomainServerNodeData.h
Normal file
26
domain-server/src/DomainServerNodeData.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// DomainServerNodeData.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 2/6/2014.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__DomainServerNodeData__
|
||||
#define __hifi__DomainServerNodeData__
|
||||
|
||||
#include <QtCore/QHash>
|
||||
|
||||
#include <NodeData.h>
|
||||
|
||||
class DomainServerNodeData : public NodeData {
|
||||
public:
|
||||
DomainServerNodeData() : _sessionSecretHash() {};
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
QHash<QUuid, QUuid>& getSessionSecretHash() { return _sessionSecretHash; }
|
||||
private:
|
||||
QHash<QUuid, QUuid> _sessionSecretHash;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__DomainServerNodeData__) */
|
|
@ -200,10 +200,12 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
audioThread->start();
|
||||
|
||||
connect(nodeList, SIGNAL(domainChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||
|
||||
connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
|
||||
connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
|
||||
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer)));
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
|
||||
connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
|
||||
|
||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||
QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||
|
@ -243,6 +245,11 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
|
||||
silentNodeTimer->moveToThread(_nodeThread);
|
||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
|
||||
|
||||
// send the identity packet for our avatar each second to our avatar mixer
|
||||
QTimer* identityPacketTimer = new QTimer();
|
||||
connect(identityPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendIdentityPacket);
|
||||
identityPacketTimer->start(1000);
|
||||
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
|
||||
|
@ -441,7 +448,7 @@ void Application::paintGL() {
|
|||
_myCamera.setTargetRotation(_myAvatar->getHead().getOrientation());
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||
_myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay
|
||||
_myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
|
||||
_myCamera.setTargetPosition(_myAvatar->getHead().calculateAverageEyePosition());
|
||||
_myCamera.setTargetRotation(_myAvatar->getHead().getCameraOrientation());
|
||||
|
||||
|
@ -1852,12 +1859,6 @@ void Application::init() {
|
|||
}
|
||||
qDebug("Loaded settings");
|
||||
|
||||
if (!_profile.getUsername().isEmpty()) {
|
||||
// we have a username for this avatar, ask the data-server for the mesh URL for this avatar
|
||||
DataServerClient::getValueForKeyAndUserString(DataServerKey::FaceMeshURL, _profile.getUserString(), &_profile);
|
||||
DataServerClient::getValueForKeyAndUserString(DataServerKey::SkeletonURL, _profile.getUserString(), &_profile);
|
||||
}
|
||||
|
||||
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count
|
||||
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
|
||||
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
|
||||
|
@ -1963,8 +1964,13 @@ void Application::updateMouseRay() {
|
|||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMouseRay()");
|
||||
|
||||
_viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(),
|
||||
_mouseRayOrigin, _mouseRayDirection);
|
||||
// if the mouse pointer isn't visible, act like it's at the center of the screen
|
||||
float x = 0.5f, y = 0.5f;
|
||||
if (!_mouseHidden) {
|
||||
x = _mouseX / (float)_glWidget->width();
|
||||
y = _mouseY / (float)_glWidget->height();
|
||||
}
|
||||
_viewFrustum.computePickRay(x, y, _mouseRayOrigin, _mouseRayDirection);
|
||||
|
||||
// adjust for mirroring
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
|
@ -2001,18 +2007,20 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot) {
|
|||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");
|
||||
|
||||
const float FAR_AWAY_STARE = TREE_SCALE;
|
||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||
lookAtSpot = _myCamera.getPosition();
|
||||
|
||||
} else if (_mouseHidden) {
|
||||
// if the mouse cursor is hidden, just look straight ahead
|
||||
glm::vec3 rayOrigin, rayDirection;
|
||||
_viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection);
|
||||
lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE;
|
||||
} else {
|
||||
// just look in direction of the mouse ray
|
||||
lookAtSpot = _mouseRayOrigin + _mouseRayDirection * FAR_AWAY_STARE;
|
||||
// look in direction of the mouse ray, but use distance from intersection, if any
|
||||
float distance = TREE_SCALE;
|
||||
if (_myAvatar->getLookAtTargetAvatar()) {
|
||||
distance = glm::distance(_mouseRayOrigin,
|
||||
static_cast<Avatar*>(_myAvatar->getLookAtTargetAvatar())->getHead().calculateAverageEyePosition());
|
||||
|
||||
} else if (_isHoverVoxel) {
|
||||
distance = glm::distance(_mouseRayOrigin, getMouseVoxelWorldCoordinates(_hoverVoxel));
|
||||
}
|
||||
lookAtSpot = _mouseRayOrigin + _mouseRayDirection * distance;
|
||||
}
|
||||
if (_faceshift.isActive()) {
|
||||
// deflect using Faceshift gaze data
|
||||
|
@ -2544,10 +2552,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
|||
int packetLength = endOfVoxelQueryPacket - voxelQueryPacket;
|
||||
|
||||
// make sure we still have an active socket
|
||||
if (node->getActiveSocket()) {
|
||||
nodeList->getNodeSocket().writeDatagram((char*) voxelQueryPacket, packetLength,
|
||||
node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort());
|
||||
}
|
||||
nodeList->writeDatagram(reinterpret_cast<const char*>(voxelQueryPacket), packetLength, node);
|
||||
|
||||
// Feed number of bytes to corresponding channel of the bandwidth meter
|
||||
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
|
||||
|
@ -3851,7 +3856,7 @@ void Application::updateWindowTitle(){
|
|||
QString buildVersion = " (build " + applicationVersion() + ")";
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
QString title = QString() + _profile.getUsername() + " " + nodeList->getOwnerUUID().toString()
|
||||
QString title = QString() + _profile.getUsername() + " " + nodeList->getSessionUUID().toString()
|
||||
+ " @ " + nodeList->getDomainHostname() + buildVersion;
|
||||
|
||||
qDebug("Application title set to: %s", title.toStdString().c_str());
|
||||
|
@ -3876,6 +3881,13 @@ void Application::domainChanged(const QString& domainHostname) {
|
|||
_particles.clear();
|
||||
}
|
||||
|
||||
void Application::nodeAdded(SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::AvatarMixer) {
|
||||
// new avatar mixer, send off our identity packet right away
|
||||
_myAvatar->sendIdentityPacket();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::nodeKilled(SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::VoxelServer) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
@ -3945,27 +3957,25 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::trackIncomingVoxelPacket(const QByteArray& packet, const HifiSockAddr& senderSockAddr, bool wasStatsPacket) {
|
||||
void Application::trackIncomingVoxelPacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket) {
|
||||
|
||||
// Attempt to identify the sender from it's address.
|
||||
SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
|
||||
if (serverNode) {
|
||||
QUuid nodeUUID = serverNode->getUUID();
|
||||
if (sendingNode) {
|
||||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_voxelSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
VoxelSceneStats& stats = _octreeServerSceneStats[nodeUUID];
|
||||
stats.trackIncomingOctreePacket(packet, wasStatsPacket, serverNode->getClockSkewUsec());
|
||||
stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec());
|
||||
}
|
||||
_voxelSceneStatsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int Application::parseOctreeStats(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||
|
||||
// But, also identify the sender, and keep track of the contained jurisdiction root for this server
|
||||
SharedNodePointer server = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
|
||||
|
||||
// parse the incoming stats datas stick it in a temporary object for now, while we
|
||||
// determine which server it belongs to
|
||||
|
@ -3973,8 +3983,8 @@ int Application::parseOctreeStats(const QByteArray& packet, const HifiSockAddr&
|
|||
int statsMessageLength = temp.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
|
||||
// quick fix for crash... why would voxelServer be NULL?
|
||||
if (server) {
|
||||
QUuid nodeUUID = server->getUUID();
|
||||
if (sendingNode) {
|
||||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_voxelSceneStatsLock.lockForWrite();
|
||||
|
@ -3991,7 +4001,7 @@ int Application::parseOctreeStats(const QByteArray& packet, const HifiSockAddr&
|
|||
|
||||
// see if this is the first we've heard of this node...
|
||||
NodeToJurisdictionMap* jurisdiction = NULL;
|
||||
if (server->getType() == NodeType::VoxelServer) {
|
||||
if (sendingNode->getType() == NodeType::VoxelServer) {
|
||||
jurisdiction = &_voxelServerJurisdictions;
|
||||
} else {
|
||||
jurisdiction = &_particleServerJurisdictions;
|
||||
|
|
|
@ -126,8 +126,6 @@ public:
|
|||
void touchEndEvent(QTouchEvent* event);
|
||||
void touchUpdateEvent(QTouchEvent* event);
|
||||
|
||||
void updateWindowTitle();
|
||||
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
|
||||
void makeVoxel(glm::vec3 position,
|
||||
|
@ -214,6 +212,8 @@ signals:
|
|||
|
||||
public slots:
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void updateWindowTitle();
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
void packetSent(quint64 length);
|
||||
|
||||
|
@ -472,8 +472,8 @@ private:
|
|||
|
||||
PieMenu _pieMenu;
|
||||
|
||||
int parseOctreeStats(const QByteArray& packet, const HifiSockAddr& senderAddress);
|
||||
void trackIncomingVoxelPacket(const QByteArray& packet, const HifiSockAddr& senderSockAddr, bool wasStatsPacket);
|
||||
int parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sendingNode);
|
||||
void trackIncomingVoxelPacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket);
|
||||
|
||||
NodeToJurisdictionMap _voxelServerJurisdictions;
|
||||
NodeToJurisdictionMap _particleServerJurisdictions;
|
||||
|
|
|
@ -388,7 +388,7 @@ void Audio::handleAudioInput() {
|
|||
NodeList* nodeList = NodeList::getInstance();
|
||||
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
|
||||
if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) {
|
||||
if (audioMixer && audioMixer->getActiveSocket()) {
|
||||
MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar();
|
||||
glm::vec3 headPosition = interfaceAvatar->getHead().getPosition();
|
||||
glm::quat headOrientation = interfaceAvatar->getHead().getOrientation();
|
||||
|
@ -409,10 +409,9 @@ void Audio::handleAudioInput() {
|
|||
memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation));
|
||||
currentPacketPtr += sizeof(headOrientation);
|
||||
|
||||
nodeList->getNodeSocket().writeDatagram(monoAudioDataPacket,
|
||||
NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes,
|
||||
audioMixer->getActiveSocket()->getAddress(),
|
||||
audioMixer->getActiveSocket()->getPort());
|
||||
nodeList->writeDatagram(monoAudioDataPacket,
|
||||
NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes,
|
||||
audioMixer);
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO)
|
||||
.updateValue(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
|
|
|
@ -40,7 +40,7 @@ void DatagramProcessor::processDatagrams() {
|
|||
_packetCount++;
|
||||
_byteCount += incomingPacket.size();
|
||||
|
||||
if (packetVersionMatch(incomingPacket)) {
|
||||
if (nodeList->packetVersionAndHashMatch(incomingPacket)) {
|
||||
// only process this packet if we have a match on the packet version
|
||||
switch (packetTypeForPacket(incomingPacket)) {
|
||||
case PacketTypeTransmitterData:
|
||||
|
@ -84,31 +84,31 @@ void DatagramProcessor::processDatagrams() {
|
|||
printf("got PacketType_VOXEL_DATA, sequence:%d flightTime:%d\n", sequence, flightTime);
|
||||
}
|
||||
|
||||
// add this packet to our list of voxel packets and process them on the voxel processing
|
||||
application->_voxelProcessor.queueReceivedPacket(senderSockAddr, incomingPacket);
|
||||
SharedNodePointer matchedNode = NodeList::getInstance()->sendingNodeForPacket(incomingPacket);
|
||||
|
||||
if (matchedNode) {
|
||||
// add this packet to our list of voxel packets and process them on the voxel processing
|
||||
application->_voxelProcessor.queueReceivedPacket(matchedNode, incomingPacket);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketTypeMetavoxelData:
|
||||
application->_metavoxels.processData(incomingPacket, senderSockAddr);
|
||||
break;
|
||||
case PacketTypeBulkAvatarData:
|
||||
case PacketTypeKillAvatar: {
|
||||
case PacketTypeKillAvatar:
|
||||
case PacketTypeAvatarIdentity: {
|
||||
// update having heard from the avatar-mixer and record the bytes received
|
||||
SharedNodePointer avatarMixer = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
|
||||
SharedNodePointer avatarMixer = nodeList->sendingNodeForPacket(incomingPacket);
|
||||
|
||||
if (avatarMixer) {
|
||||
avatarMixer->setLastHeardMicrostamp(usecTimestampNow());
|
||||
avatarMixer->recordBytesReceived(incomingPacket.size());
|
||||
|
||||
if (packetTypeForPacket(incomingPacket) == PacketTypeBulkAvatarData) {
|
||||
QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
|
||||
Q_ARG(const QByteArray&, incomingPacket),
|
||||
Q_ARG(const QWeakPointer<Node>&, avatarMixer));
|
||||
} else {
|
||||
// this is an avatar kill, pass it to the application AvatarManager
|
||||
QMetaObject::invokeMethod(&application->getAvatarManager(), "processKillAvatar",
|
||||
Q_ARG(const QByteArray&, incomingPacket));
|
||||
}
|
||||
QMetaObject::invokeMethod(&application->getAvatarManager(), "processAvatarMixerDatagram",
|
||||
Q_ARG(const QByteArray&, incomingPacket),
|
||||
Q_ARG(const QWeakPointer<Node>&, avatarMixer));
|
||||
}
|
||||
|
||||
application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
|
||||
|
@ -121,7 +121,7 @@ void DatagramProcessor::processDatagrams() {
|
|||
DataServerClient::processMessageFromDataServer(incomingPacket);
|
||||
break;
|
||||
default:
|
||||
NodeList::getInstance()->processNodeData(senderSockAddr, incomingPacket);
|
||||
nodeList->processNodeData(senderSockAddr, incomingPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -766,12 +766,12 @@ void Menu::editPreferences() {
|
|||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
|
||||
QString faceURLString = applicationInstance->getProfile()->getFaceModelURL().toString();
|
||||
QString faceURLString = applicationInstance->getAvatar()->getHead().getFaceModel().getURL().toString();
|
||||
QLineEdit* faceURLEdit = new QLineEdit(faceURLString);
|
||||
faceURLEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("Face URL:", faceURLEdit);
|
||||
|
||||
QString skeletonURLString = applicationInstance->getProfile()->getSkeletonModelURL().toString();
|
||||
QString skeletonURLString = applicationInstance->getAvatar()->getSkeletonModel().getURL().toString();
|
||||
QLineEdit* skeletonURLEdit = new QLineEdit(skeletonURLString);
|
||||
skeletonURLEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("Skeleton URL:", skeletonURLEdit);
|
||||
|
@ -832,27 +832,25 @@ void Menu::editPreferences() {
|
|||
int ret = dialog.exec();
|
||||
if (ret == QDialog::Accepted) {
|
||||
QUrl faceModelURL(faceURLEdit->text());
|
||||
|
||||
bool shouldDispatchIdentityPacket = false;
|
||||
|
||||
if (faceModelURL.toString() != faceURLString) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
applicationInstance->getProfile()->setFaceModelURL(faceModelURL);
|
||||
|
||||
// send the new face mesh URL to the data-server (if we have a client UUID)
|
||||
DataServerClient::putValueForKeyAndUserString(DataServerKey::FaceMeshURL,
|
||||
faceModelURL.toString().toLocal8Bit().constData(),
|
||||
applicationInstance->getProfile()->getUserString());
|
||||
applicationInstance->getAvatar()->setFaceModelURL(faceModelURL);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
QUrl skeletonModelURL(skeletonURLEdit->text());
|
||||
|
||||
if (skeletonModelURL.toString() != skeletonURLString) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
applicationInstance->getProfile()->setSkeletonModelURL(skeletonModelURL);
|
||||
|
||||
// send the new skeleton model URL to the data-server (if we have a client UUID)
|
||||
DataServerClient::putValueForKeyAndUserString(DataServerKey::SkeletonURL,
|
||||
skeletonModelURL.toString().toLocal8Bit().constData(),
|
||||
applicationInstance->getProfile()->getUserString());
|
||||
applicationInstance->getAvatar()->setSkeletonModelURL(skeletonModelURL);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
if (shouldDispatchIdentityPacket) {
|
||||
applicationInstance->getAvatar()->sendIdentityPacket();
|
||||
}
|
||||
|
||||
applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
|
||||
|
|
|
@ -144,9 +144,9 @@ void MetavoxelSystem::removeClient(const QUuid& uuid) {
|
|||
delete client;
|
||||
}
|
||||
|
||||
void MetavoxelSystem::receivedData(const QByteArray& data, const HifiSockAddr& sender) {
|
||||
void MetavoxelSystem::receivedData(const QByteArray& data, const SharedNodePointer& sendingNode) {
|
||||
int headerPlusIDSize;
|
||||
QUuid sessionID = readSessionID(data, sender, headerPlusIDSize);
|
||||
QUuid sessionID = readSessionID(data, sendingNode, headerPlusIDSize);
|
||||
if (sessionID.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
@ -230,10 +230,7 @@ void MetavoxelClient::receivedData(const QByteArray& data) {
|
|||
|
||||
void MetavoxelClient::sendData(const QByteArray& data) {
|
||||
QMutexLocker locker(&_node->getMutex());
|
||||
const HifiSockAddr* address = _node->getActiveSocket();
|
||||
if (address) {
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram(data, address->getAddress(), address->getPort());
|
||||
}
|
||||
NodeList::getInstance()->writeDatagram(data, _node);
|
||||
}
|
||||
|
||||
void MetavoxelClient::readPacket(Bitstream& in) {
|
||||
|
|
|
@ -52,7 +52,7 @@ private:
|
|||
|
||||
Q_INVOKABLE void addClient(const SharedNodePointer& node);
|
||||
Q_INVOKABLE void removeClient(const QUuid& uuid);
|
||||
Q_INVOKABLE void receivedData(const QByteArray& data, const HifiSockAddr& sender);
|
||||
Q_INVOKABLE void receivedData(const QByteArray& data, const SharedNodePointer& sendingNode);
|
||||
|
||||
class Point {
|
||||
public:
|
||||
|
|
|
@ -123,7 +123,6 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
|
|||
}
|
||||
}
|
||||
|
||||
void ParticleTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr,
|
||||
Node* sourceNode) {
|
||||
static_cast<ParticleTree*>(_tree)->processEraseMessage(dataByteArray, senderSockAddr, sourceNode);
|
||||
void ParticleTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
static_cast<ParticleTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
ParticleTree* getTree() { return (ParticleTree*)_tree; }
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode);
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
|
||||
virtual void init();
|
||||
virtual void render();
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "Menu.h"
|
||||
#include "VoxelPacketProcessor.h"
|
||||
|
||||
void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||
void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"VoxelPacketProcessor::processPacket()");
|
||||
|
||||
|
@ -44,11 +44,11 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, con
|
|||
// then process any remaining bytes as if it was another packet
|
||||
if (voxelPacketType == PacketTypeOctreeStats) {
|
||||
|
||||
int statsMessageLength = app->parseOctreeStats(mutablePacket, senderSockAddr);
|
||||
int statsMessageLength = app->parseOctreeStats(mutablePacket, sendingNode);
|
||||
wasStatsPacket = true;
|
||||
if (messageLength > statsMessageLength) {
|
||||
mutablePacket = mutablePacket.mid(statsMessageLength);
|
||||
if (!packetVersionMatch(packet)) {
|
||||
if (!NodeList::getInstance()->packetVersionAndHashMatch(packet)) {
|
||||
return; // bail since piggyback data doesn't match our versioning
|
||||
}
|
||||
} else {
|
||||
|
@ -60,26 +60,25 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, con
|
|||
voxelPacketType = packetTypeForPacket(mutablePacket);
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||
app->trackIncomingVoxelPacket(mutablePacket, senderSockAddr, wasStatsPacket);
|
||||
app->trackIncomingVoxelPacket(mutablePacket, sendingNode, wasStatsPacket);
|
||||
|
||||
SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr);
|
||||
if (serverNode && serverNode->getActiveSocket() && *serverNode->getActiveSocket() == senderSockAddr) {
|
||||
if (sendingNode) {
|
||||
|
||||
switch(voxelPacketType) {
|
||||
case PacketTypeParticleErase: {
|
||||
app->_particles.processEraseMessage(mutablePacket, senderSockAddr, serverNode.data());
|
||||
app->_particles.processEraseMessage(mutablePacket, sendingNode);
|
||||
} break;
|
||||
|
||||
case PacketTypeParticleData: {
|
||||
app->_particles.processDatagram(mutablePacket, senderSockAddr, serverNode.data());
|
||||
app->_particles.processDatagram(mutablePacket, sendingNode);
|
||||
} break;
|
||||
|
||||
case PacketTypeEnvironmentData: {
|
||||
app->_environment.parseData(senderSockAddr, mutablePacket);
|
||||
app->_environment.parseData(*sendingNode->getActiveSocket(), mutablePacket);
|
||||
} break;
|
||||
|
||||
default : {
|
||||
app->_voxels.setDataSourceUUID(serverNode->getUUID());
|
||||
app->_voxels.setDataSourceUUID(sendingNode->getUUID());
|
||||
app->_voxels.parseData(mutablePacket);
|
||||
app->_voxels.setDataSourceUUID(QUuid());
|
||||
} break;
|
||||
|
|
|
@ -17,6 +17,6 @@
|
|||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||
class VoxelPacketProcessor : public ReceivedPacketProcessor {
|
||||
protected:
|
||||
virtual void processPacket(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
};
|
||||
#endif // __shared__VoxelPacketProcessor__
|
||||
|
|
|
@ -336,6 +336,16 @@ bool Avatar::findSphereCollision(const glm::vec3& sphereCenter, float sphereRadi
|
|||
return false;
|
||||
}
|
||||
|
||||
void Avatar::setFaceModelURL(const QUrl &faceModelURL) {
|
||||
AvatarData::setFaceModelURL(faceModelURL);
|
||||
_head.getFaceModel().setURL(faceModelURL);
|
||||
}
|
||||
|
||||
void Avatar::setSkeletonModelURL(const QUrl &skeletonModelURL) {
|
||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||
_skeletonModel.setURL(skeletonModelURL);
|
||||
}
|
||||
|
||||
int Avatar::parseData(const QByteArray& packet) {
|
||||
// change in position implies movement
|
||||
glm::vec3 oldPosition = _position;
|
||||
|
|
|
@ -82,7 +82,6 @@ public:
|
|||
//getters
|
||||
bool isInitialized() const { return _initialized; }
|
||||
SkeletonModel& getSkeletonModel() { return _skeletonModel; }
|
||||
float getHeadYawRate() const { return _head.yawRate; }
|
||||
glm::vec3 getChestPosition() const;
|
||||
float getScale() const { return _scale; }
|
||||
const glm::vec3& getVelocity() const { return _velocity; }
|
||||
|
@ -112,7 +111,10 @@ public:
|
|||
virtual bool findSphereCollision(const glm::vec3& sphereCenter, float sphereRadius, CollisionInfo& collision);
|
||||
|
||||
virtual bool isMyAvatar() { return false; }
|
||||
|
||||
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
int parseData(const QByteArray& packet);
|
||||
|
||||
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
|
||||
|
|
|
@ -123,47 +123,29 @@ void AvatarManager::renderAvatarFades() {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarManager::processDataServerResponse(const QString& userString, const QStringList& keyList,
|
||||
const QStringList &valueList) {
|
||||
QUuid avatarKey = QUuid(userString);
|
||||
if (avatarKey == MY_AVATAR_KEY) {
|
||||
// ignore updates to our own mesh
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < keyList.size(); i++) {
|
||||
if (valueList[i] != " ") {
|
||||
if (keyList[i] == DataServerKey::FaceMeshURL || keyList[i] == DataServerKey::SkeletonURL) {
|
||||
// mesh URL for a UUID, find avatar in our list
|
||||
AvatarSharedPointer matchingAvatar = _avatarHash.value(avatarKey);
|
||||
if (matchingAvatar) {
|
||||
Avatar* avatar = static_cast<Avatar*>(matchingAvatar.data());
|
||||
if (keyList[i] == DataServerKey::FaceMeshURL) {
|
||||
qDebug() << "Changing mesh to" << valueList[i] << "for avatar with UUID"
|
||||
<< uuidStringWithoutCurlyBraces(avatarKey);
|
||||
|
||||
QMetaObject::invokeMethod(&(avatar->getHead().getFaceModel()),
|
||||
"setURL", Q_ARG(QUrl, QUrl(valueList[i])));
|
||||
} else if (keyList[i] == DataServerKey::SkeletonURL) {
|
||||
qDebug() << "Changing skeleton to" << valueList[i] << "for avatar with UUID"
|
||||
<< uuidStringWithoutCurlyBraces(avatarKey.toString());
|
||||
|
||||
QMetaObject::invokeMethod(&(avatar->getSkeletonModel()),
|
||||
"setURL", Q_ARG(QUrl, QUrl(valueList[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
switch (packetTypeForPacket(datagram)) {
|
||||
case PacketTypeBulkAvatarData:
|
||||
processAvatarDataPacket(datagram, mixerWeakPointer);
|
||||
break;
|
||||
case PacketTypeAvatarIdentity:
|
||||
processAvatarIdentityPacket(datagram);
|
||||
break;
|
||||
case PacketTypeKillAvatar:
|
||||
processKillAvatar(datagram);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
|
||||
void AvatarManager::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer<Node> &mixerWeakPointer) {
|
||||
int bytesRead = numBytesForPacketHeader(datagram);
|
||||
|
||||
QByteArray dummyAvatarByteArray = byteArrayWithPopluatedHeader(PacketTypeAvatarData);
|
||||
int numDummyHeaderBytes = dummyAvatarByteArray.size();
|
||||
int numDummyHeaderBytesWithoutUUID = numDummyHeaderBytes - NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
|
||||
// enumerate over all of the avatars in this packet
|
||||
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
|
||||
while (bytesRead < datagram.size() && mixerWeakPointer.data()) {
|
||||
|
@ -180,10 +162,6 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const
|
|||
matchingAvatar = AvatarSharedPointer(avatar);
|
||||
_avatarHash.insert(nodeUUID, matchingAvatar);
|
||||
|
||||
// new UUID requires mesh and skeleton request to data-server
|
||||
DataServerClient::getValuesForKeysAndUUID(QStringList() << DataServerKey::FaceMeshURL << DataServerKey::SkeletonURL,
|
||||
nodeUUID, this);
|
||||
|
||||
qDebug() << "Adding avatar with UUID" << nodeUUID << "to AvatarManager hash.";
|
||||
}
|
||||
|
||||
|
@ -196,6 +174,35 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const
|
|||
// have the matching (or new) avatar parse the data from the packet
|
||||
bytesRead += matchingAvatar->parseData(dummyAvatarByteArray) - numDummyHeaderBytesWithoutUUID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AvatarManager::processAvatarIdentityPacket(const QByteArray &packet) {
|
||||
// setup a data stream to parse the packet
|
||||
QDataStream identityStream(packet);
|
||||
identityStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
QUuid nodeUUID;
|
||||
|
||||
while (!identityStream.atEnd()) {
|
||||
|
||||
QUrl faceMeshURL, skeletonURL;
|
||||
identityStream >> nodeUUID >> faceMeshURL >> skeletonURL;
|
||||
|
||||
// mesh URL for a UUID, find avatar in our list
|
||||
AvatarSharedPointer matchingAvatar = _avatarHash.value(nodeUUID);
|
||||
if (matchingAvatar) {
|
||||
Avatar* avatar = static_cast<Avatar*>(matchingAvatar.data());
|
||||
|
||||
if (avatar->getFaceModelURL() != faceMeshURL) {
|
||||
avatar->setFaceModelURL(faceMeshURL);
|
||||
}
|
||||
|
||||
if (avatar->getSkeletonModelURL() != skeletonURL) {
|
||||
avatar->setSkeletonModelURL(skeletonURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::processKillAvatar(const QByteArray& datagram) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
class MyAvatar;
|
||||
|
||||
class AvatarManager : public QObject, public DataServerCallbackObject, public AvatarHashMap {
|
||||
class AvatarManager : public QObject, public AvatarHashMap {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AvatarManager(QObject* parent = 0);
|
||||
|
@ -35,13 +35,14 @@ public:
|
|||
void clearOtherAvatars();
|
||||
|
||||
public slots:
|
||||
void processDataServerResponse(const QString& userString, const QStringList& keyList, const QStringList& valueList);
|
||||
|
||||
void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
void processKillAvatar(const QByteArray& datagram);
|
||||
|
||||
|
||||
private:
|
||||
AvatarManager(const AvatarManager& other);
|
||||
|
||||
void processAvatarDataPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
void processAvatarIdentityPacket(const QByteArray& packet);
|
||||
void processKillAvatar(const QByteArray& datagram);
|
||||
|
||||
void simulateAvatarFades(float deltaTime);
|
||||
void renderAvatarFades();
|
||||
|
|
|
@ -59,15 +59,15 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
|||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||
state.rotation = glm::angleAxis(-_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
|
||||
glm::angleAxis(_owningHead->getYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-_owningHead->getPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) *
|
||||
glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||
}
|
||||
|
||||
void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
|
||||
// likewise with the eye joints
|
||||
glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getTweakedOrientation() * IDENTITY_FRONT, 0.0f));
|
||||
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
|
||||
_owningHead->getSaccade() - _translation, 1.0f));
|
||||
glm::quat between = rotationBetween(front, lookAt);
|
||||
|
|
|
@ -18,7 +18,6 @@ using namespace std;
|
|||
|
||||
Head::Head(Avatar* owningAvatar) :
|
||||
HeadData((AvatarData*)owningAvatar),
|
||||
yawRate(0.0f),
|
||||
_returnHeadToCenter(false),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_rotation(0.0f, 0.0f, 0.0f),
|
||||
|
@ -37,6 +36,9 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_leftEyeBlinkVelocity(0.0f),
|
||||
_rightEyeBlinkVelocity(0.0f),
|
||||
_timeWithoutTalking(0.0f),
|
||||
_tweakedPitch(0.f),
|
||||
_tweakedYaw(0.f),
|
||||
_tweakedRoll(0.f),
|
||||
_isCameraMoving(false),
|
||||
_faceModel(this)
|
||||
{
|
||||
|
@ -186,9 +188,14 @@ glm::quat Head::getOrientation() const {
|
|||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll)));
|
||||
}
|
||||
|
||||
glm::quat Head::getTweakedOrientation() const {
|
||||
return glm::quat(glm::radians(_bodyRotation)) * glm::quat(glm::radians(glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() )));
|
||||
}
|
||||
|
||||
glm::quat Head::getCameraOrientation () const {
|
||||
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
|
||||
return owningAvatar->getWorldAlignedOrientation();
|
||||
return owningAvatar->getWorldAlignedOrientation()
|
||||
* glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f)));
|
||||
}
|
||||
|
||||
glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
|
||||
|
@ -200,6 +207,18 @@ glm::vec3 Head::getScalePivot() const {
|
|||
return _faceModel.isActive() ? _faceModel.getTranslation() : _position;
|
||||
}
|
||||
|
||||
float Head::getTweakedYaw() const {
|
||||
return glm::clamp(_yaw + _tweakedYaw, MIN_HEAD_YAW, MAX_HEAD_YAW);
|
||||
}
|
||||
|
||||
float Head::getTweakedPitch() const {
|
||||
return glm::clamp(_pitch + _tweakedPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH);
|
||||
}
|
||||
|
||||
float Head::getTweakedRoll() const {
|
||||
return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
|
||||
}
|
||||
|
||||
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
|
||||
|
||||
Application::getInstance()->getGlowEffect()->begin();
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <AvatarData.h>
|
||||
#include <HeadData.h>
|
||||
|
||||
#include <VoxelConstants.h>
|
||||
|
||||
|
@ -47,6 +47,7 @@ public:
|
|||
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; }
|
||||
|
||||
glm::quat getOrientation() const;
|
||||
glm::quat getTweakedOrientation() const;
|
||||
glm::quat getCameraOrientation () const;
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
|
||||
|
@ -70,9 +71,15 @@ public:
|
|||
|
||||
/// Returns the point about which scaling occurs.
|
||||
glm::vec3 getScalePivot() const;
|
||||
|
||||
float yawRate;
|
||||
|
||||
void tweakPitch(float pitch) { _tweakedPitch = pitch; }
|
||||
void tweakYaw(float yaw) { _tweakedYaw = yaw; }
|
||||
void tweakRoll(float roll) { _tweakedRoll = roll; }
|
||||
|
||||
float getTweakedPitch() const;
|
||||
float getTweakedYaw() const;
|
||||
float getTweakedRoll() const;
|
||||
|
||||
private:
|
||||
// disallow copies of the Head, copy of owning Avatar is disallowed too
|
||||
Head(const Head&);
|
||||
|
@ -96,6 +103,12 @@ private:
|
|||
float _leftEyeBlinkVelocity;
|
||||
float _rightEyeBlinkVelocity;
|
||||
float _timeWithoutTalking;
|
||||
|
||||
// tweaked angles affect the rendered head, but not the camera
|
||||
float _tweakedPitch;
|
||||
float _tweakedYaw;
|
||||
float _tweakedRoll;
|
||||
|
||||
bool _isCameraMoving;
|
||||
FaceModel _faceModel;
|
||||
|
||||
|
|
|
@ -396,9 +396,9 @@ void MyAvatar::updateFromGyros(bool turnWithHead) {
|
|||
const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f;
|
||||
_head.setPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
_head.setYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
_head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
_head.tweakPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
_head.tweakYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
_head.tweakRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
|
||||
// Update torso lean distance based on accelerometer data
|
||||
const float TORSO_LENGTH = 0.5f;
|
||||
|
@ -608,6 +608,9 @@ void MyAvatar::saveData(QSettings* settings) {
|
|||
|
||||
settings->setValue("leanScale", _leanScale);
|
||||
settings->setValue("scale", _targetScale);
|
||||
|
||||
settings->setValue("faceModelURL", _faceModelURL);
|
||||
settings->setValue("skeletonModelURL", _skeletonModelURL);
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
@ -632,6 +635,9 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
_targetScale = loadSetting(settings, "scale", 1.0f);
|
||||
setScale(_scale);
|
||||
Application::getInstance()->getCamera()->setScale(_scale);
|
||||
|
||||
setFaceModelURL(settings->value("faceModelURL").toUrl());
|
||||
setSkeletonModelURL(settings->value("skeletonModelURL").toUrl());
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
@ -641,6 +647,13 @@ void MyAvatar::sendKillAvatar() {
|
|||
NodeList::getInstance()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
void MyAvatar::sendIdentityPacket() {
|
||||
QByteArray identityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity);
|
||||
identityPacket.append(AvatarData::identityByteArray());
|
||||
|
||||
NodeList::getInstance()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) {
|
||||
// first orbit horizontally
|
||||
glm::quat orientation = getOrientation();
|
||||
|
|
|
@ -94,6 +94,8 @@ public slots:
|
|||
void increaseSize();
|
||||
void decreaseSize();
|
||||
void resetSize();
|
||||
|
||||
void sendIdentityPacket();
|
||||
|
||||
private:
|
||||
bool _mousePressed;
|
||||
|
|
|
@ -20,17 +20,13 @@ Profile::Profile(const QString &username) :
|
|||
_uuid(),
|
||||
_lastDomain(),
|
||||
_lastPosition(0.0, 0.0, 0.0),
|
||||
_lastOrientationSend(0),
|
||||
_faceModelURL(),
|
||||
_skeletonModelURL()
|
||||
_lastOrientationSend(0)
|
||||
{
|
||||
if (!username.isEmpty()) {
|
||||
setUsername(username);
|
||||
|
||||
// we've been given a new username, ask the data-server for profile
|
||||
DataServerClient::getValueForKeyAndUserString(DataServerKey::UUID, getUserString(), this);
|
||||
DataServerClient::getValueForKeyAndUserString(DataServerKey::FaceMeshURL, getUserString(), this);
|
||||
DataServerClient::getValueForKeyAndUserString(DataServerKey::SkeletonURL, getUserString(), this);
|
||||
|
||||
// send our current domain server to the data-server
|
||||
updateDomain(NodeList::getInstance()->getDomainHostname());
|
||||
|
@ -45,34 +41,6 @@ QString Profile::getUserString() const {
|
|||
}
|
||||
}
|
||||
|
||||
void Profile::setUUID(const QUuid& uuid) {
|
||||
_uuid = uuid;
|
||||
|
||||
if (!_uuid.isNull()) {
|
||||
qDebug() << "Changing NodeList owner UUID to" << uuid;
|
||||
|
||||
// when the UUID is changed we need set it appropriately on the NodeList instance
|
||||
NodeList::getInstance()->setOwnerUUID(uuid);
|
||||
|
||||
// ask for a window title update so the new UUID is presented
|
||||
Application::getInstance()->updateWindowTitle();
|
||||
}
|
||||
}
|
||||
|
||||
void Profile::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
_faceModelURL = faceModelURL;
|
||||
|
||||
QMetaObject::invokeMethod(&Application::getInstance()->getAvatar()->getHead().getFaceModel(),
|
||||
"setURL", Q_ARG(QUrl, _faceModelURL));
|
||||
}
|
||||
|
||||
void Profile::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
_skeletonModelURL = skeletonModelURL;
|
||||
|
||||
QMetaObject::invokeMethod(&Application::getInstance()->getAvatar()->getSkeletonModel(),
|
||||
"setURL", Q_ARG(QUrl, _skeletonModelURL));
|
||||
}
|
||||
|
||||
void Profile::updateDomain(const QString& domain) {
|
||||
if (_lastDomain != domain) {
|
||||
_lastDomain = domain;
|
||||
|
@ -137,8 +105,6 @@ void Profile::saveData(QSettings* settings) {
|
|||
|
||||
settings->setValue("username", _username);
|
||||
settings->setValue("UUID", _uuid);
|
||||
settings->setValue("faceModelURL", _faceModelURL);
|
||||
settings->setValue("skeletonModelURL", _skeletonModelURL);
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
@ -148,8 +114,6 @@ void Profile::loadData(QSettings* settings) {
|
|||
|
||||
setUsername(settings->value("username").toString());
|
||||
this->setUUID(settings->value("UUID").toUuid());
|
||||
_faceModelURL = settings->value("faceModelURL").toUrl();
|
||||
_skeletonModelURL = settings->value("skeletonModelURL").toUrl();
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
@ -157,17 +121,7 @@ void Profile::loadData(QSettings* settings) {
|
|||
void Profile::processDataServerResponse(const QString& userString, const QStringList& keyList, const QStringList& valueList) {
|
||||
for (int i = 0; i < keyList.size(); i++) {
|
||||
if (valueList[i] != " ") {
|
||||
if (keyList[i] == DataServerKey::FaceMeshURL) {
|
||||
if (userString == _username || userString == uuidStringWithoutCurlyBraces(_uuid)) {
|
||||
qDebug("Changing user's face model URL to %s", valueList[i].toLocal8Bit().constData());
|
||||
Application::getInstance()->getProfile()->setFaceModelURL(QUrl(valueList[i]));
|
||||
}
|
||||
} else if (keyList[i] == DataServerKey::SkeletonURL) {
|
||||
if (userString == _username || userString == uuidStringWithoutCurlyBraces(_uuid)) {
|
||||
qDebug("Changing user's skeleton URL to %s", valueList[i].toLocal8Bit().constData());
|
||||
Application::getInstance()->getProfile()->setSkeletonModelURL(QUrl(valueList[i]));
|
||||
}
|
||||
} else if (keyList[i] == DataServerKey::Domain && keyList[i + 1] == DataServerKey::Position &&
|
||||
if (keyList[i] == DataServerKey::Domain && keyList[i + 1] == DataServerKey::Position &&
|
||||
keyList[i + 2] == DataServerKey::Orientation && valueList[i] != " " &&
|
||||
valueList[i + 1] != " " && valueList[i + 2] != " ") {
|
||||
|
||||
|
|
|
@ -28,15 +28,9 @@ public:
|
|||
|
||||
const QString& getUsername() const { return _username; }
|
||||
|
||||
void setUUID(const QUuid& uuid);
|
||||
void setUUID(const QUuid& uuid) { _uuid = uuid; }
|
||||
const QUuid& getUUID() { return _uuid; }
|
||||
|
||||
void setFaceModelURL(const QUrl& faceModelURL);
|
||||
const QUrl& getFaceModelURL() const { return _faceModelURL; }
|
||||
|
||||
void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
||||
|
||||
void updateDomain(const QString& domain);
|
||||
void updatePosition(const glm::vec3 position);
|
||||
void updateOrientation(const glm::quat& orientation);
|
||||
|
@ -58,8 +52,6 @@ private:
|
|||
glm::vec3 _lastPosition;
|
||||
glm::vec3 _lastOrientation;
|
||||
quint64 _lastOrientationSend;
|
||||
QUrl _faceModelURL;
|
||||
QUrl _skeletonModelURL;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__Profile__) */
|
||||
|
|
|
@ -265,7 +265,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serv
|
|||
std::stringstream extraDetails("");
|
||||
std::stringstream linkDetails("");
|
||||
|
||||
if (nodeList->getNodeActiveSocketOrPing(node.data())) {
|
||||
if (node->getActiveSocket()) {
|
||||
serverDetails << "active ";
|
||||
} else {
|
||||
serverDetails << "inactive ";
|
||||
|
|
|
@ -93,12 +93,8 @@ void AudioInjector::injectAudio() {
|
|||
// grab our audio mixer from the NodeList, if it exists
|
||||
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
|
||||
if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) {
|
||||
// send off this audio packet
|
||||
nodeList->getNodeSocket().writeDatagram(injectAudioPacket,
|
||||
audioMixer->getActiveSocket()->getAddress(),
|
||||
audioMixer->getActiveSocket()->getPort());
|
||||
}
|
||||
// send off this audio packet
|
||||
nodeList->writeDatagram(injectAudioPacket, audioMixer);
|
||||
|
||||
currentSendPosition += bytesToCopy;
|
||||
|
||||
|
|
|
@ -270,6 +270,48 @@ int AvatarData::parseData(const QByteArray& packet) {
|
|||
return sourceBuffer - startPosition;
|
||||
}
|
||||
|
||||
bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) {
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
QUuid avatarUUID;
|
||||
QUrl faceModelURL, skeletonModelURL;
|
||||
packetStream >> avatarUUID >> faceModelURL >> skeletonModelURL;
|
||||
|
||||
bool hasIdentityChanged = false;
|
||||
|
||||
if (faceModelURL != _faceModelURL) {
|
||||
setFaceModelURL(faceModelURL);
|
||||
hasIdentityChanged = true;
|
||||
}
|
||||
|
||||
if (skeletonModelURL != _skeletonModelURL) {
|
||||
setSkeletonModelURL(skeletonModelURL);
|
||||
hasIdentityChanged = true;
|
||||
}
|
||||
|
||||
return hasIdentityChanged;
|
||||
}
|
||||
|
||||
QByteArray AvatarData::identityByteArray() {
|
||||
QByteArray identityData;
|
||||
QDataStream identityStream(&identityData, QIODevice::Append);
|
||||
|
||||
identityStream << QUuid() << _faceModelURL << _skeletonModelURL;
|
||||
|
||||
return identityData;
|
||||
}
|
||||
|
||||
void AvatarData::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
qDebug() << "Changing face model for avatar to" << faceModelURL.toString();
|
||||
_faceModelURL = faceModelURL;
|
||||
}
|
||||
|
||||
void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
qDebug() << "Changing skeleton model for avatar to" << skeletonModelURL.toString();
|
||||
_skeletonModelURL = skeletonModelURL;
|
||||
}
|
||||
|
||||
void AvatarData::setClampedTargetScale(float targetScale) {
|
||||
|
||||
targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef unsigned long long quint64;
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtCore/QVariantMap>
|
||||
|
||||
|
@ -51,8 +52,7 @@ static const float MIN_AVATAR_SCALE = .005f;
|
|||
|
||||
const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation
|
||||
|
||||
enum KeyState
|
||||
{
|
||||
enum KeyState {
|
||||
NO_KEY_DOWN = 0,
|
||||
INSERT_KEY_DOWN,
|
||||
DELETE_KEY_DOWN
|
||||
|
@ -72,7 +72,9 @@ class AvatarData : public NodeData {
|
|||
|
||||
Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation)
|
||||
Q_PROPERTY(float headPitch READ getHeadPitch WRITE setHeadPitch)
|
||||
|
||||
|
||||
Q_PROPERTY(QUrl faceModelURL READ getFaceModelURL WRITE setFaceModelURL)
|
||||
Q_PROPERTY(QUrl skeletonModelURL READ getSkeletonModelURL WRITE setSkeletonModelURL)
|
||||
public:
|
||||
AvatarData();
|
||||
~AvatarData();
|
||||
|
@ -142,6 +144,14 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool hasIdentityChangedAfterParsing(const QByteArray& packet);
|
||||
QByteArray identityByteArray();
|
||||
|
||||
const QUrl& getFaceModelURL() const { return _faceModelURL; }
|
||||
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
protected:
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _handPosition;
|
||||
|
@ -168,6 +178,8 @@ protected:
|
|||
HeadData* _headData;
|
||||
HandData* _handData;
|
||||
|
||||
QUrl _faceModelURL;
|
||||
QUrl _skeletonModelURL;
|
||||
private:
|
||||
// privatize the copy constructor and assignment operator so they cannot be called
|
||||
AvatarData(const AvatarData&);
|
||||
|
|
|
@ -106,7 +106,7 @@ static QItemEditorCreatorBase* qColorEditorCreator = createQColorEditorCreator()
|
|||
static QItemEditorCreatorBase* vec3EditorCreator = createVec3EditorCreator();
|
||||
static QItemEditorCreatorBase* parameterizedURLEditorCreator = createParameterizedURLEditorCreator();
|
||||
|
||||
QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& headerPlusIDSize) {
|
||||
QUuid readSessionID(const QByteArray& data, const SharedNodePointer& sendingNode, int& headerPlusIDSize) {
|
||||
// get the header size
|
||||
int headerSize = numBytesForPacketHeader(data);
|
||||
|
||||
|
@ -114,7 +114,7 @@ QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& hea
|
|||
const int UUID_BYTES = 16;
|
||||
headerPlusIDSize = headerSize + UUID_BYTES;
|
||||
if (data.size() < headerPlusIDSize) {
|
||||
qWarning() << "Metavoxel data too short [size=" << data.size() << ", sender=" << sender << "]\n";
|
||||
qWarning() << "Metavoxel data too short [size=" << data.size() << ", sendingNode=" << sendingNode << "]\n";
|
||||
return QUuid();
|
||||
}
|
||||
return QUuid::fromRfc4122(QByteArray::fromRawData(data.constData() + headerSize, UUID_BYTES));
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QUuid>
|
||||
#include <QWidget>
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "Bitstream.h"
|
||||
|
@ -30,7 +31,7 @@ class NetworkProgram;
|
|||
/// Reads and returns the session ID from a datagram.
|
||||
/// \param[out] headerPlusIDSize the size of the header (including the session ID) within the data
|
||||
/// \return the session ID, or a null ID if invalid (in which case a warning will be logged)
|
||||
QUuid readSessionID(const QByteArray& data, const HifiSockAddr& sender, int& headerPlusIDSize);
|
||||
QUuid readSessionID(const QByteArray& data, const SharedNodePointer& sendingNode, int& headerPlusIDSize);
|
||||
|
||||
/// A streamable axis-aligned bounding box.
|
||||
class Box {
|
||||
|
|
|
@ -45,9 +45,8 @@ bool JurisdictionListener::queueJurisdictionRequest() {
|
|||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
if (nodeList->getNodeActiveSocketOrPing(node.data()) && node->getType() == getNodeType()) {
|
||||
const HifiSockAddr* nodeAddress = node->getActiveSocket();
|
||||
_packetSender.queuePacketForSending(*nodeAddress, QByteArray(reinterpret_cast<char*>(bufferOut), sizeOut));
|
||||
if (node->getType() == getNodeType() && node->getActiveSocket()) {
|
||||
_packetSender.queuePacketForSending(node, QByteArray(reinterpret_cast<char*>(bufferOut), sizeOut));
|
||||
nodeCount++;
|
||||
}
|
||||
}
|
||||
|
@ -62,16 +61,13 @@ bool JurisdictionListener::queueJurisdictionRequest() {
|
|||
return isStillRunning();
|
||||
}
|
||||
|
||||
void JurisdictionListener::processPacket(const HifiSockAddr& senderAddress, const QByteArray& packet) {
|
||||
void JurisdictionListener::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
//qDebug() << "JurisdictionListener::processPacket()";
|
||||
if (packetTypeForPacket(packet) == PacketTypeJurisdictionRequest) {
|
||||
SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(senderAddress);
|
||||
if (node) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
JurisdictionMap map;
|
||||
map.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
_jurisdictions[nodeUUID] = map;
|
||||
}
|
||||
if (packetTypeForPacket(packet) == PacketTypeJurisdictionRequest && sendingNode) {
|
||||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
JurisdictionMap map;
|
||||
map.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
_jurisdictions[nodeUUID] = map;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ protected:
|
|||
/// \param packetData pointer to received data
|
||||
/// \param ssize_t packetLength size of received data
|
||||
/// \thread "this" individual processing thread
|
||||
virtual void processPacket(const HifiSockAddr& senderAddress, const QByteArray& packet);
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
|
||||
private:
|
||||
NodeToJurisdictionMap _jurisdictions;
|
||||
|
|
|
@ -28,13 +28,11 @@ JurisdictionSender::~JurisdictionSender() {
|
|||
}
|
||||
|
||||
|
||||
void JurisdictionSender::processPacket(const HifiSockAddr& senderAddress, const QByteArray& packet) {
|
||||
void JurisdictionSender::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
if (packetTypeForPacket(packet) == PacketTypeJurisdictionRequest) {
|
||||
QUuid nodeUUID;
|
||||
deconstructPacketHeader(packet, nodeUUID);
|
||||
if (!nodeUUID.isNull()) {
|
||||
if (sendingNode) {
|
||||
lockRequestingNodes();
|
||||
_nodesRequestingJurisdictions.push(nodeUUID);
|
||||
_nodesRequestingJurisdictions.push(sendingNode->getUUID());
|
||||
unlockRequestingNodes();
|
||||
}
|
||||
}
|
||||
|
@ -65,8 +63,7 @@ bool JurisdictionSender::process() {
|
|||
SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (node && node->getActiveSocket() != NULL) {
|
||||
const HifiSockAddr* nodeAddress = node->getActiveSocket();
|
||||
_packetSender.queuePacketForSending(*nodeAddress, QByteArray(reinterpret_cast<char *>(bufferOut), sizeOut));
|
||||
_packetSender.queuePacketForSending(node, QByteArray(reinterpret_cast<char *>(bufferOut), sizeOut));
|
||||
nodeCount++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
void setNodeType(NodeType_t type) { _nodeType = type; }
|
||||
|
||||
protected:
|
||||
virtual void processPacket(const HifiSockAddr& senderAddress, const QByteArray& packet);
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
|
||||
/// Locks all the resources of the thread.
|
||||
void lockRequestingNodes() { _requestingNodeMutex.lock(); }
|
||||
|
|
|
@ -1347,7 +1347,7 @@ bool Octree::readFromSVOFile(const char* fileName) {
|
|||
fileOk = true; // assume the file is ok
|
||||
}
|
||||
if (fileOk) {
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, NULL, wantImportProgress);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress);
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
}
|
||||
delete[] entireFile;
|
||||
|
@ -1485,7 +1485,7 @@ void Octree::copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinat
|
|||
|
||||
// ask destination tree to read the bitstream
|
||||
bool wantImportProgress = true;
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, NULL, wantImportProgress);
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, SharedNodePointer(), wantImportProgress);
|
||||
readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ public:
|
|||
bool includeExistsBits;
|
||||
OctreeElement* destinationNode;
|
||||
QUuid sourceUUID;
|
||||
Node* sourceNode;
|
||||
SharedNodePointer sourceNode;
|
||||
bool wantImportProgress;
|
||||
|
||||
ReadBitstreamToTreeParams(
|
||||
|
@ -164,7 +164,7 @@ public:
|
|||
bool includeExistsBits = WANT_EXISTS_BITS,
|
||||
OctreeElement* destinationNode = NULL,
|
||||
QUuid sourceUUID = QUuid(),
|
||||
Node* sourceNode = NULL,
|
||||
SharedNodePointer sourceNode = SharedNodePointer(),
|
||||
bool wantImportProgress = false) :
|
||||
includeColor(includeColor),
|
||||
includeExistsBits(includeExistsBits),
|
||||
|
@ -190,7 +190,7 @@ public:
|
|||
virtual PacketType expectedDataPacketType() const { return PacketTypeUnknown; }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const { return false; }
|
||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, Node* senderNode) { return 0; }
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& sourceNode) { return 0; }
|
||||
|
||||
|
||||
virtual void update() { }; // nothing to do by default
|
||||
|
|
|
@ -60,19 +60,17 @@ bool OctreeEditPacketSender::serversExist() const {
|
|||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
// only send to the NodeTypes that are getMyNodeType()
|
||||
if (node->getType() == getMyNodeType()) {
|
||||
if (nodeList->getNodeActiveSocketOrPing(node.data())) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
// If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server
|
||||
if (_serverJurisdictions) {
|
||||
// lookup our nodeUUID in the jurisdiction map, if it's missing then we're
|
||||
// missing at least one jurisdiction
|
||||
if ((*_serverJurisdictions).find(nodeUUID) == (*_serverJurisdictions).end()) {
|
||||
atLeastOnJurisdictionMissing = true;
|
||||
}
|
||||
if (node->getType() == getMyNodeType() && node->getActiveSocket()) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
// If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server
|
||||
if (_serverJurisdictions) {
|
||||
// lookup our nodeUUID in the jurisdiction map, if it's missing then we're
|
||||
// missing at least one jurisdiction
|
||||
if ((*_serverJurisdictions).find(nodeUUID) == (*_serverJurisdictions).end()) {
|
||||
atLeastOnJurisdictionMissing = true;
|
||||
}
|
||||
hasServers = true;
|
||||
}
|
||||
hasServers = true;
|
||||
}
|
||||
if (atLeastOnJurisdictionMissing) {
|
||||
break; // no point in looking further...
|
||||
|
@ -91,9 +89,8 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c
|
|||
// only send to the NodeTypes that are getMyNodeType()
|
||||
if (node->getType() == getMyNodeType() &&
|
||||
((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
|
||||
if (nodeList->getNodeActiveSocketOrPing(node.data())) {
|
||||
const HifiSockAddr* nodeAddress = node->getActiveSocket();
|
||||
queuePacketForSending(*nodeAddress, QByteArray(reinterpret_cast<char*>(buffer), length));
|
||||
if (node->getActiveSocket()) {
|
||||
queuePacketForSending(node, QByteArray(reinterpret_cast<char*>(buffer), length));
|
||||
|
||||
// debugging output...
|
||||
bool wantDebugging = false;
|
||||
|
|
|
@ -26,7 +26,7 @@ void OctreeRenderer::init() {
|
|||
OctreeRenderer::~OctreeRenderer() {
|
||||
}
|
||||
|
||||
void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode) {
|
||||
void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
bool extraDebugging = false; // Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)
|
||||
PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram()",showTimingDetails);
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
virtual void renderElement(OctreeElement* element, RenderArgs* args) = 0;
|
||||
|
||||
/// process incoming data
|
||||
virtual void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode);
|
||||
virtual void processDatagram(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
|
||||
/// initialize and GPU/rendering related resources
|
||||
virtual void init();
|
||||
|
|
|
@ -90,7 +90,7 @@ bool ParticleTree::findAndUpdateOperation(OctreeElement* element, void* extraDat
|
|||
return true;
|
||||
}
|
||||
|
||||
void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) {
|
||||
void ParticleTree::storeParticle(const Particle& particle, const SharedNodePointer& senderNode) {
|
||||
// First, look for the existing particle in the tree..
|
||||
FindAndUpdateParticleArgs args = { particle, false };
|
||||
recurseTreeWithOperation(findAndUpdateOperation, &args);
|
||||
|
@ -101,7 +101,7 @@ void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) {
|
|||
float size = std::max(MINIMUM_PARTICLE_ELEMENT_SIZE, particle.getRadius());
|
||||
ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
|
||||
|
||||
element->storeParticle(particle, senderNode);
|
||||
element->storeParticle(particle);
|
||||
}
|
||||
// what else do we need to do here to get reaveraging to work
|
||||
_isDirty = true;
|
||||
|
@ -386,7 +386,7 @@ const Particle* ParticleTree::findParticleByID(uint32_t id, bool alreadyLocked)
|
|||
|
||||
|
||||
int ParticleTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, Node* senderNode) {
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
|
||||
|
||||
int processedBytes = 0;
|
||||
// we handle these types of "edit" packets
|
||||
|
@ -415,7 +415,7 @@ int ParticleTree::processEditPacketData(PacketType packetType, const unsigned ch
|
|||
return processedBytes;
|
||||
}
|
||||
|
||||
void ParticleTree::notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode) {
|
||||
void ParticleTree::notifyNewlyCreatedParticle(const Particle& newParticle, const SharedNodePointer& senderNode) {
|
||||
_newlyCreatedHooksLock.lockForRead();
|
||||
for (size_t i = 0; i < _newlyCreatedHooks.size(); i++) {
|
||||
_newlyCreatedHooks[i]->particleCreated(newParticle, senderNode);
|
||||
|
@ -596,8 +596,7 @@ void ParticleTree::forgetParticlesDeletedBefore(quint64 sinceTime) {
|
|||
}
|
||||
|
||||
|
||||
void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr,
|
||||
Node* sourceNode) {
|
||||
void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
|
||||
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
|
||||
const unsigned char* dataAt = packetData;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
class NewlyCreatedParticleHook {
|
||||
public:
|
||||
virtual void particleCreated(const Particle& newParticle, Node* senderNode) = 0;
|
||||
virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode) = 0;
|
||||
};
|
||||
|
||||
class ParticleTree : public Octree {
|
||||
|
@ -35,11 +35,11 @@ public:
|
|||
virtual PacketType expectedDataPacketType() const { return PacketTypeParticleData; }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, Node* senderNode);
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
||||
|
||||
virtual void update();
|
||||
|
||||
void storeParticle(const Particle& particle, Node* senderNode = NULL);
|
||||
void storeParticle(const Particle& particle, const SharedNodePointer& senderNode = SharedNodePointer());
|
||||
void updateParticle(const ParticleID& particleID, const ParticleProperties& properties);
|
||||
void addParticle(const ParticleID& particleID, const ParticleProperties& properties);
|
||||
void deleteParticle(const ParticleID& particleID);
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
bool encodeParticlesDeletedSince(quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength);
|
||||
void forgetParticlesDeletedBefore(quint64 sinceTime);
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode);
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
void handleAddParticleResponse(const QByteArray& packet);
|
||||
|
||||
private:
|
||||
|
@ -82,7 +82,7 @@ private:
|
|||
static bool findAndDeleteOperation(OctreeElement* element, void* extraData);
|
||||
static bool findAndUpdateParticleIDOperation(OctreeElement* element, void* extraData);
|
||||
|
||||
void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode);
|
||||
void notifyNewlyCreatedParticle(const Particle& newParticle, const SharedNodePointer& senderNode);
|
||||
|
||||
QReadWriteLock _newlyCreatedHooksLock;
|
||||
std::vector<NewlyCreatedParticleHook*> _newlyCreatedHooks;
|
||||
|
|
|
@ -332,7 +332,7 @@ bool ParticleTreeElement::collapseChildren() {
|
|||
}
|
||||
|
||||
|
||||
void ParticleTreeElement::storeParticle(const Particle& particle, Node* senderNode) {
|
||||
void ParticleTreeElement::storeParticle(const Particle& particle) {
|
||||
_particles->push_back(particle);
|
||||
markWithChangedTime();
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
protected:
|
||||
virtual void init(unsigned char * octalCode);
|
||||
|
||||
void storeParticle(const Particle& particle, Node* senderNode = NULL);
|
||||
void storeParticle(const Particle& particle);
|
||||
|
||||
ParticleTree* _myTree;
|
||||
QList<Particle>* _particles;
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// DataServerScriptingInterface.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 1/20/2014.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <DataServerClient.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "DataServerScriptingInterface.h"
|
||||
|
||||
DataServerScriptingInterface::DataServerScriptingInterface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DataServerScriptingInterface::setValueForKey(const QString& key, const QString& value) {
|
||||
DataServerClient::putValueForKeyAndUUID(key, value, NodeList::getInstance()->getOwnerUUID());
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// DataServerScriptingInterface.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 1/20/2014.
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__DataServerScriptingInterface__
|
||||
#define __hifi__DataServerScriptingInterface__
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
class DataServerScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DataServerScriptingInterface();
|
||||
|
||||
public slots:
|
||||
void setValueForKey(const QString& key, const QString& value);
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__DataServerScriptingInterface__) */
|
|
@ -44,7 +44,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co
|
|||
AbstractMenuInterface* menu,
|
||||
AbstractControllerScriptingInterface* controllerScriptingInterface) :
|
||||
_isAvatar(false),
|
||||
_dataServerScriptingInterface(),
|
||||
_avatarData(NULL)
|
||||
{
|
||||
_scriptContents = scriptContents;
|
||||
|
@ -137,7 +136,6 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Script", this);
|
||||
registerGlobalObject("Audio", &_audioScriptingInterface);
|
||||
registerGlobalObject("Controller", _controllerScriptingInterface);
|
||||
registerGlobalObject("Data", &_dataServerScriptingInterface);
|
||||
registerGlobalObject("Particles", &_particlesScriptingInterface);
|
||||
registerGlobalObject("Quat", &_quatLibrary);
|
||||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
class ParticlesScriptingInterface;
|
||||
|
||||
#include "AbstractControllerScriptingInterface.h"
|
||||
#include "DataServerScriptingInterface.h"
|
||||
#include "Quat.h"
|
||||
#include "Vec3.h"
|
||||
|
||||
|
@ -44,9 +43,6 @@ public:
|
|||
|
||||
/// Access the ParticlesScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
|
||||
static ParticlesScriptingInterface* getParticlesScriptingInterface() { return &_particlesScriptingInterface; }
|
||||
|
||||
/// Access the DataServerScriptingInterface for access to its underlying UUID
|
||||
const DataServerScriptingInterface& getDataServerScriptingInterface() { return _dataServerScriptingInterface; }
|
||||
|
||||
/// sets the script contents, will return false if failed, will fail if script is already running
|
||||
bool setScriptContents(const QString& scriptContents);
|
||||
|
@ -98,7 +94,6 @@ private:
|
|||
static ParticlesScriptingInterface _particlesScriptingInterface;
|
||||
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
||||
AudioScriptingInterface _audioScriptingInterface;
|
||||
DataServerScriptingInterface _dataServerScriptingInterface;
|
||||
AvatarData* _avatarData;
|
||||
bool _wantMenuItems;
|
||||
QString _scriptMenuName;
|
||||
|
|
|
@ -52,8 +52,6 @@ private:
|
|||
|
||||
namespace DataServerKey {
|
||||
const QString Domain = "domain";
|
||||
const QString FaceMeshURL = "mesh";
|
||||
const QString SkeletonURL = "skeleton";
|
||||
const QString Position = "position";
|
||||
const QString Orientation = "orientation";
|
||||
const QString UUID = "uuid";
|
||||
|
|
|
@ -45,8 +45,6 @@ HifiSockAddr::HifiSockAddr(const QString& hostname, quint16 hostOrderPort) {
|
|||
}
|
||||
|
||||
HifiSockAddr& HifiSockAddr::operator=(const HifiSockAddr& rhsSockAddr) {
|
||||
//HifiSockAddr temp(rhsSockAddr);
|
||||
//swap(temp);
|
||||
_address = rhsSockAddr._address;
|
||||
_port = rhsSockAddr._port;
|
||||
|
||||
|
|
|
@ -8,15 +8,17 @@
|
|||
// A really simple class that stores a network packet between being received and being processed
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <QtDebug>
|
||||
#include <cassert>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#include "NetworkPacket.h"
|
||||
|
||||
void NetworkPacket::copyContents(const HifiSockAddr& sockAddr, const QByteArray& packet) {
|
||||
void NetworkPacket::copyContents(const SharedNodePointer& destinationNode, const QByteArray& packet) {
|
||||
if (packet.size() && packet.size() <= MAX_PACKET_SIZE) {
|
||||
_sockAddr = sockAddr;
|
||||
_destinationNode = destinationNode;
|
||||
_byteArray = packet;
|
||||
} else {
|
||||
qDebug(">>> NetworkPacket::copyContents() unexpected length = %d", packet.size());
|
||||
|
@ -24,28 +26,28 @@ void NetworkPacket::copyContents(const HifiSockAddr& sockAddr, const QByteArray&
|
|||
}
|
||||
|
||||
NetworkPacket::NetworkPacket(const NetworkPacket& packet) {
|
||||
copyContents(packet.getSockAddr(), packet.getByteArray());
|
||||
copyContents(packet.getDestinationNode(), packet.getByteArray());
|
||||
}
|
||||
|
||||
NetworkPacket::NetworkPacket(const HifiSockAddr& sockAddr, const QByteArray& packet) {
|
||||
copyContents(sockAddr, packet);
|
||||
NetworkPacket::NetworkPacket(const SharedNodePointer& destinationNode, const QByteArray& packet) {
|
||||
copyContents(destinationNode, packet);
|
||||
};
|
||||
|
||||
// copy assignment
|
||||
NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) {
|
||||
copyContents(other.getSockAddr(), other.getByteArray());
|
||||
copyContents(other.getDestinationNode(), other.getByteArray());
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef HAS_MOVE_SEMANTICS
|
||||
// move, same as copy, but other packet won't be used further
|
||||
NetworkPacket::NetworkPacket(NetworkPacket && packet) {
|
||||
copyContents(packet.getAddress(), packet.getByteArray());
|
||||
copyContents(packet.getDestinationNode(), packet.getByteArray());
|
||||
}
|
||||
|
||||
// move assignment
|
||||
NetworkPacket& NetworkPacket::operator=(NetworkPacket&& other) {
|
||||
copyContents(other.getAddress(), other.getByteArray());
|
||||
copyContents(other.getDestinationNode(), other.getByteArray());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "HifiSockAddr.h"
|
||||
|
||||
#include "SharedUtil.h" // for MAX_PACKET_SIZE
|
||||
#include "NodeList.h"
|
||||
|
||||
/// Storage of not-yet processed inbound, or not yet sent outbound generic UDP network packet
|
||||
class NetworkPacket {
|
||||
|
@ -33,15 +31,15 @@ public:
|
|||
NetworkPacket& operator= (NetworkPacket&& other); // move assignment
|
||||
#endif
|
||||
|
||||
NetworkPacket(const HifiSockAddr& sockAddr, const QByteArray& byteArray);
|
||||
NetworkPacket(const SharedNodePointer& destinationNode, const QByteArray& byteArray);
|
||||
|
||||
const HifiSockAddr& getSockAddr() const { return _sockAddr; }
|
||||
const SharedNodePointer& getDestinationNode() const { return _destinationNode; }
|
||||
const QByteArray& getByteArray() const { return _byteArray; }
|
||||
|
||||
private:
|
||||
void copyContents(const HifiSockAddr& sockAddr, const QByteArray& byteArray);
|
||||
void copyContents(const SharedNodePointer& destinationNode, const QByteArray& byteArray);
|
||||
|
||||
HifiSockAddr _sockAddr;
|
||||
SharedNodePointer _destinationNode;
|
||||
QByteArray _byteArray;
|
||||
};
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ Node::Node(const QUuid& uuid, char type, const HifiSockAddr& publicSocket, const
|
|||
_publicSocket(publicSocket),
|
||||
_localSocket(localSocket),
|
||||
_activeSocket(NULL),
|
||||
_connectionSecret(),
|
||||
_bytesReceivedMovingAverage(NULL),
|
||||
_linkedData(NULL),
|
||||
_isAlive(true),
|
||||
|
|
|
@ -56,7 +56,6 @@ public:
|
|||
|
||||
char getType() const { return _type; }
|
||||
void setType(char type) { _type = type; }
|
||||
|
||||
|
||||
const QUuid& getUUID() const { return _uuid; }
|
||||
void setUUID(const QUuid& uuid) { _uuid = uuid; }
|
||||
|
@ -76,6 +75,9 @@ public:
|
|||
|
||||
void activatePublicSocket();
|
||||
void activateLocalSocket();
|
||||
|
||||
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
||||
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
||||
|
||||
NodeData* getLinkedData() const { return _linkedData; }
|
||||
void setLinkedData(NodeData* linkedData) { _linkedData = linkedData; }
|
||||
|
@ -109,6 +111,7 @@ private:
|
|||
HifiSockAddr _publicSocket;
|
||||
HifiSockAddr _localSocket;
|
||||
HifiSockAddr* _activeSocket;
|
||||
QUuid _connectionSecret;
|
||||
SimpleMovingAverage* _bytesReceivedMovingAverage;
|
||||
NodeData* _linkedData;
|
||||
bool _isAlive;
|
||||
|
|
|
@ -64,7 +64,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
|||
_nodeSocket(this),
|
||||
_ownerType(newOwnerType),
|
||||
_nodeTypesOfInterest(),
|
||||
_ownerUUID(QUuid::createUuid()),
|
||||
_sessionUUID(),
|
||||
_numNoReplyDomainCheckIns(0),
|
||||
_assignmentServerSocket(),
|
||||
_publicSockAddr(),
|
||||
|
@ -80,6 +80,78 @@ NodeList::~NodeList() {
|
|||
clear();
|
||||
}
|
||||
|
||||
bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||
// currently this just checks if the version in the packet matches our return from versionForPacketType
|
||||
// may need to be expanded in the future for types and versions that take > than 1 byte
|
||||
|
||||
if (packet[1] != versionForPacketType(packetTypeForPacket(packet))
|
||||
&& packetTypeForPacket(packet) != PacketTypeStunResponse) {
|
||||
PacketType mismatchType = packetTypeForPacket(packet);
|
||||
int numPacketTypeBytes = arithmeticCodingValueFromBuffer(packet.data());
|
||||
|
||||
qDebug() << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender"
|
||||
<< uuidFromPacketHeader(packet) << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but"
|
||||
<< qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";
|
||||
}
|
||||
|
||||
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>() << PacketTypeDomainList
|
||||
<< PacketTypeDomainListRequest << PacketTypeStunResponse << PacketTypeDataServerConfirm
|
||||
<< PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend
|
||||
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment;
|
||||
|
||||
if (!NON_VERIFIED_PACKETS.contains(packetTypeForPacket(packet))) {
|
||||
// figure out which node this is from
|
||||
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
||||
if (sendingNode) {
|
||||
// check if the md5 hash in the header matches the hash we would expect
|
||||
if (hashFromPacketHeader(packet) == hashForPacketAndConnectionUUID(packet, sendingNode->getConnectionSecret())) {
|
||||
return true;
|
||||
} else {
|
||||
qDebug() << "Packet hash mismatch on" << packetTypeForPacket(packet) << "- Sender"
|
||||
<< uuidFromPacketHeader(packet);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Packet of type" << packetTypeForPacket(packet) << "received from unknown node with UUID"
|
||||
<< uuidFromPacketHeader(packet);
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 NodeList::writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr) {
|
||||
if (destinationNode) {
|
||||
// if we don't have an ovveriden address, assume they want to send to the node's active socket
|
||||
const HifiSockAddr* destinationSockAddr = &overridenSockAddr;
|
||||
if (overridenSockAddr.isNull()) {
|
||||
if (destinationNode->getActiveSocket()) {
|
||||
// use the node's active socket as the destination socket
|
||||
destinationSockAddr = destinationNode->getActiveSocket();
|
||||
} else {
|
||||
// we don't have a socket to send to, return 0
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray datagramCopy = datagram;
|
||||
// setup the MD5 hash for source verification in the header
|
||||
replaceHashInPacketGivenConnectionUUID(datagramCopy, destinationNode->getConnectionSecret());
|
||||
|
||||
return _nodeSocket.writeDatagram(datagramCopy, destinationSockAddr->getAddress(), destinationSockAddr->getPort());
|
||||
}
|
||||
|
||||
// didn't have a destinationNode to send to, return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
qint64 NodeList::writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr) {
|
||||
return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr);
|
||||
}
|
||||
|
||||
void NodeList::setDomainHostname(const QString& domainHostname) {
|
||||
|
||||
if (domainHostname != _domainHostname) {
|
||||
|
@ -111,44 +183,38 @@ void NodeList::setDomainHostname(const QString& domainHostname) {
|
|||
}
|
||||
}
|
||||
|
||||
void NodeList::timePingReply(const QByteArray& packet) {
|
||||
QUuid nodeUUID;
|
||||
deconstructPacketHeader(packet, nodeUUID);
|
||||
void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
SharedNodePointer matchingNode = nodeWithUUID(nodeUUID);
|
||||
quint8 pingType;
|
||||
quint64 ourOriginalTime, othersReplyTime;
|
||||
|
||||
if (matchingNode) {
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
quint64 ourOriginalTime, othersReplyTime;
|
||||
|
||||
packetStream >> ourOriginalTime >> othersReplyTime;
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
int pingTime = now - ourOriginalTime;
|
||||
int oneWayFlightTime = pingTime / 2; // half of the ping is our one way flight
|
||||
|
||||
// The other node's expected time should be our original time plus the one way flight time
|
||||
// anything other than that is clock skew
|
||||
quint64 othersExprectedReply = ourOriginalTime + oneWayFlightTime;
|
||||
int clockSkew = othersReplyTime - othersExprectedReply;
|
||||
|
||||
matchingNode->setPingMs(pingTime / 1000);
|
||||
matchingNode->setClockSkewUsec(clockSkew);
|
||||
|
||||
const bool wantDebug = false;
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "PING_REPLY from node " << *matchingNode << "\n" <<
|
||||
" now: " << now << "\n" <<
|
||||
" ourTime: " << ourOriginalTime << "\n" <<
|
||||
" pingTime: " << pingTime << "\n" <<
|
||||
" oneWayFlightTime: " << oneWayFlightTime << "\n" <<
|
||||
" othersReplyTime: " << othersReplyTime << "\n" <<
|
||||
" othersExprectedReply: " << othersExprectedReply << "\n" <<
|
||||
" clockSkew: " << clockSkew;
|
||||
}
|
||||
packetStream >> pingType >> ourOriginalTime >> othersReplyTime;
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
int pingTime = now - ourOriginalTime;
|
||||
int oneWayFlightTime = pingTime / 2; // half of the ping is our one way flight
|
||||
|
||||
// The other node's expected time should be our original time plus the one way flight time
|
||||
// anything other than that is clock skew
|
||||
quint64 othersExprectedReply = ourOriginalTime + oneWayFlightTime;
|
||||
int clockSkew = othersReplyTime - othersExprectedReply;
|
||||
|
||||
sendingNode->setPingMs(pingTime / 1000);
|
||||
sendingNode->setClockSkewUsec(clockSkew);
|
||||
|
||||
const bool wantDebug = false;
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "PING_REPLY from node " << *sendingNode << "\n" <<
|
||||
" now: " << now << "\n" <<
|
||||
" ourTime: " << ourOriginalTime << "\n" <<
|
||||
" pingTime: " << pingTime << "\n" <<
|
||||
" oneWayFlightTime: " << oneWayFlightTime << "\n" <<
|
||||
" othersReplyTime: " << othersReplyTime << "\n" <<
|
||||
" othersExprectedReply: " << othersExprectedReply << "\n" <<
|
||||
" clockSkew: " << clockSkew;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,16 +230,25 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
|
|||
}
|
||||
case PacketTypePing: {
|
||||
// send back a reply
|
||||
QByteArray replyPacket = constructPingReplyPacket(packet);
|
||||
_nodeSocket.writeDatagram(replyPacket, senderSockAddr.getAddress(), senderSockAddr.getPort());
|
||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||
if (matchingNode) {
|
||||
QByteArray replyPacket = constructPingReplyPacket(packet);
|
||||
writeDatagram(replyPacket, matchingNode, senderSockAddr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketTypePingReply: {
|
||||
// activate the appropriate socket for this node, if not yet updated
|
||||
activateSocketFromNodeCommunication(senderSockAddr);
|
||||
|
||||
// set the ping time for this node for stat collection
|
||||
timePingReply(packet);
|
||||
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
||||
|
||||
if (sendingNode) {
|
||||
// activate the appropriate socket for this node, if not yet updated
|
||||
activateSocketFromNodeCommunication(packet, sendingNode);
|
||||
|
||||
// set the ping time for this node for stat collection
|
||||
timePingReply(packet, sendingNode);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketTypeStunResponse: {
|
||||
|
@ -187,44 +262,28 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
|
|||
}
|
||||
}
|
||||
|
||||
int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
|
||||
node->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
if (!senderSockAddr.isNull() && !node->getActiveSocket()) {
|
||||
if (senderSockAddr == node->getPublicSocket()) {
|
||||
node->activatePublicSocket();
|
||||
} else if (senderSockAddr == node->getLocalSocket()) {
|
||||
node->activateLocalSocket();
|
||||
}
|
||||
}
|
||||
|
||||
if (node->getActiveSocket() || senderSockAddr.isNull()) {
|
||||
node->recordBytesReceived(packet.size());
|
||||
|
||||
if (!node->getLinkedData() && linkedDataCreateCallback) {
|
||||
linkedDataCreateCallback(node);
|
||||
}
|
||||
|
||||
int numParsedBytes = node->getLinkedData()->parseData(packet);
|
||||
return numParsedBytes;
|
||||
} else {
|
||||
// we weren't able to match the sender address to the address we have for this node, unlock and don't parse
|
||||
return 0;
|
||||
int NodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
|
||||
QMutexLocker locker(&matchingNode->getMutex());
|
||||
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
matchingNode->recordBytesReceived(packet.size());
|
||||
|
||||
if (!matchingNode->getLinkedData() && linkedDataCreateCallback) {
|
||||
linkedDataCreateCallback(matchingNode.data());
|
||||
}
|
||||
|
||||
return matchingNode->getLinkedData()->parseData(packet);
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) {
|
||||
// naively returns the first node that has a matching active HifiSockAddr
|
||||
// note that there can be multiple nodes that have a matching active socket, so this isn't a good way to uniquely identify
|
||||
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||
if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) {
|
||||
return node;
|
||||
}
|
||||
int NodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||
|
||||
if (matchingNode) {
|
||||
updateNodeWithDataFromPacket(matchingNode, packet);
|
||||
}
|
||||
|
||||
return SharedNodePointer();
|
||||
|
||||
// we weren't able to match the sender address to the address we have for this node, unlock and don't parse
|
||||
return 0;
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||
|
@ -232,6 +291,13 @@ SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
|||
return _nodeHash.value(nodeUUID);
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::sendingNodeForPacket(const QByteArray& packet) {
|
||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||
|
||||
// return the matching node, or NULL if there is no match
|
||||
return nodeWithUUID(nodeUUID);
|
||||
}
|
||||
|
||||
NodeHash NodeList::getNodeHash() {
|
||||
QMutexLocker locker(&_nodeHashMutex);
|
||||
return NodeHash(_nodeHash);
|
||||
|
@ -257,7 +323,7 @@ void NodeList::reset() {
|
|||
_nodeTypesOfInterest.clear();
|
||||
|
||||
// refresh the owner UUID
|
||||
_ownerUUID = QUuid::createUuid();
|
||||
_sessionUUID = QUuid::createUuid();
|
||||
}
|
||||
|
||||
void NodeList::addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd) {
|
||||
|
@ -492,6 +558,16 @@ void NodeList::sendDomainServerCheckIn() {
|
|||
}
|
||||
}
|
||||
|
||||
void NodeList::setSessionUUID(const QUuid& sessionUUID) {
|
||||
QUuid oldUUID = _sessionUUID;
|
||||
_sessionUUID = sessionUUID;
|
||||
|
||||
if (sessionUUID != oldUUID) {
|
||||
qDebug() << "NodeList UUID changed from" << oldUUID << "to" << _sessionUUID;
|
||||
emit uuidChanged(sessionUUID);
|
||||
}
|
||||
}
|
||||
|
||||
int NodeList::processDomainServerList(const QByteArray& packet) {
|
||||
// this is a packet from the domain server, reset the count of un-replied check-ins
|
||||
_numNoReplyDomainCheckIns = 0;
|
||||
|
@ -501,14 +577,20 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
|
|||
// setup variables to read into from QDataStream
|
||||
qint8 nodeType;
|
||||
|
||||
QUuid nodeUUID;
|
||||
QUuid nodeUUID, connectionUUID;
|
||||
|
||||
HifiSockAddr nodePublicSocket;
|
||||
HifiSockAddr nodeLocalSocket;
|
||||
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
|
||||
// pull our owner UUID from the packet, it's always the first thing
|
||||
QUuid newUUID;
|
||||
packetStream >> newUUID;
|
||||
setSessionUUID(newUUID);
|
||||
|
||||
// pull each node in the packet
|
||||
while(packetStream.device()->pos() < packet.size()) {
|
||||
packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket;
|
||||
|
||||
|
@ -518,8 +600,15 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
|
|||
nodePublicSocket.setAddress(_domainSockAddr.getAddress());
|
||||
}
|
||||
|
||||
addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket);
|
||||
SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket);
|
||||
|
||||
packetStream >> connectionUUID;
|
||||
node->setConnectionSecret(connectionUUID);
|
||||
}
|
||||
|
||||
// ping inactive nodes in conjunction with receipt of list from domain-server
|
||||
// this makes it happen every second and also pings any newly added nodes
|
||||
pingInactiveNodes();
|
||||
|
||||
return readNodes;
|
||||
}
|
||||
|
@ -544,10 +633,12 @@ void NodeList::sendAssignment(Assignment& assignment) {
|
|||
_nodeSocket.writeDatagram(packet, assignmentServerSocket->getAddress(), assignmentServerSocket->getPort());
|
||||
}
|
||||
|
||||
QByteArray NodeList::constructPingPacket() {
|
||||
QByteArray NodeList::constructPingPacket(PingType_t pingType) {
|
||||
QByteArray pingPacket = byteArrayWithPopluatedHeader(PacketTypePing);
|
||||
|
||||
QDataStream packetStream(&pingPacket, QIODevice::Append);
|
||||
|
||||
packetStream << pingType;
|
||||
packetStream << usecTimestampNow();
|
||||
|
||||
return pingPacket;
|
||||
|
@ -557,23 +648,28 @@ QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) {
|
|||
QDataStream pingPacketStream(pingPacket);
|
||||
pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
|
||||
|
||||
PingType_t typeFromOriginalPing;
|
||||
pingPacketStream >> typeFromOriginalPing;
|
||||
|
||||
quint64 timeFromOriginalPing;
|
||||
pingPacketStream >> timeFromOriginalPing;
|
||||
|
||||
QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypePingReply);
|
||||
QDataStream packetStream(&replyPacket, QIODevice::Append);
|
||||
|
||||
packetStream << timeFromOriginalPing << usecTimestampNow();
|
||||
packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow();
|
||||
|
||||
return replyPacket;
|
||||
}
|
||||
|
||||
void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) {
|
||||
QByteArray pingPacket = constructPingPacket();
|
||||
|
||||
void NodeList::pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer& node) {
|
||||
|
||||
// send the ping packet to the local and public sockets for this node
|
||||
_nodeSocket.writeDatagram(pingPacket, node->getLocalSocket().getAddress(), node->getLocalSocket().getPort());
|
||||
_nodeSocket.writeDatagram(pingPacket, node->getPublicSocket().getAddress(), node->getPublicSocket().getPort());
|
||||
QByteArray localPingPacket = constructPingPacket(PingType::Local);
|
||||
writeDatagram(localPingPacket, node, node->getLocalSocket());
|
||||
|
||||
QByteArray publicPingPacket = constructPingPacket(PingType::Public);
|
||||
writeDatagram(publicPingPacket, node, node->getPublicSocket());
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||
|
@ -586,9 +682,9 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
|||
// we didn't have this node, so add them
|
||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
|
||||
SharedNodePointer newNodeSharedPointer(newNode, &QObject::deleteLater);
|
||||
|
||||
|
||||
_nodeHash.insert(newNode->getUUID(), newNodeSharedPointer);
|
||||
|
||||
|
||||
_nodeHashMutex.unlock();
|
||||
|
||||
qDebug() << "Added" << *newNode;
|
||||
|
@ -630,11 +726,8 @@ unsigned NodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& des
|
|||
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||
// only send to the NodeTypes we are asked to send to.
|
||||
if (destinationNodeTypes.contains(node->getType())) {
|
||||
if (getNodeActiveSocketOrPing(node.data())) {
|
||||
// we know which socket is good for this node, send there
|
||||
_nodeSocket.writeDatagram(packet, node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort());
|
||||
++n;
|
||||
}
|
||||
writeDatagram(packet, node);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -645,34 +738,25 @@ void NodeList::pingInactiveNodes() {
|
|||
foreach (const SharedNodePointer& node, getNodeHash()) {
|
||||
if (!node->getActiveSocket()) {
|
||||
// we don't have an active link to this node, ping it to set that up
|
||||
pingPublicAndLocalSocketsForInactiveNode(node.data());
|
||||
pingPublicAndLocalSocketsForInactiveNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const HifiSockAddr* NodeList::getNodeActiveSocketOrPing(Node* node) {
|
||||
if (node->getActiveSocket()) {
|
||||
return node->getActiveSocket();
|
||||
} else {
|
||||
pingPublicAndLocalSocketsForInactiveNode(node);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddress) {
|
||||
|
||||
foreach (const SharedNodePointer& node, _nodeHash) {
|
||||
if (!node->getActiveSocket()) {
|
||||
// check both the public and local addresses for each node to see if we find a match
|
||||
// prioritize the private address so that we prune erroneous local matches
|
||||
if (node->getPublicSocket() == nodeAddress) {
|
||||
node->activatePublicSocket();
|
||||
break;
|
||||
} else if (node->getLocalSocket() == nodeAddress) {
|
||||
node->activateLocalSocket();
|
||||
break;
|
||||
}
|
||||
}
|
||||
void NodeList::activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||
// deconstruct this ping packet to see if it is a public or local reply
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
quint8 pingType;
|
||||
packetStream >> pingType;
|
||||
|
||||
// if this is a local or public ping then we can activate a socket
|
||||
// we do nothing with agnostic pings, those are simply for timing
|
||||
if (pingType == PingType::Local && sendingNode->getActiveSocket() != &sendingNode->getLocalSocket()) {
|
||||
sendingNode->activateLocalSocket();
|
||||
} else if (pingType == PingType::Public && !sendingNode->getActiveSocket()) {
|
||||
sendingNode->activatePublicSocket();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,13 @@ typedef QSharedPointer<Node> SharedNodePointer;
|
|||
typedef QHash<QUuid, SharedNodePointer> NodeHash;
|
||||
Q_DECLARE_METATYPE(SharedNodePointer)
|
||||
|
||||
typedef quint8 PingType_t;
|
||||
namespace PingType {
|
||||
const PingType_t Agnostic = 0;
|
||||
const PingType_t Local = 1;
|
||||
const PingType_t Public = 2;
|
||||
}
|
||||
|
||||
class NodeList : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -70,10 +77,17 @@ public:
|
|||
|
||||
unsigned short getDomainPort() const { return _domainSockAddr.getPort(); }
|
||||
|
||||
const QUuid& getOwnerUUID() const { return _ownerUUID; }
|
||||
void setOwnerUUID(const QUuid& ownerUUID) { _ownerUUID = ownerUUID; }
|
||||
const QUuid& getSessionUUID() const { return _sessionUUID; }
|
||||
void setSessionUUID(const QUuid& sessionUUID);
|
||||
|
||||
QUdpSocket& getNodeSocket() { return _nodeSocket; }
|
||||
|
||||
bool packetVersionAndHashMatch(const QByteArray& packet);
|
||||
|
||||
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||
qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||
|
||||
void(*linkedDataCreateCallback)(Node *);
|
||||
|
||||
|
@ -93,27 +107,27 @@ public:
|
|||
void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; }
|
||||
void sendAssignment(Assignment& assignment);
|
||||
|
||||
QByteArray constructPingPacket();
|
||||
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic);
|
||||
QByteArray constructPingReplyPacket(const QByteArray& pingPacket);
|
||||
void pingPublicAndLocalSocketsForInactiveNode(Node* node);
|
||||
void pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer& node);
|
||||
|
||||
SharedNodePointer nodeWithAddress(const HifiSockAddr& senderSockAddr);
|
||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||
|
||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
|
||||
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
||||
|
||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
|
||||
|
||||
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
void processKillNode(const QByteArray& datagram);
|
||||
|
||||
int updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
int updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray& packet);
|
||||
int findNodeAndUpdateWithDataFromPacket(const QByteArray& packet);
|
||||
|
||||
unsigned broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes);
|
||||
SharedNodePointer soloNodeOfType(char nodeType);
|
||||
|
||||
void loadData(QSettings* settings);
|
||||
void saveData(QSettings* settings);
|
||||
|
||||
const HifiSockAddr* getNodeActiveSocketOrPing(Node* node);
|
||||
public slots:
|
||||
void sendDomainServerCheckIn();
|
||||
void pingInactiveNodes();
|
||||
|
@ -122,6 +136,7 @@ public slots:
|
|||
void killNodeWithUUID(const QUuid& nodeUUID);
|
||||
signals:
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void uuidChanged(const QUuid& ownerUUID);
|
||||
void nodeAdded(SharedNodePointer);
|
||||
void nodeKilled(SharedNodePointer);
|
||||
private:
|
||||
|
@ -143,15 +158,15 @@ private:
|
|||
QUdpSocket _nodeSocket;
|
||||
NodeType_t _ownerType;
|
||||
NodeSet _nodeTypesOfInterest;
|
||||
QUuid _ownerUUID;
|
||||
QUuid _sessionUUID;
|
||||
int _numNoReplyDomainCheckIns;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
HifiSockAddr _publicSockAddr;
|
||||
bool _hasCompletedInitialSTUNFailure;
|
||||
unsigned int _stunRequestsSinceSuccess;
|
||||
|
||||
void activateSocketFromNodeCommunication(const HifiSockAddr& nodeSockAddr);
|
||||
void timePingReply(const QByteArray& packet);
|
||||
void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode);
|
||||
void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode);
|
||||
void resetDomainData(char domainField[], const char* domainData);
|
||||
void domainLookup();
|
||||
void clear();
|
||||
|
|
|
@ -46,6 +46,17 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
switch (type) {
|
||||
case PacketTypeParticleData:
|
||||
return 1;
|
||||
case PacketTypeDomainList:
|
||||
case PacketTypeDomainListRequest:
|
||||
return 1;
|
||||
case PacketTypeCreateAssignment:
|
||||
case PacketTypeRequestAssignment:
|
||||
return 1;
|
||||
case PacketTypeDataServerGet:
|
||||
case PacketTypeDataServerPut:
|
||||
case PacketTypeDataServerConfirm:
|
||||
case PacketTypeDataServerSend:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,53 +80,53 @@ int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionU
|
|||
int numTypeBytes = packArithmeticallyCodedValue(type, packet);
|
||||
packet[numTypeBytes] = versionForPacketType(type);
|
||||
|
||||
QUuid packUUID = connectionUUID.isNull() ? NodeList::getInstance()->getOwnerUUID() : connectionUUID;
|
||||
char* position = packet + numTypeBytes + sizeof(PacketVersion);
|
||||
|
||||
QUuid packUUID = connectionUUID.isNull() ? NodeList::getInstance()->getSessionUUID() : connectionUUID;
|
||||
|
||||
QByteArray rfcUUID = packUUID.toRfc4122();
|
||||
memcpy(packet + numTypeBytes + sizeof(PacketVersion), rfcUUID.constData(), NUM_BYTES_RFC4122_UUID);
|
||||
memcpy(position, rfcUUID.constData(), NUM_BYTES_RFC4122_UUID);
|
||||
position += NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
// pack 16 bytes of zeros where the md5 hash will be placed one data is packed
|
||||
memset(position, 0, NUM_BYTES_MD5_HASH);
|
||||
position += NUM_BYTES_MD5_HASH;
|
||||
|
||||
// return the number of bytes written for pointer pushing
|
||||
return numTypeBytes + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
||||
}
|
||||
|
||||
bool packetVersionMatch(const QByteArray& packet) {
|
||||
// currently this just checks if the version in the packet matches our return from versionForPacketType
|
||||
// may need to be expanded in the future for types and versions that take > than 1 byte
|
||||
|
||||
if (packet[1] == versionForPacketType(packetTypeForPacket(packet)) || packetTypeForPacket(packet) == PacketTypeStunResponse) {
|
||||
return true;
|
||||
} else {
|
||||
PacketType mismatchType = packetTypeForPacket(packet);
|
||||
int numPacketTypeBytes = arithmeticCodingValueFromBuffer(packet.data());
|
||||
|
||||
QUuid nodeUUID;
|
||||
deconstructPacketHeader(packet, nodeUUID);
|
||||
|
||||
qDebug() << "Packet mismatch on" << packetTypeForPacket(packet) << "- Sender"
|
||||
<< nodeUUID << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but"
|
||||
<< qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";
|
||||
|
||||
return false;
|
||||
}
|
||||
return position - packet;
|
||||
}
|
||||
|
||||
int numBytesForPacketHeader(const QByteArray& packet) {
|
||||
// returns the number of bytes used for the type, version, and UUID
|
||||
return numBytesArithmeticCodingFromBuffer(packet.data()) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
||||
return numBytesArithmeticCodingFromBuffer(packet.data()) + NUM_STATIC_HEADER_BYTES;
|
||||
}
|
||||
|
||||
int numBytesForPacketHeader(const char* packet) {
|
||||
// returns the number of bytes used for the type, version, and UUID
|
||||
return numBytesArithmeticCodingFromBuffer(packet) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
||||
return numBytesArithmeticCodingFromBuffer(packet) + NUM_STATIC_HEADER_BYTES;
|
||||
}
|
||||
|
||||
int numBytesForPacketHeaderGivenPacketType(PacketType type) {
|
||||
return (int) ceilf((float)type / 255) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
|
||||
return (int) ceilf((float)type / 255) + NUM_STATIC_HEADER_BYTES;
|
||||
}
|
||||
|
||||
void deconstructPacketHeader(const QByteArray& packet, QUuid& senderUUID) {
|
||||
senderUUID = QUuid::fromRfc4122(packet.mid(numBytesArithmeticCodingFromBuffer(packet.data()) + sizeof(PacketVersion),
|
||||
NUM_BYTES_RFC4122_UUID));
|
||||
QUuid uuidFromPacketHeader(const QByteArray& packet) {
|
||||
return QUuid::fromRfc4122(packet.mid(numBytesArithmeticCodingFromBuffer(packet.data()) + sizeof(PacketVersion),
|
||||
NUM_BYTES_RFC4122_UUID));
|
||||
}
|
||||
|
||||
QByteArray hashFromPacketHeader(const QByteArray& packet) {
|
||||
return packet.mid(numBytesForPacketHeader(packet) - NUM_BYTES_MD5_HASH, NUM_BYTES_MD5_HASH);
|
||||
}
|
||||
|
||||
QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID) {
|
||||
return QCryptographicHash::hash(packet.mid(numBytesForPacketHeader(packet)) + connectionUUID.toRfc4122(),
|
||||
QCryptographicHash::Md5);
|
||||
}
|
||||
|
||||
void replaceHashInPacketGivenConnectionUUID(QByteArray& packet, const QUuid& connectionUUID) {
|
||||
packet.replace(numBytesForPacketHeader(packet) - NUM_BYTES_MD5_HASH, NUM_BYTES_MD5_HASH,
|
||||
hashForPacketAndConnectionUUID(packet, connectionUUID));
|
||||
}
|
||||
|
||||
PacketType packetTypeForPacket(const QByteArray& packet) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_PacketHeaders_h
|
||||
#define hifi_PacketHeaders_h
|
||||
|
||||
#include <QtCore/QCryptographicHash>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include "UUID.h"
|
||||
|
@ -51,12 +52,15 @@ enum PacketType {
|
|||
PacketTypeParticleAddOrEdit,
|
||||
PacketTypeParticleErase,
|
||||
PacketTypeParticleAddResponse,
|
||||
PacketTypeMetavoxelData
|
||||
PacketTypeMetavoxelData,
|
||||
PacketTypeAvatarIdentity
|
||||
};
|
||||
|
||||
typedef char PacketVersion;
|
||||
|
||||
const int MAX_PACKET_HEADER_BYTES = sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;;
|
||||
const int NUM_BYTES_MD5_HASH = 16;
|
||||
const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH;
|
||||
const int MAX_PACKET_HEADER_BYTES = sizeof(PacketType) + NUM_STATIC_HEADER_BYTES;
|
||||
|
||||
PacketVersion versionForPacketType(PacketType type);
|
||||
|
||||
|
@ -66,17 +70,20 @@ QByteArray byteArrayWithPopluatedHeader(PacketType type, const QUuid& connection
|
|||
int populatePacketHeader(QByteArray& packet, PacketType type, const QUuid& connectionUUID = nullUUID);
|
||||
int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionUUID = nullUUID);
|
||||
|
||||
bool packetVersionMatch(const QByteArray& packet);
|
||||
|
||||
int numBytesForPacketHeader(const QByteArray& packet);
|
||||
int numBytesForPacketHeader(const char* packet);
|
||||
int numBytesForPacketHeaderGivenPacketType(PacketType type);
|
||||
|
||||
void deconstructPacketHeader(const QByteArray& packet, QUuid& senderUUID);
|
||||
QUuid uuidFromPacketHeader(const QByteArray& packet);
|
||||
|
||||
QByteArray hashFromPacketHeader(const QByteArray& packet);
|
||||
QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID);
|
||||
void replaceHashInPacketGivenConnectionUUID(QByteArray& packet, const QUuid& connectionUUID);
|
||||
|
||||
PacketType packetTypeForPacket(const QByteArray& packet);
|
||||
PacketType packetTypeForPacket(const char* packet);
|
||||
|
||||
int arithmeticCodingValueFromBuffer(const char* checkValue);
|
||||
int numBytesArithmeticCodingFromBuffer(const char* checkValue);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -47,8 +47,8 @@ PacketSender::~PacketSender() {
|
|||
}
|
||||
|
||||
|
||||
void PacketSender::queuePacketForSending(const HifiSockAddr& address, const QByteArray& packet) {
|
||||
NetworkPacket networkPacket(address, packet);
|
||||
void PacketSender::queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet) {
|
||||
NetworkPacket networkPacket(destinationNode, packet);
|
||||
lock();
|
||||
_packets.push_back(networkPacket);
|
||||
unlock();
|
||||
|
@ -263,9 +263,7 @@ bool PacketSender::nonThreadedProcess() {
|
|||
unlock();
|
||||
|
||||
// send the packet through the NodeList...
|
||||
NodeList::getInstance()->getNodeSocket().writeDatagram(temporary.getByteArray(),
|
||||
temporary.getSockAddr().getAddress(),
|
||||
temporary.getSockAddr().getPort());
|
||||
NodeList::getInstance()->writeDatagram(temporary.getByteArray(), temporary.getDestinationNode());
|
||||
packetsSentThisCall++;
|
||||
_packetsOverCheckInterval++;
|
||||
_totalPacketsSent++;
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
/// \param packetData pointer to data
|
||||
/// \param ssize_t packetLength size of data
|
||||
/// \thread any thread, typically the application thread
|
||||
void queuePacketForSending(const HifiSockAddr& address, const QByteArray& packet);
|
||||
void queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet);
|
||||
|
||||
void setPacketsPerSecond(int packetsPerSecond);
|
||||
int getPacketsPerSecond() const { return _packetsPerSecond; }
|
||||
|
|
|
@ -16,14 +16,11 @@ ReceivedPacketProcessor::ReceivedPacketProcessor() {
|
|||
_dontSleep = false;
|
||||
}
|
||||
|
||||
void ReceivedPacketProcessor::queueReceivedPacket(const HifiSockAddr& address, const QByteArray& packet) {
|
||||
void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& destinationNode, const QByteArray& packet) {
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(address);
|
||||
if (node) {
|
||||
node->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
destinationNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
NetworkPacket networkPacket(address, packet);
|
||||
NetworkPacket networkPacket(destinationNode, packet);
|
||||
lock();
|
||||
_packets.push_back(networkPacket);
|
||||
unlock();
|
||||
|
@ -44,7 +41,7 @@ bool ReceivedPacketProcessor::process() {
|
|||
NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us
|
||||
_packets.erase(_packets.begin()); // remove the oldest packet
|
||||
unlock(); // let others add to the packets
|
||||
processPacket(temporary.getSockAddr(), temporary.getByteArray()); // process our temporary copy
|
||||
processPacket(temporary.getDestinationNode(), temporary.getByteArray()); // process our temporary copy
|
||||
}
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
/// \param packetData pointer to received data
|
||||
/// \param ssize_t packetLength size of received data
|
||||
/// \thread network receive thread
|
||||
void queueReceivedPacket(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
void queueReceivedPacket(const SharedNodePointer& destinationNode, const QByteArray& packet);
|
||||
|
||||
/// Are there received packets waiting to be processed
|
||||
bool hasPacketsToProcess() const { return _packets.size() > 0; }
|
||||
|
@ -38,7 +38,7 @@ protected:
|
|||
/// \param packetData pointer to received data
|
||||
/// \param ssize_t packetLength size of received data
|
||||
/// \thread "this" individual processing thread
|
||||
virtual void processPacket(const HifiSockAddr& senderAddress, const QByteArray& packet) = 0;
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) = 0;
|
||||
|
||||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process();
|
||||
|
|
|
@ -60,3 +60,16 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
|||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadedAssignment::readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr) {
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
if (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
destinationByteArray.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(destinationByteArray.data(), destinationByteArray.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,10 @@ public slots:
|
|||
|
||||
virtual void deleteLater();
|
||||
|
||||
virtual void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) = 0;
|
||||
virtual void readPendingDatagrams() = 0;
|
||||
protected:
|
||||
bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr);
|
||||
|
||||
void commonInit(const char* targetName, NodeType_t nodeType);
|
||||
bool _isFinished;
|
||||
private slots:
|
||||
|
|
|
@ -522,7 +522,7 @@ bool VoxelTree::handlesEditPacketType(PacketType packetType) const {
|
|||
}
|
||||
|
||||
int VoxelTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, Node* senderNode) {
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& node) {
|
||||
|
||||
// we handle these types of "edit" packets
|
||||
switch (packetType) {
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
virtual PacketType expectedDataPacketType() const { return PacketTypeVoxelData; }
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, Node* senderNode);
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& node);
|
||||
void processSetVoxelsBitstream(const unsigned char* bitstream, int bufferSizeBytes);
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue