From 7d1a64ca8ce2863669a4c45fa03a1ee32bc88d3a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 13 Jan 2014 17:09:21 -0800 Subject: [PATCH] change NodeList container to QHash with QSharedPointer --- assignment-client/src/audio/AudioMixer.cpp | 21 +- assignment-client/src/avatars/AvatarMixer.cpp | 18 +- domain-server/src/DomainServer.cpp | 32 +- domain-server/src/DomainServer.h | 6 +- interface/src/Application.cpp | 202 ++++-------- interface/src/Application.h | 10 +- interface/src/Audio.cpp | 4 +- interface/src/DataServerClient.cpp | 11 +- interface/src/MetavoxelSystem.cpp | 13 +- interface/src/MetavoxelSystem.h | 10 +- interface/src/VoxelPacketProcessor.cpp | 5 +- interface/src/VoxelSystem.cpp | 12 +- interface/src/VoxelSystem.h | 8 +- interface/src/avatar/Avatar.cpp | 21 -- interface/src/avatar/Avatar.h | 2 - interface/src/avatar/Hand.cpp | 25 +- interface/src/avatar/MyAvatar.cpp | 71 +---- interface/src/avatar/MyAvatar.h | 1 - interface/src/ui/VoxelStatsDialog.cpp | 95 +++--- libraries/audio/src/AudioInjector.cpp | 4 +- libraries/avatars/src/AvatarData.cpp | 9 - libraries/avatars/src/AvatarData.h | 5 - .../src/OctreeInboundPacketProcessor.cpp | 6 +- .../octree-server/src/OctreeSendThread.cpp | 4 +- libraries/octree-server/src/OctreeServer.cpp | 15 +- libraries/octree-server/src/OctreeServer.h | 10 +- libraries/octree/src/JurisdictionListener.cpp | 24 +- libraries/octree/src/JurisdictionListener.h | 12 +- libraries/octree/src/JurisdictionSender.cpp | 4 +- libraries/octree/src/JurisdictionSender.h | 1 + .../octree/src/OctreeEditPacketSender.cpp | 43 +-- .../particles/src/ParticleCollisionSystem.cpp | 14 +- libraries/shared/src/NodeList.cpp | 299 +++++------------- libraries/shared/src/NodeList.h | 73 +---- .../shared/src/ReceivedPacketProcessor.cpp | 2 +- 35 files changed, 355 insertions(+), 737 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index e315d366f8..d15f7172ae 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -182,15 +182,13 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf } void AudioMixer::prepareMixForListeningNode(Node* node) { - NodeList* nodeList = NodeList::getInstance(); - AvatarAudioRingBuffer* nodeRingBuffer = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer(); // zero out the client mix for this node memset(_clientSamples, 0, sizeof(_clientSamples)); // loop through all other nodes that have sufficient audio to mix - for (NodeList::iterator otherNode = nodeList->begin(); otherNode != nodeList->end(); otherNode++) { + foreach(SharedNodePointer otherNode, NodeList::getInstance()->getNodeHash()) { if (otherNode->getLinkedData()) { AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData(); @@ -200,7 +198,7 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { PositionalAudioRingBuffer* otherNodeBuffer = otherNodeClientData->getRingBuffers()[i]; if ((*otherNode != *node - || otherNodeBuffer->shouldLoopbackForNode()) + || otherNodeBuffer->shouldLoopbackForNode()) && otherNodeBuffer->willBeAddedToMix()) { addBufferToMixForListeningNodeWithBuffer(otherNodeBuffer, nodeRingBuffer); } @@ -220,10 +218,10 @@ void AudioMixer::processDatagram(const QByteArray& dataByteArray, const HifiSock NodeList* nodeList = NodeList::getInstance(); - Node* matchingNode = nodeList->nodeWithUUID(nodeUUID); + SharedNodePointer matchingNode = nodeList->nodeWithUUID(nodeUUID); if (matchingNode) { - nodeList->updateNodeWithData(matchingNode, senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); + nodeList->updateNodeWithData(matchingNode.data(), senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); if (!matchingNode->getActiveSocket()) { // we don't have an active socket for this node, but they're talking to us @@ -264,14 +262,14 @@ void AudioMixer::run() { if (_isFinished) { break; } - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getLinkedData()) { ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); } } - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getType() == NODE_TYPE_AGENT && node->getActiveSocket() && node->getLinkedData() && ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioRingBuffer()) { prepareMixForListeningNode(&(*node)); @@ -284,12 +282,13 @@ void AudioMixer::run() { } // push forward the next output pointers for any audio buffers we used - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getLinkedData()) { ((AudioMixerClientData*) node->getLinkedData())->pushBuffersAfterFrameSend(); } } + int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f6096fd18a..b614e7ac2b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -67,7 +67,7 @@ void broadcastAvatarData() { NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT && node->getActiveSocket()) { // reset packet pointers for this node @@ -76,7 +76,7 @@ void broadcastAvatarData() { // this is an AGENT we have received head data from // send back a packet with other active node data to this node - for (NodeList::iterator otherNode = nodeList->begin(); otherNode != nodeList->end(); otherNode++) { + foreach(SharedNodePointer otherNode, nodeList->getNodeHash()) { if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()) { unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], @@ -109,13 +109,11 @@ void broadcastAvatarData() { packetsSent++; //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - NodeList::getInstance()->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, - node->getActiveSocket()->getAddress(), - node->getActiveSocket()->getPort()); + nodeList->getNodeSocket().writeDatagram((char*) broadcastPacket, currentBufferPosition - broadcastPacket, + node->getActiveSocket()->getAddress(), + node->getActiveSocket()->getPort()); } } - - } void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr) { @@ -128,11 +126,11 @@ void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSoc NUM_BYTES_RFC4122_UUID)); // add or update the node in our list - Node* avatarNode = nodeList->nodeWithUUID(nodeUUID); + SharedNodePointer avatarNode = nodeList->nodeWithUUID(nodeUUID); if (avatarNode) { // parse positional data from an node - nodeList->updateNodeWithData(avatarNode, senderSockAddr, + nodeList->updateNodeWithData(avatarNode.data(), senderSockAddr, (unsigned char*) dataByteArray.data(), dataByteArray.size()); } else { break; @@ -144,7 +142,7 @@ void AvatarMixer::processDatagram(const QByteArray& dataByteArray, const HifiSoc QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader((unsigned char*) dataByteArray.data()), NUM_BYTES_RFC4122_UUID)); // let everyone else know about the update - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getActiveSocket() && node->getUUID() != nodeUUID) { nodeList->getNodeSocket().writeDatagram(dataByteArray, node->getActiveSocket()->getAddress(), diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ec1875668a..4d47aa3885 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -77,7 +77,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : // Start the web server. mg_start(&callbacks, NULL, options); - nodeList->addHook(this); + connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); if (!_staticAssignmentFile.exists() || _voxelServerConfig) { @@ -171,10 +171,10 @@ void DomainServer::readAvailableDatagrams() { nodeLocalAddress, nodeUUID))) { - Node* checkInNode = nodeList->addOrUpdateNode(nodeUUID, - nodeType, - nodePublicAddress, - nodeLocalAddress); + SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, + nodeType, + nodePublicAddress, + nodeLocalAddress); if (matchingStaticAssignment) { // this was a newly added node with a matching static assignment @@ -201,7 +201,7 @@ void DomainServer::readAvailableDatagrams() { if (numInterestTypes > 0) { // if the node has sent no types of interest, assume they want nothing but their own ID back - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getUUID() != nodeUUID && memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) { @@ -318,9 +318,7 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) { QJsonObject assignedNodesJSON; // enumerate the NodeList to find the assigned nodes - NodeList* nodeList = NodeList::getInstance(); - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getLinkedData()) { // add the node using the UUID as the key QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID()); @@ -372,10 +370,10 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) { // enumerate the NodeList to find the assigned nodes NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { // add the node using the UUID as the key QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID()); - nodesJSON[uuidString] = jsonObjectForNode(&(*node)); + nodesJSON[uuidString] = jsonObjectForNode(node.data()); } rootJSON["nodes"] = nodesJSON; @@ -410,14 +408,14 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) { QUuid deleteUUID = QUuid(QString(ri->uri + strlen(URI_NODE) + sizeof('/'))); if (!deleteUUID.isNull()) { - Node *nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID); + SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID); if (nodeToKill) { // start with a 200 response mg_printf(connection, "%s", RESPONSE_200); // we have a valid UUID and node - kill the node that has this assignment - NodeList::getInstance()->killNode(nodeToKill); + NodeList::getInstance()->killNodeWithUUID(deleteUUID); // successfully processed request return 1; @@ -494,10 +492,6 @@ void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignme } } -void DomainServer::nodeAdded(Node* node) { - -} - void DomainServer::nodeKilled(Node* node) { // if this node has linked data it was from an assignment if (node->getLinkedData()) { @@ -741,7 +735,7 @@ bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePu const QUuid& checkInUUID) { NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getLinkedData() && nodePublicSocket == node->getPublicSocket() && nodeLocalSocket == node->getLocalSocket() @@ -773,7 +767,7 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { NodeList* nodeList = NodeList::getInstance(); // enumerate the nodes and check if there is one with an attached assignment with matching UUID - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getLinkedData()) { Assignment* linkedAssignment = (Assignment*) node->getLinkedData(); if (linkedAssignment->getUUID() == _staticAssignments[i].getUUID()) { diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 10cb58b786..99bd560228 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -22,7 +22,7 @@ const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000; -class DomainServer : public QCoreApplication, public NodeListHook { +class DomainServer : public QCoreApplication { Q_OBJECT public: DomainServer(int argc, char* argv[]); @@ -31,10 +31,10 @@ public: static void setDomainServerInstance(DomainServer* domainServer); - /// Called by NodeList to inform us that a node has been added. - void nodeAdded(Node* node); +public slots: /// Called by NodeList to inform us that a node has been killed. void nodeKilled(Node* node); + private: static int civetwebRequestHandler(struct mg_connection *connection); static void civetwebUploadHandler(struct mg_connection *connection, const char *path); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 958995daae..e28114034b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -173,9 +173,11 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : connect(audioThread, SIGNAL(started()), &_audio, SLOT(start())); audioThread->start(); - - nodeList->addHook(&_voxels); - nodeList->addHook(this); + + 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))); + nodeList->addDomainListener(this); // network receive thread and voxel parsing thread are both controlled by the --nonblocking command line @@ -263,8 +265,6 @@ Application::~Application() { _audio.thread()->wait(); storeSizeAndPosition(); - NodeList::getInstance()->removeHook(&_voxels); - NodeList::getInstance()->removeHook(this); NodeList::getInstance()->removeDomainListener(this); _sharedVoxelSystem.changeTree(new VoxelTree); @@ -1441,7 +1441,7 @@ void Application::terminate() { static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& dataBytes) { // record the packet for stats-tracking Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AVATARS).updateValue(dataBytes); - Node* avatarMixerNode = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); + SharedNodePointer avatarMixerNode = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); if (avatarMixerNode) { avatarMixerNode->recordBytesReceived(dataBytes); } @@ -1458,7 +1458,7 @@ static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& da dataBytes -= NUM_BYTES_RFC4122_UUID; // make sure the node exists - Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID); + SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(nodeUUID); if (!node || !node->getLinkedData()) { return NULL; } @@ -1985,16 +1985,16 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) { - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar* avatar = (Avatar*)node->getLinkedData(); float distance; + if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) { // rescale to compensate for head embiggening eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) * - (avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot(); - + (avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot(); + _lookatIndicatorScale = avatar->getHead().getScale(); _lookatOtherPosition = avatar->getHead().getPosition(); nodeUUID = avatar->getOwningNode()->getUUID(); @@ -2002,6 +2002,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con } } } + return NULL; } @@ -2026,71 +2027,6 @@ void Application::renderLookatIndicator(glm::vec3 pointOfInterest) { renderCircle(haloOrigin, INDICATOR_RADIUS, IDENTITY_UP, NUM_SEGMENTS); } -void maybeBeginFollowIndicator(bool& began) { - if (!began) { - Application::getInstance()->getGlowEffect()->begin(); - glLineWidth(5); - glBegin(GL_LINES); - began = true; - } -} - -void Application::renderFollowIndicator() { - NodeList* nodeList = NodeList::getInstance(); - - // initialize lazily so that we don't enable the glow effect unnecessarily - bool began = false; - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) { - if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { - Avatar* avatar = (Avatar *) node->getLinkedData(); - Avatar* leader = NULL; - - if (!avatar->getLeaderUUID().isNull()) { - if (avatar->getLeaderUUID() == NodeList::getInstance()->getOwnerUUID()) { - leader = &_myAvatar; - } else { - for (NodeList::iterator it = nodeList->begin(); it != nodeList->end(); ++it) { - if(it->getUUID() == avatar->getLeaderUUID() - && it->getType() == NODE_TYPE_AGENT) { - leader = (Avatar*) it->getLinkedData(); - } - } - } - - if (leader != NULL) { - maybeBeginFollowIndicator(began); - glColor3f(1.f, 0.f, 0.f); - glVertex3f((avatar->getHead().getPosition().x + avatar->getPosition().x) / 2.f, - (avatar->getHead().getPosition().y + avatar->getPosition().y) / 2.f, - (avatar->getHead().getPosition().z + avatar->getPosition().z) / 2.f); - glColor3f(0.f, 1.f, 0.f); - glVertex3f((leader->getHead().getPosition().x + leader->getPosition().x) / 2.f, - (leader->getHead().getPosition().y + leader->getPosition().y) / 2.f, - (leader->getHead().getPosition().z + leader->getPosition().z) / 2.f); - } - } - } - } - - if (_myAvatar.getLeadingAvatar() != NULL) { - maybeBeginFollowIndicator(began); - glColor3f(1.f, 0.f, 0.f); - glVertex3f((_myAvatar.getHead().getPosition().x + _myAvatar.getPosition().x) / 2.f, - (_myAvatar.getHead().getPosition().y + _myAvatar.getPosition().y) / 2.f, - (_myAvatar.getHead().getPosition().z + _myAvatar.getPosition().z) / 2.f); - glColor3f(0.f, 1.f, 0.f); - glVertex3f((_myAvatar.getLeadingAvatar()->getHead().getPosition().x + _myAvatar.getLeadingAvatar()->getPosition().x) / 2.f, - (_myAvatar.getLeadingAvatar()->getHead().getPosition().y + _myAvatar.getLeadingAvatar()->getPosition().y) / 2.f, - (_myAvatar.getLeadingAvatar()->getHead().getPosition().z + _myAvatar.getLeadingAvatar()->getPosition().z) / 2.f); - } - - if (began) { - glEnd(); - _glowEffect.end(); - } -} - void Application::renderHighlightVoxel(VoxelDetail voxel) { glDisable(GL_LIGHTING); glPushMatrix(); @@ -2108,9 +2044,8 @@ void Application::renderHighlightVoxel(VoxelDetail voxel) { void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); - NodeList* nodeList = NodeList::getInstance(); - - for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { node->lock(); if (node->getLinkedData()) { Avatar *avatar = (Avatar *)node->getLinkedData(); @@ -2739,39 +2674,36 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node unsigned char voxelQueryPacket[MAX_PACKET_SIZE]; - NodeList* nodeList = NodeList::getInstance(); - // Iterate all of the nodes, and get a count of how many voxel servers we have... int totalServers = 0; int inViewServers = 0; int unknownJurisdictionServers = 0; - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { // only send to the NodeTypes that are serverType if (node->getActiveSocket() != NULL && node->getType() == serverType) { totalServers++; - + // get the server bounds for this server QUuid nodeUUID = node->getUUID(); - + // if we haven't heard from this voxel server, go ahead and send it a query, so we // can get the jurisdiction... if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { unknownJurisdictionServers++; } else { const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - + unsigned char* rootCode = map.getRootOctalCode(); - + if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); serverBounds.scale(TREE_SCALE); - + ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); - + if (serverFrustumLocation != ViewFrustum::OUTSIDE) { inViewServers++; } @@ -2804,18 +2736,20 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node if (wantExtraDebugging && unknownJurisdictionServers > 0) { qDebug("perServerPPS: %d perUnknownServer: %d\n", perServerPPS, perUnknownServer); } - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + NodeList* nodeList = NodeList::getInstance(); + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { // only send to the NodeTypes that are serverType if (node->getActiveSocket() != NULL && node->getType() == serverType) { - - + + // get the server bounds for this server QUuid nodeUUID = node->getUUID(); - + bool inView = false; bool unknownView = false; - + // if we haven't heard from this voxel server, go ahead and send it a query, so we // can get the jurisdiction... if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { @@ -2825,15 +2759,15 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node } } else { const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - + unsigned char* rootCode = map.getRootOctalCode(); - + if (rootCode) { VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); serverBounds.scale(TREE_SCALE); - + ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); if (serverFrustumLocation != ViewFrustum::OUTSIDE) { inView = true; @@ -2846,15 +2780,15 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node } } } - + if (inView) { _voxelQuery.setMaxOctreePacketsPerSecond(perServerPPS); } else if (unknownView) { if (wantExtraDebugging) { qDebug() << "no known jurisdiction for node " << *node << ", give it budget of " - << perUnknownServer << " to send us jurisdiction.\n"; + << perUnknownServer << " to send us jurisdiction.\n"; } - + // set the query's position/orientation to be degenerate in a manner that will get the scene quickly // If there's only one server, then don't do this, and just let the normal voxel query pass through // as expected... this way, we will actually get a valid scene if there is one to be seen @@ -2878,24 +2812,24 @@ void Application::queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, Node } // set up the packet for sending... unsigned char* endOfVoxelQueryPacket = voxelQueryPacket; - + // insert packet type/version and node UUID endOfVoxelQueryPacket += populateTypeAndVersion(endOfVoxelQueryPacket, packetType); QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122(); memcpy(endOfVoxelQueryPacket, ownerUUID.constData(), ownerUUID.size()); endOfVoxelQueryPacket += ownerUUID.size(); - + // encode the query data... endOfVoxelQueryPacket += _voxelQuery.getBroadcastData(endOfVoxelQueryPacket); - + 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()); + node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); } - + // Feed number of bytes to corresponding channel of the bandwidth meter _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength); } @@ -3252,12 +3186,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } } - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... renderFollowIndicator..."); - renderFollowIndicator(); - } - // render transmitter pick ray, if non-empty if (_transmitterPickStart != _transmitterPickEnd) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), @@ -3384,12 +3312,12 @@ void Application::displayOverlay() { glPointSize(1.0f); char nodes[100]; - NodeList* nodeList = NodeList::getInstance(); int totalAvatars = 0, totalServers = 0; - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++; } + sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars); drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, nodes, 1, 0, 0); } @@ -3489,8 +3417,8 @@ void Application::displayStats() { int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0; NodeList* nodeList = NodeList::getInstance(); - Node* audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - Node* avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); + SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0; pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0; @@ -3499,7 +3427,8 @@ void Application::displayStats() { // Now handle voxel servers, since there could be more than one, we average their ping times unsigned long totalPingVoxel = 0; int voxelServerCount = 0; - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { if (node->getType() == NODE_TYPE_VOXEL_SERVER) { totalPingVoxel += node->getPingMs(); voxelServerCount++; @@ -3508,6 +3437,7 @@ void Application::displayStats() { } } } + if (voxelServerCount) { pingVoxel = totalPingVoxel/voxelServerCount; } @@ -3524,7 +3454,7 @@ void Application::displayStats() { sprintf(avatarStats, "Avatar: pos %.3f, %.3f, %.3f, vel %.1f, yaw = %.2f", avatarPos.x, avatarPos.y, avatarPos.z, glm::length(_myAvatar.getVelocity()), _myAvatar.getBodyYaw()); drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats); - Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); + SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; if (avatarMixer) { sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", @@ -3848,10 +3778,10 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { if (!selfAvatarOnly) { // Render avatars of other nodes NodeList* nodeList = NodeList::getInstance(); - - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { node->lock(); - + if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -3860,7 +3790,7 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { avatar->render(false); avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); } - + node->unlock(); } @@ -4106,18 +4036,6 @@ void Application::eyedropperVoxelUnderCursor() { } } -void Application::toggleFollowMode() { - glm::vec3 mouseRayOrigin, mouseRayDirection; - _viewFrustum.computePickRay(_pieMenu.getX() / (float)_glWidget->width(), - _pieMenu.getY() / (float)_glWidget->height(), - mouseRayOrigin, mouseRayDirection); - glm::vec3 eyePositionIgnored; - QUuid nodeUUIDIgnored; - Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeUUIDIgnored); - - _myAvatar.follow(leadingAvatar); -} - void Application::resetSensors() { _headMouseX = _mouseX = _glWidget->width() / 2; _headMouseY = _mouseY = _glWidget->height() / 2; @@ -4200,11 +4118,7 @@ void Application::domainChanged(QString domain) { updateLocalOctreeCache(); } -void Application::nodeAdded(Node* node) { - -} - -void Application::nodeKilled(Node* node) { +void Application::nodeKilled(SharedNodePointer node) { if (node->getType() == NODE_TYPE_VOXEL_SERVER) { QUuid nodeUUID = node->getUUID(); // see if this is the first we've heard of this node... @@ -4284,7 +4198,7 @@ void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t m const HifiSockAddr& senderSockAddr, bool wasStatsPacket) { // Attempt to identify the sender from it's address. - Node* serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (serverNode) { QUuid nodeUUID = serverNode->getUUID(); @@ -4301,7 +4215,7 @@ void Application::trackIncomingVoxelPacket(unsigned char* messageData, ssize_t m int Application::parseOctreeStats(unsigned char* messageData, ssize_t messageLength, const HifiSockAddr& senderSockAddr) { // But, also identify the sender, and keep track of the contained jurisdiction root for this server - Node* server = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + 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 diff --git a/interface/src/Application.h b/interface/src/Application.h index 92831ff9ce..a0bf608e98 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -95,7 +95,7 @@ static const float NODE_KILLED_RED = 1.0f; static const float NODE_KILLED_GREEN = 0.0f; static const float NODE_KILLED_BLUE = 0.0f; -class Application : public QApplication, public NodeListHook, public PacketSenderNotify, public DomainChangeListener { +class Application : public QApplication, public PacketSenderNotify, public DomainChangeListener { Q_OBJECT friend class VoxelPacketProcessor; @@ -194,8 +194,7 @@ public: void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near, float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const; - virtual void nodeAdded(Node* node); - virtual void nodeKilled(Node* node); + virtual void packetSentNotification(ssize_t length); virtual void domainChanged(QString domain); @@ -214,6 +213,8 @@ public: void setIsHighlightVoxel(bool isHighlightVoxel) { _isHighlightVoxel = isHighlightVoxel; } public slots: + void nodeKilled(SharedNodePointer node); + void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); void exportVoxels(); void importVoxels(); @@ -250,8 +251,6 @@ private slots: glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); - void toggleFollowMode(); - void closeMirrorView(); void restoreMirrorView(); void shrinkMirrorView(); @@ -301,7 +300,6 @@ private: bool isLookingAtMyAvatar(Avatar* avatar); void renderLookatIndicator(glm::vec3 pointOfInterest); - void renderFollowIndicator(); void renderHighlightVoxel(VoxelDetail voxel); void updateAvatar(float deltaTime); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 429b0ec66a..9349223691 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -365,9 +365,9 @@ void Audio::handleAudioInput() { NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); NodeList* nodeList = NodeList::getInstance(); - Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + SharedNodePointer audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer)) { + if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) { MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 33fa59e3e4..34fe0b165c 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -144,14 +144,14 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int Application::getInstance()->getProfile()->setFaceModelURL(QUrl(valueList[i])); } else { // mesh URL for a UUID, find avatar in our list - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar* avatar = (Avatar *) node->getLinkedData(); if (avatar->getUUID() == userUUID) { QMetaObject::invokeMethod(&avatar->getHead().getFaceModel(), - "setURL", Q_ARG(QUrl, QUrl(valueList[i]))); + "setURL", Q_ARG(QUrl, QUrl(valueList[i]))); } } } @@ -163,14 +163,13 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int Application::getInstance()->getProfile()->setSkeletonModelURL(QUrl(valueList[i])); } else { // skeleton URL for a UUID, find avatar in our list - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar* avatar = (Avatar *) node->getLinkedData(); if (avatar->getUUID() == userUUID) { QMetaObject::invokeMethod(&avatar->getSkeletonModel(), "setURL", - Q_ARG(QUrl, QUrl(valueList[i]))); + Q_ARG(QUrl, QUrl(valueList[i]))); } } } diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 355b027e93..fc72f7444e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -26,10 +26,6 @@ MetavoxelSystem::MetavoxelSystem() : _buffer(QOpenGLBuffer::VertexBuffer) { } -MetavoxelSystem::~MetavoxelSystem() { - NodeList::getInstance()->removeHook(this); -} - void MetavoxelSystem::init() { if (!_program.isLinked()) { switchToResourcesParentIfRequired(); @@ -39,7 +35,10 @@ void MetavoxelSystem::init() { _pointScaleLocation = _program.uniformLocation("pointScale"); } - NodeList::getInstance()->addHook(this); + NodeList* nodeList = NodeList::getInstance(); + + connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer))); + connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); AttributeRegistry::getInstance()->configureScriptEngine(&_scriptEngine); @@ -117,14 +116,14 @@ void MetavoxelSystem::render() { _program.release(); } -void MetavoxelSystem::nodeAdded(Node* node) { +void MetavoxelSystem::nodeAdded(SharedNodePointer node) { if (node->getType() == NODE_TYPE_METAVOXEL_SERVER) { QMetaObject::invokeMethod(this, "addClient", Q_ARG(const QUuid&, node->getUUID()), Q_ARG(const HifiSockAddr&, node->getLocalSocket())); } } -void MetavoxelSystem::nodeKilled(Node* node) { +void MetavoxelSystem::nodeKilled(SharedNodePointer node) { if (node->getType() == NODE_TYPE_METAVOXEL_SERVER) { QMetaObject::invokeMethod(this, "removeClient", Q_ARG(const QUuid&, node->getUUID())); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index ddb69644d5..a58729285d 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -26,13 +26,11 @@ class MetavoxelClient; /// Renders a metavoxel tree. -class MetavoxelSystem : public QObject, public NodeListHook { +class MetavoxelSystem : public QObject { Q_OBJECT public: - MetavoxelSystem(); - ~MetavoxelSystem(); void init(); @@ -41,9 +39,9 @@ public: void simulate(float deltaTime); void render(); - virtual void nodeAdded(Node* node); - virtual void nodeKilled(Node* node); - +public slots: + void nodeAdded(SharedNodePointer node); + void nodeKilled(SharedNodePointer node); private: Q_INVOKABLE void addClient(const QUuid& uuid, const HifiSockAddr& address); diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 6e5d4ca85c..76b2ce55fc 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -57,12 +57,13 @@ void VoxelPacketProcessor::processPacket(const HifiSockAddr& senderSockAddr, uns if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { app->trackIncomingVoxelPacket(packetData, messageLength, senderSockAddr, wasStatsPacket); - Node* serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + SharedNodePointer serverNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); if (serverNode && serverNode->getActiveSocket() && *serverNode->getActiveSocket() == senderSockAddr) { switch(packetData[0]) { case PACKET_TYPE_PARTICLE_DATA: { - app->_particles.processDatagram(QByteArray((char*) packetData, messageLength), senderSockAddr, serverNode); + app->_particles.processDatagram(QByteArray((char*) packetData, messageLength), + senderSockAddr, serverNode.data()); } break; case PACKET_TYPE_ENVIRONMENT_DATA: { diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index ede9a8e15d..7dfa4158cf 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1604,13 +1604,13 @@ void VoxelSystem::falseColorizeBySource() { }; // create a bunch of colors we'll use during colorization - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getType() == NODE_TYPE_VOXEL_SERVER) { uint16_t nodeID = VoxelTreeElement::getSourceNodeUUIDKey(node->getUUID()); int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS; args.colors[nodeID] = groupColors[groupColor]; - + if (groupColors[groupColor].red > 0) { groupColors[groupColor].red = ((groupColors[groupColor].red - MIN_COLOR)/2) + MIN_COLOR; } @@ -1620,7 +1620,7 @@ void VoxelSystem::falseColorizeBySource() { if (groupColors[groupColor].blue > 0) { groupColors[groupColor].blue = ((groupColors[groupColor].blue - MIN_COLOR)/2) + MIN_COLOR; } - + voxelServerCount++; } } @@ -2683,7 +2683,7 @@ void VoxelSystem::falseColorizeOccludedV2() { setupNewVoxelsForDrawing(); } -void VoxelSystem::nodeAdded(Node* node) { +void VoxelSystem::nodeAdded(SharedNodePointer node) { if (node->getType() == NODE_TYPE_VOXEL_SERVER) { qDebug("VoxelSystem... voxel server %s added...\n", node->getUUID().toString().toLocal8Bit().constData()); _voxelServerCount++; @@ -2704,7 +2704,7 @@ bool VoxelSystem::killSourceVoxelsOperation(OctreeElement* element, void* extraD return true; } -void VoxelSystem::nodeKilled(Node* node) { +void VoxelSystem::nodeKilled(SharedNodePointer node) { if (node->getType() == NODE_TYPE_VOXEL_SERVER) { _voxelServerCount--; QUuid nodeUUID = node->getUUID(); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index e9f0cc47ab..a1bce77be1 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -37,8 +37,7 @@ struct VoxelShaderVBOData }; -class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook, - public NodeListHook { +class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook { Q_OBJECT friend class VoxelHideShowThread; @@ -112,8 +111,6 @@ public: virtual void elementDeleted(OctreeElement* element); virtual void elementUpdated(OctreeElement* element); - virtual void nodeAdded(Node* node); - virtual void nodeKilled(Node* node); bool treeIsBusy() const { return _treeIsBusy; } @@ -124,6 +121,9 @@ signals: void importProgress(int progress); public slots: + void nodeAdded(SharedNodePointer node); + void nodeKilled(SharedNodePointer node); + void collectStatsForTreesAndVBOs(); // Methods that recurse tree diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b3b4793b39..9bc77b1f5d 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -95,7 +95,6 @@ Avatar::Avatar(Node* owningNode) : _mouseRayOrigin(0.0f, 0.0f, 0.0f), _mouseRayDirection(0.0f, 0.0f, 0.0f), _isCollisionsOn(true), - _leadingAvatar(NULL), _moving(false), _initialized(false), _handHoldingPosition(0.0f, 0.0f, 0.0f), @@ -146,27 +145,7 @@ glm::quat Avatar::getWorldAlignedOrientation () const { return computeRotationFromBodyToWorldUp() * getOrientation(); } -void Avatar::follow(Avatar* leadingAvatar) { - const float MAX_STRING_LENGTH = 2; - - _leadingAvatar = leadingAvatar; - if (_leadingAvatar != NULL) { - _leaderUUID = leadingAvatar->getOwningNode()->getUUID(); - _stringLength = glm::length(_position - _leadingAvatar->getPosition()) / _scale; - if (_stringLength > MAX_STRING_LENGTH) { - _stringLength = MAX_STRING_LENGTH; - } - } else { - _leaderUUID = QUuid(); - } -} - void Avatar::simulate(float deltaTime, Transmitter* transmitter) { - - if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) { - follow(NULL); - } - if (_scale != _newScale) { setScale(_newScale); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 1a4511275a..6fa9528741 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -135,7 +135,6 @@ public: void init(); void simulate(float deltaTime, Transmitter* transmitter); - void follow(Avatar* leadingAvatar); void render(bool forceRenderHead); //setters @@ -217,7 +216,6 @@ protected: glm::vec3 _mouseRayOrigin; glm::vec3 _mouseRayDirection; bool _isCollisionsOn; - Avatar* _leadingAvatar; float _stringLength; bool _moving; ///< set when position is changing diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 2cbbd6fa51..78be4a1864 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -368,8 +368,7 @@ void Hand::updateCollisions() { glm::vec3 totalPenetration; // check other avatars - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { Avatar* otherAvatar = (Avatar*)node->getLinkedData(); if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { @@ -388,21 +387,21 @@ void Hand::updateCollisions() { if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { palm.setIsCollidingWithPalm(true); if (!wasColliding) { - const float PALM_COLLIDE_VOLUME = 1.f; - const float PALM_COLLIDE_FREQUENCY = 1000.f; - const float PALM_COLLIDE_DURATION_MAX = 0.75f; - const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; - Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, - PALM_COLLIDE_FREQUENCY, - PALM_COLLIDE_DURATION_MAX, - PALM_COLLIDE_DECAY_PER_SAMPLE); - // If the other person's palm is in motion, move mine downward to show I was hit - const float MIN_VELOCITY_FOR_SLAP = 0.05f; + const float PALM_COLLIDE_VOLUME = 1.f; + const float PALM_COLLIDE_FREQUENCY = 1000.f; + const float PALM_COLLIDE_DURATION_MAX = 0.75f; + const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; + Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, + PALM_COLLIDE_FREQUENCY, + PALM_COLLIDE_DURATION_MAX, + PALM_COLLIDE_DECAY_PER_SAMPLE); + // If the other person's palm is in motion, move mine downward to show I was hit + const float MIN_VELOCITY_FOR_SLAP = 0.05f; if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { // add slapback here } } - + } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 161ea5b9d8..1e6b2565ce 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -87,15 +87,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { _elapsedTimeMoving += deltaTime; } - if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) { - follow(NULL); - } - - // Ajust, scale, position and lookAt position when following an other avatar - if (_leadingAvatar && _newScale != _leadingAvatar->getScale()) { - _newScale = _leadingAvatar->getScale(); - } - if (_scale != _newScale) { float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _newScale; setScale(scale); @@ -327,9 +318,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { estimatedRotation = webcam->getEstimatedRotation(); } else { - if (!_leadingAvatar) { - _head.setPitch(_head.getMousePitch()); - } + _head.setPitch(_head.getMousePitch()); _head.getVideoFace().clearFrame(); // restore rotation, lean to neutral positions @@ -634,47 +623,6 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { _shouldJump = false; } - - // Add thrusts from leading avatar - const float FOLLOWING_RATE = 0.02f; - const float MIN_YAW = 5.0f; - const float MIN_PITCH = 1.0f; - const float PITCH_RATE = 0.1f; - const float MIN_YAW_BEFORE_PITCH = 30.0f; - - if (_leadingAvatar != NULL) { - glm::vec3 toTarget = _leadingAvatar->getPosition() - _position; - - if (glm::length(_position - _leadingAvatar->getPosition()) > _scale * _stringLength) { - _position += toTarget * FOLLOWING_RATE; - } else { - toTarget = _leadingAvatar->getHead().getLookAtPosition() - _head.getPosition(); - } - toTarget = glm::vec3(glm::dot(right, toTarget), - glm::dot(up , toTarget), - glm::dot(front, toTarget)); - - float yawAngle = angleBetween(-IDENTITY_FRONT, glm::vec3(toTarget.x, 0.f, toTarget.z)); - if (glm::abs(yawAngle) > MIN_YAW){ - if (IDENTITY_RIGHT.x * toTarget.x + IDENTITY_RIGHT.y * toTarget.y + IDENTITY_RIGHT.z * toTarget.z > 0) { - _bodyYawDelta -= yawAngle; - } else { - _bodyYawDelta += yawAngle; - } - } - - float pitchAngle = glm::abs(90.0f - angleBetween(IDENTITY_UP, toTarget)); - if (glm::abs(pitchAngle) > MIN_PITCH && yawAngle < MIN_YAW_BEFORE_PITCH){ - if (IDENTITY_UP.x * toTarget.x + IDENTITY_UP.y * toTarget.y + IDENTITY_UP.z * toTarget.z > 0) { - _head.setMousePitch(_head.getMousePitch() + PITCH_RATE * pitchAngle); - } else { - _head.setMousePitch(_head.getMousePitch() - PITCH_RATE * pitchAngle); - } - _head.setPitch(_head.getMousePitch()); - } - } - - // Add thrusts from Transmitter if (transmitter) { transmitter->checkForLostTransmitter(); @@ -873,15 +821,7 @@ void MyAvatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar _distanceToNearestAvatar = std::numeric_limits::max(); - // loop through all the other avatars for potential interactions... - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - //Avatar *otherAvatar = (Avatar *)node->getLinkedData(); - // - // Placeholder: Add code here when we want to add Avatar<->Avatar collision stuff - } - } + // loop through all the other avatars for potential interactions } class SortedAvatar { @@ -902,10 +842,10 @@ void MyAvatar::updateChatCircle(float deltaTime) { // find all circle-enabled members and sort by distance QVector sortedAvatars; - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - SortedAvatar sortedAvatar; + SortedAvatar sortedAvatar; sortedAvatar.avatar = (Avatar*)node->getLinkedData(); if (!sortedAvatar.avatar->isChatCirclingEnabled()) { continue; @@ -914,6 +854,7 @@ void MyAvatar::updateChatCircle(float deltaTime) { sortedAvatars.append(sortedAvatar); } } + qSort(sortedAvatars.begin(), sortedAvatars.end()); // compute the accumulated centers diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 99cc360d59..474c212623 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -51,7 +51,6 @@ public: float getAbsoluteHeadYaw() const; const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } - Avatar* getLeadingAvatar() const { return _leadingAvatar; } glm::vec3 getGravity() const { return _gravity; } glm::vec3 getUprightHeadPosition() const; glm::vec3 getEyeLevelPosition() const; diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index 3a2c8468ad..a25fe9f097 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -241,9 +241,10 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve NodeToJurisdictionMap& serverJurisdictions) { QLocale locale(QLocale::English); - + NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER if (node->getType() == serverType) { serverCount++; @@ -261,7 +262,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve std::stringstream serverDetails(""); std::stringstream extraDetails(""); std::stringstream linkDetails(""); - + if (nodeList->getNodeActiveSocketOrPing(&(*node))) { serverDetails << "active "; } else { @@ -270,29 +271,29 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve QUuid nodeUUID = node->getUUID(); - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're + // 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()) { serverDetails << " unknown jurisdiction "; } else { const JurisdictionMap& map = serverJurisdictions[nodeUUID]; - + unsigned char* rootCode = map.getRootOctalCode(); - + if (rootCode) { QString rootCodeHex = octalCodeToHexString(rootCode); - + VoxelPositionSize rootDetails; voxelDetailsForCode(rootCode, rootDetails); AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); serverBounds.scale(TREE_SCALE); - serverDetails << " jurisdiction: " - << rootCodeHex.toLocal8Bit().constData() - << " [" - << rootDetails.x << ", " - << rootDetails.y << ", " - << rootDetails.z << ": " - << rootDetails.s << "] "; + serverDetails << " jurisdiction: " + << rootCodeHex.toLocal8Bit().constData() + << " [" + << rootDetails.x << ", " + << rootDetails.y << ", " + << rootDetails.z << ": " + << rootDetails.s << "] "; } else { serverDetails << " jurisdiction has no rootCode"; } // root code @@ -304,7 +305,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getOcteeSceneStats(); if (sceneStats->find(nodeUUID) != sceneStats->end()) { VoxelSceneStats& stats = sceneStats->at(nodeUUID); - + switch (_extraServerDetails[serverCount-1]) { case MOST: { extraDetails << "
" ; @@ -312,14 +313,14 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve const unsigned long USECS_PER_MSEC = 1000; float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - + QString lastFullEncodeString = locale.toString(lastFullEncode); QString lastFullSendString = locale.toString(lastFullSend); - - extraDetails << "
" << "Last Full Scene... " << - "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << - "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; - + + extraDetails << "
" << "Last Full Scene... " << + "Encode Time: " << lastFullEncodeString.toLocal8Bit().constData() << " ms " << + "Send Time: " << lastFullSendString.toLocal8Bit().constData() << " ms "; + for (int i = 0; i < VoxelSceneStats::ITEM_COUNT; i++) { VoxelSceneStats::Item item = (VoxelSceneStats::Item)(i); VoxelSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); @@ -330,44 +331,44 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve QString totalString = locale.toString((uint)stats.getTotalElements()); QString internalString = locale.toString((uint)stats.getTotalInternal()); QString leavesString = locale.toString((uint)stats.getTotalLeaves()); - + serverDetails << "
" << "Node UUID: " << - nodeUUID.toString().toLocal8Bit().constData() << " "; - + nodeUUID.toString().toLocal8Bit().constData() << " "; + serverDetails << "
" << "Voxels: " << - totalString.toLocal8Bit().constData() << " total " << - internalString.toLocal8Bit().constData() << " internal " << - leavesString.toLocal8Bit().constData() << " leaves "; - + totalString.toLocal8Bit().constData() << " total " << + internalString.toLocal8Bit().constData() << " internal " << + leavesString.toLocal8Bit().constData() << " leaves "; + QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets()); QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); QString incomingOutOfOrderString = locale.toString((uint)stats.getIncomingOutOfOrder()); QString incomingLikelyLostString = locale.toString((uint)stats.getIncomingLikelyLost()); - + int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC; QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); QString incomingPingTimeString = locale.toString(node->getPingMs()); QString incomingClockSkewString = locale.toString(clockSkewInMS); - + serverDetails << "
" << "Incoming Packets: " << - incomingPacketsString.toLocal8Bit().constData() << - " Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() << - " Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData(); - + incomingPacketsString.toLocal8Bit().constData() << + " Out of Order: " << incomingOutOfOrderString.toLocal8Bit().constData() << + " Likely Lost: " << incomingLikelyLostString.toLocal8Bit().constData(); + serverDetails << "
" << - " Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs"; - - serverDetails << "
" << - " Average Ping Time: " << incomingPingTimeString.toLocal8Bit().constData() << " msecs"; - - serverDetails << "
" << - " Average Clock Skew: " << incomingClockSkewString.toLocal8Bit().constData() << " msecs"; - + " Average Flight Time: " << incomingFlightTimeString.toLocal8Bit().constData() << " msecs"; + + serverDetails << "
" << + " Average Ping Time: " << incomingPingTimeString.toLocal8Bit().constData() << " msecs"; + + serverDetails << "
" << + " Average Clock Skew: " << incomingClockSkewString.toLocal8Bit().constData() << " msecs"; + serverDetails << "
" << "Incoming" << - " Bytes: " << incomingBytesString.toLocal8Bit().constData() << - " Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData(); - + " Bytes: " << incomingBytesString.toLocal8Bit().constData() << + " Wasted Bytes: " << incomingWastedBytesString.toLocal8Bit().constData(); + serverDetails << extraDetails.str(); if (_extraServerDetails[serverCount-1] == MORE) { linkDetails << " " << " [most...]"; @@ -376,7 +377,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve linkDetails << " " << " [less...]"; linkDetails << " " << " [least...]"; } - + } break; case LESS: { // nothing @@ -391,7 +392,7 @@ void VoxelStatsDialog::showOctreeServersOfType(int& serverCount, NODE_TYPE serve serverDetails << linkDetails.str(); _labels[_voxelServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); } // is VOXEL_SERVER - } // Node Loop + } } void VoxelStatsDialog::reject() { diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 722c2a6dbd..60ff777452 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -103,9 +103,9 @@ void AudioInjector::injectAudio() { // grab our audio mixer from the NodeList, if it exists - Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + SharedNodePointer audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer)) { + if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer.data())) { // send off this audio packet nodeList->getNodeSocket().writeDatagram((char*) injectedAudioPacket, (currentPacketPosition - injectedAudioPacket) + bytesToCopy, diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 14115ced47..8ba5f6e984 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -30,7 +30,6 @@ AvatarData::AvatarData(Node* owningNode) : _bodyPitch(0.0), _bodyRoll(0.0), _newScale(1.0f), - _leaderUUID(), _handState(0), _keyState(NO_KEY_DOWN), _isChatCirclingEnabled(false), @@ -77,10 +76,6 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // Body scale destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _newScale); - - // Follow mode info - memcpy(destinationBuffer, _leaderUUID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); - destinationBuffer += NUM_BYTES_RFC4122_UUID; // Head rotation (NOTE: This needs to become a quaternion to save two bytes) destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_yaw); @@ -200,10 +195,6 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // Body scale sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _newScale); - // Follow mode info - _leaderUUID = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID)); - sourceBuffer += NUM_BYTES_RFC4122_UUID; - // Head rotation (NOTE: This needs to become a quaternion to save two bytes) float headYaw, headPitch, headRoll; sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index e7f359aff2..0fa3aaa972 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -100,8 +100,6 @@ public: QString getQStringChatMessage() { return QString(_chatMessage.data()); } bool isChatCirclingEnabled() const { return _isChatCirclingEnabled; } - - const QUuid& getLeaderUUID() const { return _leaderUUID; } const HeadData* getHeadData() const { return _headData; } const HandData* getHandData() const { return _handData; } @@ -134,9 +132,6 @@ protected: // Body scale float _newScale; - // Following mode infos - QUuid _leaderUUID; - // Hand state (are we grabbing something or not) char _handState; diff --git a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp index 020c1b274b..c88dfd16ac 100644 --- a/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp +++ b/libraries/octree-server/src/OctreeInboundPacketProcessor.cpp @@ -57,7 +57,7 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket); _receivedPacketCount++; - Node* senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); + SharedNodePointer senderNode = NodeList::getInstance()->nodeWithAddress(senderSockAddr); unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); @@ -87,7 +87,9 @@ void OctreeInboundPacketProcessor::processPacket(const HifiSockAddr& senderSockA _myServer->getOctree()->lockForWrite(); uint64_t startProcess = usecTimestampNow(); int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType, - packetData, packetLength, editData, maxSize, senderNode); + packetData, + packetLength, + editData, maxSize, senderNode.data()); _myServer->getOctree()->unlock(); uint64_t endProcess = usecTimestampNow(); diff --git a/libraries/octree-server/src/OctreeSendThread.cpp b/libraries/octree-server/src/OctreeSendThread.cpp index ccdf1ed8e2..41450022d2 100644 --- a/libraries/octree-server/src/OctreeSendThread.cpp +++ b/libraries/octree-server/src/OctreeSendThread.cpp @@ -30,7 +30,7 @@ bool OctreeSendThread::process() { // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { - Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); + SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); if (node) { // make sure the node list doesn't kill our node while we're using it @@ -48,7 +48,7 @@ bool OctreeSendThread::process() { if (_myServer->wantsDebugSending() && _myServer->wantsVerboseDebug()) { printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); } - packetsSent = packetDistributor(node, nodeData, viewFrustumChanged); + packetsSent = packetDistributor(node.data(), nodeData, viewFrustumChanged); } node->unlock(); // we're done with this node for now. diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 2a7f073ca4..1cfbf03ad8 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -27,11 +27,7 @@ void OctreeServer::attachQueryNodeToNode(Node* newNode) { } } -void OctreeServer::nodeAdded(Node* node) { - // do nothing -} - -void OctreeServer::nodeKilled(Node* node) { +void OctreeServer::nodeKilled(SharedNodePointer node) { // Use this to cleanup our node if (node->getType() == NODE_TYPE_AGENT) { OctreeQueryNode* nodeData = (OctreeQueryNode*)node->getLinkedData(); @@ -90,9 +86,6 @@ OctreeServer::~OctreeServer() { _persistThread->terminate(); delete _persistThread; } - - // tell our NodeList we're done with notifications - NodeList::getInstance()->removeHook(this); delete _jurisdiction; _jurisdiction = NULL; @@ -524,10 +517,10 @@ void OctreeServer::processDatagram(const QByteArray& dataByteArray, const HifiSo QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesPacketHeader, NUM_BYTES_RFC4122_UUID)); - Node* node = nodeList->nodeWithUUID(nodeUUID); + SharedNodePointer node = nodeList->nodeWithUUID(nodeUUID); if (node) { - nodeList->updateNodeWithData(node, senderSockAddr, (unsigned char *) dataByteArray.data(), + nodeList->updateNodeWithData(node.data(), senderSockAddr, (unsigned char *) dataByteArray.data(), dataByteArray.size()); if (!node->getActiveSocket()) { // we don't have an active socket for this node, but they're talking to us @@ -612,7 +605,7 @@ void OctreeServer::run() { setvbuf(stdout, NULL, _IOLBF, 0); // tell our NodeList about our desire to get notifications - nodeList->addHook(this); + connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); nodeList->linkedDataCreateCallback = &OctreeServer::attachQueryNodeToNode; srand((unsigned)time(0)); diff --git a/libraries/octree-server/src/OctreeServer.h b/libraries/octree-server/src/OctreeServer.h index 39fb9ee990..f6380788a6 100644 --- a/libraries/octree-server/src/OctreeServer.h +++ b/libraries/octree-server/src/OctreeServer.h @@ -23,7 +23,7 @@ #include "OctreeInboundPacketProcessor.h" /// Handles assignments of type OctreeServer - sending octrees to various clients. -class OctreeServer : public ThreadedAssignment, public NodeListHook { +class OctreeServer : public ThreadedAssignment { public: OctreeServer(const unsigned char* dataBuffer, int numBytes); ~OctreeServer(); @@ -60,15 +60,13 @@ public: virtual int sendSpecialPacket(Node* node) { return 0; } static void attachQueryNodeToNode(Node* newNode); - - // NodeListHook - virtual void nodeAdded(Node* node); - virtual void nodeKilled(Node* node); - + public slots: /// runs the voxel server assignment void run(); void processDatagram(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr); + + void nodeKilled(SharedNodePointer node); protected: int _argc; diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index 2080d0f2aa..29f6dde309 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -15,29 +15,20 @@ #include #include "JurisdictionListener.h" - JurisdictionListener::JurisdictionListener(NODE_TYPE type, PacketSenderNotify* notify) : PacketSender(notify, JurisdictionListener::DEFAULT_PACKETS_PER_SECOND) { _nodeType = type; ReceivedPacketProcessor::_dontSleep = true; // we handle sleeping so this class doesn't need to NodeList* nodeList = NodeList::getInstance(); - nodeList->addHook(this); - + + connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer))); + //qDebug("JurisdictionListener::JurisdictionListener(NODE_TYPE type=%c)\n", type); } -JurisdictionListener::~JurisdictionListener() { - NodeList* nodeList = NodeList::getInstance(); - nodeList->removeHook(this); -} - -void JurisdictionListener::nodeAdded(Node* node) { - // nothing to do. But need to implement it. -} - -void JurisdictionListener::nodeKilled(Node* node) { +void JurisdictionListener::nodeKilled(SharedNodePointer node) { if (_jurisdictions.find(node->getUUID()) != _jurisdictions.end()) { _jurisdictions.erase(_jurisdictions.find(node->getUUID())); } @@ -52,8 +43,9 @@ bool JurisdictionListener::queueJurisdictionRequest() { int nodeCount = 0; NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (nodeList->getNodeActiveSocketOrPing(&(*node)) && + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { + if (nodeList->getNodeActiveSocketOrPing(&(*node)) && node->getType() == getNodeType()) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut); @@ -73,7 +65,7 @@ bool JurisdictionListener::queueJurisdictionRequest() { void JurisdictionListener::processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { if (packetData[0] == PACKET_TYPE_JURISDICTION) { - Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress); + SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(senderAddress); if (node) { QUuid nodeUUID = node->getUUID(); JurisdictionMap map; diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h index b8951683a5..393ca80420 100644 --- a/libraries/octree/src/JurisdictionListener.h +++ b/libraries/octree/src/JurisdictionListener.h @@ -15,32 +15,32 @@ #include #include + #include "JurisdictionMap.h" /// Sends out PACKET_TYPE_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes /// the PACKET_TYPE_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions /// within the domain. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets /// and adding them to the processing queue by calling queueReceivedPacket() -class JurisdictionListener : public NodeListHook, public PacketSender, public ReceivedPacketProcessor { +class JurisdictionListener : public PacketSender, public ReceivedPacketProcessor { public: static const int DEFAULT_PACKETS_PER_SECOND = 1; static const int NO_SERVER_CHECK_RATE = 60; // if no servers yet detected, keep checking at 60fps JurisdictionListener(NODE_TYPE type = NODE_TYPE_VOXEL_SERVER, PacketSenderNotify* notify = NULL); - ~JurisdictionListener(); virtual bool process(); NodeToJurisdictionMap* getJurisdictions() { return &_jurisdictions; }; - /// Called by NodeList to inform us that a node has been added. - void nodeAdded(Node* node); - /// Called by NodeList to inform us that a node has been killed. - void nodeKilled(Node* node); NODE_TYPE getNodeType() const { return _nodeType; } void setNodeType(NODE_TYPE type) { _nodeType = type; } +public slots: + /// Called by NodeList to inform us that a node has been killed. + void nodeKilled(SharedNodePointer node); + protected: /// Callback for processing of received packets. Will process any queued PACKET_TYPE_JURISDICTION and update the /// jurisdiction map member variable diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp index 289b2b2f07..24aeb1a51f 100644 --- a/libraries/octree/src/JurisdictionSender.cpp +++ b/libraries/octree/src/JurisdictionSender.cpp @@ -32,7 +32,7 @@ JurisdictionSender::~JurisdictionSender() { void JurisdictionSender::processPacket(const HifiSockAddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { if (packetData[0] == PACKET_TYPE_JURISDICTION_REQUEST) { - Node* node = NodeList::getInstance()->nodeWithAddress(senderAddress); + SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(senderAddress); if (node) { QUuid nodeUUID = node->getUUID(); lockRequestingNodes(); @@ -64,7 +64,7 @@ bool JurisdictionSender::process() { QUuid nodeUUID = _nodesRequestingJurisdictions.front(); _nodesRequestingJurisdictions.pop(); - Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID); + SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(nodeUUID); if (node->getActiveSocket() != NULL) { const HifiSockAddr* nodeAddress = node->getActiveSocket(); diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h index c3a47ffee3..1fc1e76d9b 100644 --- a/libraries/octree/src/JurisdictionSender.h +++ b/libraries/octree/src/JurisdictionSender.h @@ -21,6 +21,7 @@ /// to requesting parties. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets /// and adding them to the processing queue by calling queueReceivedPacket() class JurisdictionSender : public PacketSender, public ReceivedPacketProcessor { + Q_OBJECT public: static const int DEFAULT_PACKETS_PER_SECOND = 1; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 9f7978c342..1367ca41bd 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -57,14 +57,15 @@ bool OctreeEditPacketSender::serversExist() const { bool hasServers = false; bool atLeastOnJurisdictionMissing = false; // assume the best NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getType() == getMyNodeType()) { if (nodeList->getNodeActiveSocketOrPing(&(*node))) { 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 + // 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; @@ -77,6 +78,7 @@ bool OctreeEditPacketSender::serversExist() const { break; // no point in looking further... } } + return (hasServers && !atLeastOnJurisdictionMissing); } @@ -84,7 +86,8 @@ bool OctreeEditPacketSender::serversExist() const { // a known nodeID. void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) { NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, nodeList->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getType() == getMyNodeType() && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) { @@ -100,11 +103,11 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c uint64_t createdAt = (*((uint64_t*)(buffer + numBytesPacketHeader + sizeof(sequence)))); uint64_t queuedAt = usecTimestampNow(); uint64_t transitTime = queuedAt - createdAt; - qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << - " - command to node bytes=" << length << - " sequence=" << sequence << - " transitTimeSoFar=" << transitTime << " usecs\n"; - } + qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] << + " - command to node bytes=" << length << + " sequence=" << sequence << + " transitTimeSoFar=" << transitTime << " usecs\n"; + } } } } @@ -166,13 +169,13 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l // But we can't really do that with a packed message, since each edit message could be destined // for a different server... So we need to actually manage multiple queued packets... one // for each server - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) { QUuid nodeUUID = node->getUUID(); bool isMyJurisdiction = true; - // we need to get the jurisdiction for this + // we need to get the jurisdiction for this // here we need to get the "pending packet" for this server const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); @@ -212,15 +215,15 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c // But we can't really do that with a packed message, since each edit message could be destined // for a different server... So we need to actually manage multiple queued packets... one // for each server - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { // only send to the NodeTypes that are getMyNodeType() if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) { QUuid nodeUUID = node->getUUID(); bool isMyJurisdiction = true; - + if (_serverJurisdictions) { - // we need to get the jurisdiction for this + // we need to get the jurisdiction for this // here we need to get the "pending packet" for this server if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; @@ -232,19 +235,19 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c if (isMyJurisdiction) { EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID]; packetBuffer._nodeUUID = nodeUUID; - + // If we're switching type, then we send the last one and start over - if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || + if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) || (packetBuffer._currentSize + length >= _maxPacketSize)) { releaseQueuedPacket(packetBuffer); initializePacket(packetBuffer, type); } - + // If the buffer is empty and not correctly initialized for our type... if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) { initializePacket(packetBuffer, type); } - + // This is really the first time we know which server/node this particular edit message // is going to, so we couldn't adjust for clock skew till now. But here's our chance. // We call this virtual function that allows our specific type of EditPacketSender to @@ -252,7 +255,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c if (node->getClockSkewUsec() != 0) { adjustEditPacketForClockSkew(codeColorBuffer, length, node->getClockSkewUsec()); } - + memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length); packetBuffer._currentSize += length; } diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index 6711dc2d13..3ef831d9c7 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -187,22 +187,22 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { } // loop through all the other avatars for potential interactions... - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + + foreach(SharedNodePointer node, NodeList::getInstance()->getNodeHash()) { //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n"; if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { // TODO: dot collidingPalm and hand velocities and skip collision when they are moving apart. AvatarData* avatar = static_cast(node->getLinkedData()); //printf("updateCollisionWithAvatars()...avatar=%p\n", avatar); - + // check hands... const HandData* handData = avatar->getHandData(); - + if (handData->findSpherePenetration(center, radius, penetration, collidingPalm)) { // apply a hard collision when ball collides with hand penetration /= (float)(TREE_SCALE); updateCollisionSound(particle, penetration, COLLISION_FREQUENCY); - + // determine if the palm that collided was moving, if so, then we add that palm velocity as well... glm::vec3 addedVelocity = NO_ADDED_VELOCITY; if (collidingPalm) { @@ -210,9 +210,9 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { //printf("collidingPalm Velocity=%f,%f,%f\n", palmVelocity.x, palmVelocity.y, palmVelocity.z); addedVelocity = palmVelocity; } - + applyHardCollision(particle, penetration, ELASTICITY, DAMPING, addedVelocity); - + } else if (avatar->findSpherePenetration(center, radius, penetration)) { penetration /= (float)(TREE_SCALE); updateCollisionSound(particle, penetration, COLLISION_FREQUENCY); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 0a50a659b2..a4e3aaafae 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -52,10 +52,9 @@ NodeList* NodeList::getInstance() { } NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : + _nodeHash(), _domainHostname(DEFAULT_DOMAIN_HOSTNAME), _domainSockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), - _nodeBuckets(), - _numNodes(0), _nodeSocket(), _ownerType(newOwnerType), _nodeTypesOfInterest(NULL), @@ -108,10 +107,10 @@ void NodeList::setDomainHostname(const QString& domainHostname) { } void NodeList::timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData) { - for(NodeList::iterator node = begin(); node != end(); node++) { + foreach(SharedNodePointer node, _nodeHash) { if (node->getPublicSocket() == nodeAddress || node->getLocalSocket() == nodeAddress) { - + unsigned char* dataAt = packetData + numBytesForPacketHeader(packetData); uint64_t ourOriginalTime = *(uint64_t*)(dataAt); dataAt += sizeof(ourOriginalTime); @@ -129,15 +128,15 @@ void NodeList::timePingReply(const HifiSockAddr& nodeAddress, unsigned char *pac node->setClockSkewUsec(clockSkew); const bool wantDebug = false; - if (wantDebug) { + if (wantDebug) { qDebug() << "PING_REPLY from node " << *node << "\n" << - " now: " << now << "\n" << - " ourTime: " << ourOriginalTime << "\n" << - " pingTime: " << pingTime << "\n" << - " oneWayFlightTime: " << oneWayFlightTime << "\n" << - " othersReplyTime: " << othersReplyTime << "\n" << - " othersExprectedReply: " << othersExprectedReply << "\n" << - " clockSkew: " << clockSkew << "\n"; + " now: " << now << "\n" << + " ourTime: " << ourOriginalTime << "\n" << + " pingTime: " << pingTime << "\n" << + " oneWayFlightTime: " << oneWayFlightTime << "\n" << + " othersReplyTime: " << othersReplyTime << "\n" << + " othersExprectedReply: " << othersExprectedReply << "\n" << + " clockSkew: " << clockSkew << "\n"; } break; } @@ -184,10 +183,9 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, unsigned char } void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned char *packetData, int numTotalBytes) { + SharedNodePointer bulkSendNode = nodeWithAddress(senderAddress); // find the avatar mixer in our node list and update the lastRecvTime from it - Node* bulkSendNode = nodeWithAddress(senderAddress); - if (bulkSendNode) { bulkSendNode->setLastHeardMicrostamp(usecTimestampNow()); @@ -209,14 +207,14 @@ void NodeList::processBulkNodeData(const HifiSockAddr& senderAddress, unsigned c numTotalBytes - (currentPosition - startPosition)); QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)currentPosition, NUM_BYTES_RFC4122_UUID)); - Node* matchingNode = nodeWithUUID(nodeUUID); + SharedNodePointer matchingNode = nodeWithUUID(nodeUUID); if (!matchingNode) { // we're missing this node, we need to add it to the list matchingNode = addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, HifiSockAddr(), HifiSockAddr()); } - currentPosition += updateNodeWithData(matchingNode, + currentPosition += updateNodeWithData(matchingNode.data(), HifiSockAddr(), packetHolder, numTotalBytes - (currentPosition - startPosition)); @@ -253,53 +251,39 @@ int NodeList::updateNodeWithData(Node *node, const HifiSockAddr& senderSockAddr, } } -Node* NodeList::nodeWithAddress(const HifiSockAddr &senderSockAddr) { - for(NodeList::iterator node = begin(); node != end(); node++) { +QSharedPointer 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(QSharedPointer node, _nodeHash) { if (node->getActiveSocket() && *node->getActiveSocket() == senderSockAddr) { - return &(*node); + return node; } } - return NULL; + return QSharedPointer(NULL); } -Node* NodeList::nodeWithUUID(const QUuid& nodeUUID) { - for(NodeList::iterator node = begin(); node != end(); node++) { - if (node->getUUID() == nodeUUID) { - return &(*node); - } +QSharedPointer NodeList::nodeWithUUID(const QUuid& nodeUUID) { + QHash >::const_iterator foundIterator = _nodeHash.find(nodeUUID); + if (foundIterator != _nodeHash.end()) { + return foundIterator.value(); + } else { + return QSharedPointer(NULL); } - - return NULL; -} - -int NodeList::getNumAliveNodes() const { - int numAliveNodes = 0; - - for (NodeList::iterator node = begin(); node != end(); node++) { - if (node->isAlive()) { - ++numAliveNodes; - } - } - - return numAliveNodes; } void NodeList::clear() { qDebug() << "Clearing the NodeList. Deleting all nodes in list.\n"; - // delete all of the nodes in the list, set the pointers back to NULL and the number of nodes to 0 - for (int i = 0; i < _numNodes; i++) { - Node** nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET]; - Node* node = nodeBucket[i % NODES_PER_BUCKET]; - - node->lock(); - notifyHooksOfKilledNode(&*node); - - delete node; - } + NodeHash::iterator nodeItem = _nodeHash.begin(); - _numNodes = 0; + // iterate the nodes in the list + while (nodeItem != _nodeHash.end()) { + // emit our signal to say this node has been killed + emit nodeKilled(nodeItem.value()); + // erase the node from our node hash + _nodeHash.erase(nodeItem); + } } void NodeList::reset() { @@ -457,6 +441,14 @@ void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes) } } +void NodeList::killNodeWithUUID(const QUuid& nodeUUID) { + NodeHash::iterator nodeToKill = _nodeHash.find(nodeUUID); + if (nodeToKill != _nodeHash.end()) { + emit nodeKilled(nodeToKill.value()); + _nodeHash.erase(nodeToKill); + } +} + void NodeList::sendKillNode(const char* nodeTypes, int numNodeTypes) { unsigned char packet[MAX_PACKET_SIZE]; unsigned char* packetPosition = packet; @@ -483,9 +475,10 @@ void NodeList::processKillNode(unsigned char* packetData, size_t dataBytes) { dataBytes -= NUM_BYTES_RFC4122_UUID; // make sure the node exists - Node* node = nodeWithUUID(nodeUUID); - if (node) { - killNode(node, true); + NodeHash::iterator nodeToKill = _nodeHash.find(nodeUUID); + if (nodeToKill != _nodeHash.end()) { + emit nodeKilled(nodeToKill.value()); + _nodeHash.erase(nodeToKill); } } @@ -681,26 +674,24 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) { node->getPublicSocket().getAddress(), node->getPublicSocket().getPort()); } -Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, +SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) { - NodeList::iterator node = end(); + NodeHash::iterator matchingNodeItem = _nodeHash.find(uuid); - for (node = begin(); node != end(); node++) { - if (node->getUUID() == uuid) { - // we already have this node, stop checking - break; - } - } - - if (node == end()) { + if (matchingNodeItem == _nodeHash.end()) { // we didn't have this node, so add them Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket); - addNodeToList(newNode); + NodeHash::iterator addedItem = _nodeHash.insert(newNode->getUUID(), SharedNodePointer(newNode)); - return newNode; + qDebug() << "Added" << *newNode << "\n"; + + emit nodeAdded(addedItem.value()); + + return SharedNodePointer(newNode); } else { - node->lock(); + SharedNodePointer node = matchingNodeItem.value(); + matchingNodeItem.value()->lock(); if (node->getType() == NODE_TYPE_AUDIO_MIXER || node->getType() == NODE_TYPE_VOXEL_SERVER || @@ -724,33 +715,17 @@ Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, node->unlock(); // we had this node already, do nothing for now - return &*node; + return node; } } -void NodeList::addNodeToList(Node* newNode) { - // find the correct array to add this node to - int bucketIndex = _numNodes / NODES_PER_BUCKET; - - if (!_nodeBuckets[bucketIndex]) { - _nodeBuckets[bucketIndex] = new Node*[NODES_PER_BUCKET](); - } - - _nodeBuckets[bucketIndex][_numNodes % NODES_PER_BUCKET] = newNode; - - ++_numNodes; - - qDebug() << "Added" << *newNode << "\n"; - - notifyHooksOfAddedNode(newNode); -} - unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) { unsigned n = 0; - for(NodeList::iterator node = begin(); node != end(); node++) { + + foreach(SharedNodePointer node, _nodeHash) { // only send to the NodeTypes we are asked to send to. if (memchr(nodeTypes, node->getType(), numNodeTypes)) { - if (getNodeActiveSocketOrPing(&(*node))) { + if (getNodeActiveSocketOrPing(node.data())) { // we know which socket is good for this node, send there _nodeSocket.writeDatagram((char*) broadcastData, dataBytes, node->getActiveSocket()->getAddress(), node->getActiveSocket()->getPort()); @@ -758,14 +733,15 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt } } } + return n; } void NodeList::pingInactiveNodes() { - for(NodeList::iterator node = begin(); node != end(); node++) { + foreach(SharedNodePointer node, _nodeHash) { if (!node->getActiveSocket()) { // we don't have an active link to this node, ping it to set that up - pingPublicAndLocalSocketsForInactiveNode(&(*node)); + pingPublicAndLocalSocketsForInactiveNode(node.data()); } } } @@ -780,7 +756,8 @@ const HifiSockAddr* NodeList::getNodeActiveSocketOrPing(Node* node) { } void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddress) { - for(NodeList::iterator node = begin(); node != end(); node++) { + + foreach(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 @@ -795,46 +772,35 @@ void NodeList::activateSocketFromNodeCommunication(const HifiSockAddr& nodeAddre } } -Node* NodeList::soloNodeOfType(char nodeType) { +SharedNodePointer NodeList::soloNodeOfType(char nodeType) { + if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) { - for(NodeList::iterator node = begin(); node != end(); node++) { + foreach(SharedNodePointer node, _nodeHash) { if (node->getType() == nodeType) { - return &(*node); + return node; } } } - return NULL; -} - -void NodeList::killNode(Node* node, bool mustLockNode) { - if (mustLockNode) { - node->lock(); - } - - qDebug() << "Killed " << *node << "\n"; - - notifyHooksOfKilledNode(&*node); - - node->setAlive(false); - - if (mustLockNode) { - node->unlock(); - } + return SharedNodePointer(NULL); } void NodeList::removeSilentNodes() { - NodeList* nodeList = NodeList::getInstance(); - for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) { - node->lock(); + NodeHash::iterator nodeItem = _nodeHash.begin(); + + while (nodeItem != _nodeHash.end()) { + nodeItem.value()->lock(); - if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { + if ((usecTimestampNow() - nodeItem.value()->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { + SharedNodePointer node = nodeItem.value(); + // kill this node, don't lock - we already did it - nodeList->killNode(&(*node), false); + _nodeHash.erase(nodeItem); + + // unlock the node + node->unlock(); } - - node->unlock(); } } @@ -868,80 +834,6 @@ void NodeList::saveData(QSettings* settings) { settings->endGroup(); } -NodeList::iterator NodeList::begin() const { - Node** nodeBucket = NULL; - - for (int i = 0; i < _numNodes; i++) { - if (i % NODES_PER_BUCKET == 0) { - nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET]; - } - - if (nodeBucket[i % NODES_PER_BUCKET]->isAlive()) { - return NodeListIterator(this, i); - } - } - - // there's no alive node to start from - return the end - return end(); -} - -NodeList::iterator NodeList::end() const { - return NodeListIterator(this, _numNodes); -} - -NodeListIterator::NodeListIterator(const NodeList* nodeList, int nodeIndex) : - _nodeIndex(nodeIndex) { - _nodeList = nodeList; -} - -NodeListIterator& NodeListIterator::operator=(const NodeListIterator& otherValue) { - _nodeList = otherValue._nodeList; - _nodeIndex = otherValue._nodeIndex; - return *this; -} - -bool NodeListIterator::operator==(const NodeListIterator &otherValue) { - return _nodeIndex == otherValue._nodeIndex; -} - -bool NodeListIterator::operator!=(const NodeListIterator &otherValue) { - return !(*this == otherValue); -} - -Node& NodeListIterator::operator*() { - Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET]; - return *nodeBucket[_nodeIndex % NODES_PER_BUCKET]; -} - -Node* NodeListIterator::operator->() { - Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET]; - return nodeBucket[_nodeIndex % NODES_PER_BUCKET]; -} - -NodeListIterator& NodeListIterator::operator++() { - skipDeadAndStopIncrement(); - return *this; -} - -NodeList::iterator NodeListIterator::operator++(int) { - NodeListIterator newIterator = NodeListIterator(*this); - skipDeadAndStopIncrement(); - return newIterator; -} - -void NodeListIterator::skipDeadAndStopIncrement() { - while (_nodeIndex != _nodeList->_numNodes) { - ++_nodeIndex; - - if (_nodeIndex == _nodeList->_numNodes) { - break; - } else if ((*(*this)).isAlive()) { - // skip over the dead nodes - break; - } - } -} - void NodeList::addDomainListener(DomainChangeListener* listener) { _domainListeners.push_back(listener); QString domain = _domainHostname.isEmpty() ? _domainSockAddr.getAddress().toString() : _domainHostname; @@ -957,33 +849,6 @@ void NodeList::removeDomainListener(DomainChangeListener* listener) { } } -void NodeList::addHook(NodeListHook* hook) { - _hooks.push_back(hook); -} - -void NodeList::removeHook(NodeListHook* hook) { - for (int i = 0; i < _hooks.size(); i++) { - if (_hooks[i] == hook) { - _hooks.erase(_hooks.begin() + i); - return; - } - } -} - -void NodeList::notifyHooksOfAddedNode(Node* node) { - for (int i = 0; i < _hooks.size(); i++) { - //printf("NodeList::notifyHooksOfAddedNode() i=%d\n", i); - _hooks[i]->nodeAdded(node); - } -} - -void NodeList::notifyHooksOfKilledNode(Node* node) { - for (int i = 0; i < _hooks.size(); i++) { - //printf("NodeList::notifyHooksOfKilledNode() i=%d\n", i); - _hooks[i]->nodeKilled(node); - } -} - void NodeList::notifyDomainChanged() { for (int i = 0; i < _domainListeners.size(); i++) { _domainListeners[i]->domainChanged(_domainHostname); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 47cdbac99d..e139eb62f2 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -14,9 +14,10 @@ #include #include +#include +#include #include #include -#include #include "Node.h" #include "NodeTypes.h" @@ -43,31 +44,21 @@ const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; class Assignment; class HifiSockAddr; -class NodeListIterator; - -// Callers who want to hook add/kill callbacks should implement this class -class NodeListHook { -public: - virtual void nodeAdded(Node* node) = 0; - virtual void nodeKilled(Node* node) = 0; -}; class DomainChangeListener { public: virtual void domainChanged(QString domain) = 0; }; +typedef QSharedPointer SharedNodePointer; +typedef QHash NodeHash; + class NodeList : public QObject { Q_OBJECT public: static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0); static NodeList* getInstance(); - typedef NodeListIterator iterator; - - NodeListIterator begin() const; - NodeListIterator end() const; - NODE_TYPE getOwnerType() const { return _ownerType; } void setOwnerType(NODE_TYPE ownerType) { _ownerType = ownerType; } @@ -88,8 +79,9 @@ public: void(*linkedDataCreateCallback)(Node *); - int size() { return _numNodes; } - int getNumAliveNodes() const; + const NodeHash& getNodeHash() { return _nodeHash; } + + int size() const { return _nodeHash.size(); } int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; } @@ -107,13 +99,13 @@ public: int fillPingReplyPacket(unsigned char* pingBuffer, unsigned char* replyBuffer); void pingPublicAndLocalSocketsForInactiveNode(Node* node); + void killNodeWithUUID(const QUuid& nodeUUID); void sendKillNode(const char* nodeTypes, int numNodeTypes); - Node* nodeWithAddress(const HifiSockAddr& senderSockAddr); - Node* nodeWithUUID(const QUuid& nodeUUID); + SharedNodePointer nodeWithAddress(const HifiSockAddr& senderSockAddr); + SharedNodePointer nodeWithUUID(const QUuid& nodeUUID); - Node* addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); - void killNode(Node* node, bool mustLockNode = true); + SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); void processNodeData(const HifiSockAddr& senderSockAddr, unsigned char *packetData, size_t dataBytes); void processBulkNodeData(const HifiSockAddr& senderSockAddr, unsigned char *packetData, int numTotalBytes); @@ -122,18 +114,11 @@ public: unsigned broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes); - Node* soloNodeOfType(char nodeType); + SharedNodePointer soloNodeOfType(char nodeType); void loadData(QSettings* settings); void saveData(QSettings* settings); - friend class NodeListIterator; - - void addHook(NodeListHook* hook); - void removeHook(NodeListHook* hook); - void notifyHooksOfAddedNode(Node* node); - void notifyHooksOfKilledNode(Node* node); - void addDomainListener(DomainChangeListener* listener); void removeDomainListener(DomainChangeListener* listener); @@ -142,6 +127,9 @@ public slots: void sendDomainServerCheckIn(); void pingInactiveNodes(); void removeSilentNodes(); +signals: + void nodeAdded(QSharedPointer); + void nodeKilled(QSharedPointer); private: static NodeList* _sharedInstance; @@ -150,17 +138,14 @@ private: NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton - void addNodeToList(Node* newNode); - void sendSTUNRequest(); void processSTUNResponse(unsigned char* packetData, size_t dataBytes); void processKillNode(unsigned char* packetData, size_t dataBytes); + NodeHash _nodeHash; QString _domainHostname; HifiSockAddr _domainSockAddr; - Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET]; - int _numNodes; QUdpSocket _nodeSocket; char _ownerType; char* _nodeTypesOfInterest; @@ -174,7 +159,6 @@ private: void activateSocketFromNodeCommunication(const HifiSockAddr& nodeSockAddr); void timePingReply(const HifiSockAddr& nodeAddress, unsigned char *packetData); - std::vector _hooks; std::vector _domainListeners; void resetDomainData(char domainField[], const char* domainData); @@ -182,27 +166,4 @@ private: void domainLookup(); }; -class NodeListIterator : public std::iterator { -public: - NodeListIterator(const NodeList* nodeList, int nodeIndex); - - int getNodeIndex() { return _nodeIndex; } - - NodeListIterator& operator=(const NodeListIterator& otherValue); - - bool operator==(const NodeListIterator& otherValue); - bool operator!= (const NodeListIterator& otherValue); - - Node& operator*(); - Node* operator->(); - - NodeListIterator& operator++(); - NodeListIterator operator++(int); -private: - void skipDeadAndStopIncrement(); - - const NodeList* _nodeList; - int _nodeIndex; -}; - #endif /* defined(__hifi__NodeList__) */ diff --git a/libraries/shared/src/ReceivedPacketProcessor.cpp b/libraries/shared/src/ReceivedPacketProcessor.cpp index 4ad869460e..d61db2b184 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.cpp +++ b/libraries/shared/src/ReceivedPacketProcessor.cpp @@ -18,7 +18,7 @@ ReceivedPacketProcessor::ReceivedPacketProcessor() { void ReceivedPacketProcessor::queueReceivedPacket(const HifiSockAddr& address, unsigned char* packetData, ssize_t packetLength) { // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(address); + SharedNodePointer node = NodeList::getInstance()->nodeWithAddress(address); if (node) { node->setLastHeardMicrostamp(usecTimestampNow()); }