diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 9df66d0362..aaf58a7f42 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -114,28 +114,38 @@ void AvatarMixer::broadcastAvatarData() { NodeList* nodeList = NodeList::getInstance(); + AvatarMixerClientData* nodeData = NULL; + AvatarMixerClientData* otherNodeData = NULL; + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket()) { + if (node->getLinkedData() && node->getType() == NodeType::Agent && node->getActiveSocket() + && (nodeData = reinterpret_cast(node->getLinkedData()))->getMutex().tryLock()) { ++_sumListeners; // reset packet pointers for this node mixedAvatarByteArray.resize(numPacketHeaderBytes); - AvatarMixerClientData* myData = reinterpret_cast(node->getLinkedData()); - AvatarData& avatar = myData->getAvatar(); + AvatarData& avatar = nodeData->getAvatar(); glm::vec3 myPosition = avatar.getPosition(); // this is an AGENT we have received head data from // send back a packet with other active node data to this node foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) { - if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()) { + if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID() + && (otherNodeData = reinterpret_cast(otherNode->getLinkedData()))->getMutex().tryLock()) { AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); AvatarData& otherAvatar = otherNodeData->getAvatar(); glm::vec3 otherPosition = otherAvatar.getPosition(); - // Decide whether to send this avatar's data based on current performance throttling - if (_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio)) { + float distanceToAvatar = glm::length(myPosition - otherPosition); + // The full rate distance is the distance at which EVERY update will be sent for this avatar + // at a distance of twice the full rate distance, there will be a 50% chance of sending this avatar's update + const float FULL_RATE_DISTANCE = 2.f; + + // Decide whether to send this avatar's data based on it's distance from us + if ((_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio)) + && (distanceToAvatar == 0.f || randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) { QByteArray avatarByteArray; avatarByteArray.append(otherNode->getUUID().toRfc4122()); avatarByteArray.append(otherAvatar.toByteArray()); @@ -152,7 +162,7 @@ void AvatarMixer::broadcastAvatarData() { // if the receiving avatar has just connected make sure we send out the mesh and billboard // for this avatar (assuming they exist) - bool forceSend = !myData->checkAndSetHasReceivedFirstPackets(); + bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets(); // we will also force a send of billboard or identity packet // if either has changed in the last frame @@ -185,10 +195,14 @@ void AvatarMixer::broadcastAvatarData() { ++_sumIdentityPackets; } } + + otherNodeData->getMutex().unlock(); } } nodeList->writeDatagram(mixedAvatarByteArray, node); + + nodeData->getMutex().unlock(); } } @@ -232,6 +246,7 @@ void AvatarMixer::readPendingDatagrams() { // parse the identity packet and update the change timestamp if appropriate if (avatar.hasIdentityChangedAfterParsing(receivedPacket)) { + QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch()); } } @@ -248,6 +263,7 @@ void AvatarMixer::readPendingDatagrams() { // parse the billboard packet and update the change timestamp if appropriate if (avatar.hasBillboardChangedAfterParsing(receivedPacket)) { + QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch()); } diff --git a/libraries/shared/src/NodeData.cpp b/libraries/shared/src/NodeData.cpp index a7fa18f409..e3800f8b93 100644 --- a/libraries/shared/src/NodeData.cpp +++ b/libraries/shared/src/NodeData.cpp @@ -8,6 +8,12 @@ #include "NodeData.h" +NodeData::NodeData() : + _mutex() +{ + +} + NodeData::~NodeData() { } \ No newline at end of file diff --git a/libraries/shared/src/NodeData.h b/libraries/shared/src/NodeData.h index cf800fc3cd..b6b75443a2 100644 --- a/libraries/shared/src/NodeData.h +++ b/libraries/shared/src/NodeData.h @@ -9,6 +9,7 @@ #ifndef hifi_NodeData_h #define hifi_NodeData_h +#include #include class Node; @@ -16,9 +17,14 @@ class Node; class NodeData : public QObject { Q_OBJECT public: - + NodeData(); virtual ~NodeData() = 0; virtual int parseData(const QByteArray& packet) = 0; + + QMutex& getMutex() { return _mutex; } + +private: + QMutex _mutex; }; #endif diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 85e981490e..e80f25709a 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -317,6 +317,8 @@ int NodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode linkedDataCreateCallback(matchingNode.data()); } + QMutexLocker linkedDataLocker(&matchingNode->getLinkedData()->getMutex()); + return matchingNode->getLinkedData()->parseData(packet); }