diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index e305972679..47f7084f64 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -62,7 +62,8 @@ void broadcastAvatarData() { mixedAvatarByteArray.resize(numPacketHeaderBytes); AvatarMixerClientData* myData = reinterpret_cast(node->getLinkedData()); - glm::vec3 myPosition = myData->getPosition(); + AvatarData& avatar = myData->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 @@ -70,7 +71,8 @@ void broadcastAvatarData() { if (otherNode->getLinkedData() && otherNode->getUUID() != node->getUUID()) { AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - glm::vec3 otherPosition = otherNodeData->getPosition(); + AvatarData& otherAvatar = otherNodeData->getAvatar(); + glm::vec3 otherPosition = otherAvatar.getPosition(); 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 @@ -79,7 +81,7 @@ void broadcastAvatarData() { if ((distanceToAvatar == 0.f) || (randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) { QByteArray avatarByteArray; avatarByteArray.append(otherNode->getUUID().toRfc4122()); - avatarByteArray.append(otherNodeData->toByteArray()); + avatarByteArray.append(otherAvatar.toByteArray()); if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) { nodeList->writeDatagram(mixedAvatarByteArray, node); @@ -110,7 +112,8 @@ void broadcastIdentityPacket() { if (node->getLinkedData() && node->getType() == NodeType::Agent) { AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); - QByteArray individualData = nodeData->identityByteArray(); + AvatarData& avatar = nodeData->getAvatar(); + QByteArray individualData = avatar.identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, node->getUUID().toRfc4122()); if (avatarIdentityPacket.size() + individualData.size() > MAX_PACKET_SIZE) { @@ -135,9 +138,10 @@ void broadcastIdentityPacket() { void broadcastBillboardPacket(const SharedNodePointer& sendingNode) { AvatarMixerClientData* nodeData = static_cast(sendingNode->getLinkedData()); + AvatarData& avatar = nodeData->getAvatar(); QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); packet.append(sendingNode->getUUID().toRfc4122()); - packet.append(nodeData->getBillboard()); + packet.append(avatar.getBillboard()); NodeList* nodeList = NodeList::getInstance(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { @@ -190,12 +194,13 @@ void AvatarMixer::readPendingDatagrams() { if (avatarNode && avatarNode->getLinkedData()) { AvatarMixerClientData* nodeData = reinterpret_cast(avatarNode->getLinkedData()); - if (nodeData->hasIdentityChangedAfterParsing(receivedPacket) + AvatarData& avatar = nodeData->getAvatar(); + if (avatar.hasIdentityChangedAfterParsing(receivedPacket) && !nodeData->hasSentIdentityBetweenKeyFrames()) { // this avatar changed their identity in some way and we haven't sent a packet in this keyframe QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); - QByteArray individualByteArray = nodeData->identityByteArray(); + QByteArray individualByteArray = avatar.identityByteArray(); individualByteArray.replace(0, NUM_BYTES_RFC4122_UUID, avatarNode->getUUID().toRfc4122()); identityPacket.append(individualByteArray); @@ -213,7 +218,8 @@ void AvatarMixer::readPendingDatagrams() { if (avatarNode && avatarNode->getLinkedData()) { AvatarMixerClientData* nodeData = static_cast(avatarNode->getLinkedData()); - if (nodeData->hasBillboardChangedAfterParsing(receivedPacket) + AvatarData& avatar = nodeData->getAvatar(); + if (avatar.hasBillboardChangedAfterParsing(receivedPacket) && !nodeData->hasSentBillboardBetweenKeyFrames()) { // this avatar changed their billboard and we haven't sent a packet in this keyframe broadcastBillboardPacket(avatarNode); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 388d6f6488..a29b6efdb4 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -9,8 +9,15 @@ #include "AvatarMixerClientData.h" AvatarMixerClientData::AvatarMixerClientData() : + NodeData(), _hasSentIdentityBetweenKeyFrames(false), _hasSentBillboardBetweenKeyFrames(false) { } + +int AvatarMixerClientData::parseData(const QByteArray& packet) { + // increment to push past the packet header + int offset = numBytesForPacketHeader(packet); + return _avatar.parseDataAtOffset(packet, offset); +} diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 7240288306..854e8172d3 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -12,11 +12,14 @@ #include #include +#include -class AvatarMixerClientData : public AvatarData { +class AvatarMixerClientData : public NodeData { Q_OBJECT public: AvatarMixerClientData(); + + int parseData(const QByteArray& packet); bool hasSentIdentityBetweenKeyFrames() const { return _hasSentIdentityBetweenKeyFrames; } void setHasSentIdentityBetweenKeyFrames(bool hasSentIdentityBetweenKeyFrames) @@ -25,11 +28,14 @@ public: bool hasSentBillboardBetweenKeyFrames() const { return _hasSentBillboardBetweenKeyFrames; } void setHasSentBillboardBetweenKeyFrames(bool hasSentBillboardBetweenKeyFrames) { _hasSentBillboardBetweenKeyFrames = hasSentBillboardBetweenKeyFrames; } + + AvatarData& getAvatar() { return _avatar; } private: bool _hasSentIdentityBetweenKeyFrames; bool _hasSentBillboardBetweenKeyFrames; + AvatarData _avatar; }; #endif /* defined(__hifi__AvatarMixerClientData__) */ diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index cb6e3d67ee..75a8386ea9 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -633,11 +633,11 @@ void Avatar::setBillboard(const QByteArray& billboard) { _billboardTexture.reset(); } -int Avatar::parseData(const QByteArray& packet) { +int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) { // change in position implies movement glm::vec3 oldPosition = _position; - int bytesRead = AvatarData::parseData(packet); + int bytesRead = AvatarData::parseDataAtOffset(packet, offset); const float MOVE_DISTANCE_THRESHOLD = 0.001f; _moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 542320805e..30073c54d4 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -133,7 +133,7 @@ public: void setShowDisplayName(bool showDisplayName); - int parseData(const QByteArray& packet); + int parseDataAtOffset(const QByteArray& packet, int offset); static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index cd7d360743..49479e903e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -148,10 +148,6 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const void AvatarManager::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer &mixerWeakPointer) { int bytesRead = numBytesForPacketHeader(datagram); - QByteArray dummyAvatarByteArray = byteArrayWithPopulatedHeader(PacketTypeAvatarData); - int numDummyHeaderBytes = dummyAvatarByteArray.size(); - int numDummyHeaderBytesWithoutUUID = numDummyHeaderBytes - NUM_BYTES_RFC4122_UUID; - // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (bytesRead < datagram.size() && mixerWeakPointer.data()) { @@ -171,16 +167,10 @@ void AvatarManager::processAvatarDataPacket(const QByteArray &datagram, const QW qDebug() << "Adding avatar with UUID" << nodeUUID << "to AvatarManager hash."; } - // copy the rest of the packet to the avatarData holder so we can read the next Avatar from there - dummyAvatarByteArray.resize(numDummyHeaderBytesWithoutUUID); - - // make this Avatar's UUID the UUID in the packet and tack the remaining data onto the end - dummyAvatarByteArray.append(datagram.mid(bytesRead)); // have the matching (or new) avatar parse the data from the packet - bytesRead += matchingAvatar->parseData(dummyAvatarByteArray) - numDummyHeaderBytesWithoutUUID; + bytesRead += matchingAvatar->parseDataAtOffset(datagram, bytesRead); } - } void AvatarManager::processAvatarIdentityPacket(const QByteArray &packet) { diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 21de041343..5650d7a800 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -29,7 +29,6 @@ using namespace std; QNetworkAccessManager* AvatarData::networkAccessManager = NULL; AvatarData::AvatarData() : - NodeData(), _handPosition(0,0,0), _bodyYaw(-90.f), _bodyPitch(0.0f), @@ -184,8 +183,8 @@ QByteArray AvatarData::toByteArray() { return avatarDataByteArray.left(destinationBuffer - startPosition); } -// called on the other nodes - assigns it to my views of the others -int AvatarData::parseData(const QByteArray& packet) { +// read data in packet starting at byte offset and return number of bytes parsed +int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { // lazily allocate memory for HeadData in case we're not an Avatar instance if (!_headData) { @@ -197,9 +196,8 @@ int AvatarData::parseData(const QByteArray& packet) { _handData = new HandData(this); } - // increment to push past the packet header const unsigned char* startPosition = reinterpret_cast(packet.data()); - const unsigned char* sourceBuffer = startPosition + numBytesForPacketHeader(packet); + const unsigned char* sourceBuffer = startPosition + offset; // Body world position memcpy(&_position, sourceBuffer, sizeof(float) * 3); @@ -288,13 +286,13 @@ int AvatarData::parseData(const QByteArray& packet) { // joint data int jointCount = *sourceBuffer++; _jointData.resize(jointCount); - unsigned char validity = 0; // although always set below, this fixes a warning of potential uninitialized use + unsigned char validity = 0; int validityBit = 0; for (int i = 0; i < jointCount; i++) { if (validityBit == 0) { validity = *sourceBuffer++; } - _jointData[i].valid = validity & (1 << validityBit); + _jointData[i].valid = (bool)(validity & (1 << validityBit)); validityBit = (validityBit + 1) % BITS_IN_BYTE; } for (int i = 0; i < jointCount; i++) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 067fadd8b1..c7a93daef5 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -40,7 +40,6 @@ typedef unsigned long long quint64; #include #include -#include #include "HeadData.h" #include "HandData.h" @@ -74,7 +73,7 @@ class QNetworkAccessManager; class JointData; -class AvatarData : public NodeData { +class AvatarData : public QObject { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -97,7 +96,7 @@ class AvatarData : public NodeData { Q_PROPERTY(QString billboardURL READ getBillboardURL WRITE setBillboardFromURL) public: AvatarData(); - ~AvatarData(); + virtual ~AvatarData(); const glm::vec3& getPosition() const { return _position; } void setPosition(const glm::vec3 position) { _position = position; } @@ -106,7 +105,11 @@ public: void setHandPosition(const glm::vec3& handPosition); QByteArray toByteArray(); - int parseData(const QByteArray& packet); + + /// \param packet byte array of data + /// \param offset number of bytes into packet where data starts + /// \return number of bytes parsed + virtual int parseDataAtOffset(const QByteArray& packet, int offset); // Body Rotation (degrees) float getBodyYaw() const { return _bodyYaw; }