diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 16a49a8999..6f04cfa196 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -16,9 +16,13 @@ #include #include -#include #include +#include +#include +ScriptableAvatar::ScriptableAvatar() { + _clientTraitsHandler = std::unique_ptr(new ClientTraitsHandler(this)); +} QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) { _globalPosition = getWorldPosition(); @@ -63,8 +67,6 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _animSkeleton.reset(); AvatarData::setSkeletonModelURL(skeletonModelURL); - - _clientTraitsHandler.markTraitChanged(AvatarTraits::SkeletonModelURL); } static AnimPose composeAnimPose(const FBXJoint& fbxJoint, const glm::quat rotation, const glm::vec3 translation) { @@ -141,5 +143,5 @@ void ScriptableAvatar::update(float deltatime) { } } - _clientTraitsHandler.sendChangedTraitsToMixer(); + _clientTraitsHandler->sendChangedTraitsToMixer(); } diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 201bfe67e8..89f9369133 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -15,7 +15,6 @@ #include #include #include -#include #include /**jsdoc @@ -125,6 +124,8 @@ class ScriptableAvatar : public AvatarData, public Dependency { Q_OBJECT public: + ScriptableAvatar(); + /**jsdoc * @function Avatar.startAnimation * @param {string} url @@ -165,8 +166,6 @@ private: QStringList _maskedJoints; AnimationPointer _bind; // a sleazy way to get the skeleton, given the various library/cmake dependencies std::shared_ptr _animSkeleton; - - ClientTraitsHandler _clientTraitsHandler { this }; }; #endif // hifi_ScriptableAvatar_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 90d1ad257b..2c88f917a1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -119,9 +119,9 @@ MyAvatar::MyAvatar(QThread* thread) : _goToOrientation(), _prevShouldDrawHead(true), _audioListenerMode(FROM_HEAD), - _hmdAtRestDetector(glm::vec3(0), glm::quat()), - _clientTraitsHandler(this) + _hmdAtRestDetector(glm::vec3(0), glm::quat()) { + _clientTraitsHandler = std::unique_ptr(new ClientTraitsHandler(this)); // give the pointer to our head to inherited _headData variable from AvatarData _headData = new MyHead(this); @@ -514,7 +514,7 @@ void MyAvatar::update(float deltaTime) { sendIdentityPacket(); } - _clientTraitsHandler.sendChangedTraitsToMixer(); + _clientTraitsHandler->sendChangedTraitsToMixer(); simulate(deltaTime); @@ -1702,10 +1702,6 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { saveAvatarUrl(); emit skeletonChanged(); - - if (previousSkeletonModelURL != _skeletonModelURL) { - _clientTraitsHandler.markTraitChanged(AvatarTraits::SkeletonModelURL); - } } void MyAvatar::removeAvatarEntities(const std::function& condition) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8fdc4ba4e3..ba6348cc22 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1334,7 +1334,6 @@ public slots: */ void setAnimGraphUrl(const QUrl& url); // thread-safe - /**jsdoc * @function MyAvatar.getPositionForAudio * @returns {Vec3} @@ -1347,7 +1346,6 @@ public slots: */ glm::quat getOrientationForAudio(); - /**jsdoc * @function MyAvatar.setModelScale * @param {number} scale @@ -1776,8 +1774,6 @@ private: bool _haveReceivedHeightLimitsFromDomain { false }; int _disableHandTouchCount { 0 }; - - ClientTraitsHandler _clientTraitsHandler; }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index c9d8049cd3..f32da39bba 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -43,6 +43,7 @@ #include "AvatarLogging.h" #include "AvatarTraits.h" +#include "ClientTraitsHandler.h" //#define WANT_DEBUG @@ -1897,6 +1898,10 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { updateJointMappings(); + if (_clientTraitsHandler) { + _clientTraitsHandler->markTraitChanged(AvatarTraits::SkeletonModelURL); + } + emit skeletonModelURLChanged(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 619f8e1722..a5d2d0749b 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -372,6 +372,8 @@ public: bool operator<(const AvatarPriority& other) const { return priority < other.priority; } }; +class ClientTraitsHandler; + class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT @@ -924,6 +926,7 @@ public: * @param {string} entityData */ Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData); + /**jsdoc * @function MyAvatar.clearAvatarEntity * @param {Uuid} entityID @@ -1435,6 +1438,9 @@ protected: bool _hasProcessedFirstIdentity { false }; float _density; + // null unless MyAvatar or ScriptableAvatar sending traits data to mixer + std::unique_ptr _clientTraitsHandler; + template T readLockWithNamedJointIndex(const QString& name, const T& defaultValue, F f) const { int index = getFauxJointIndex(name); diff --git a/libraries/avatars/src/AvatarTraits.h b/libraries/avatars/src/AvatarTraits.h index 121e1057c6..d30da0e1af 100644 --- a/libraries/avatars/src/AvatarTraits.h +++ b/libraries/avatars/src/AvatarTraits.h @@ -12,8 +12,8 @@ #ifndef hifi_AvatarTraits_h #define hifi_AvatarTraits_h +#include #include -#include #include namespace AvatarTraits { @@ -23,7 +23,28 @@ namespace AvatarTraits { TotalTraitTypes }; - using TraitTypeSet = std::set; + class TraitTypeSet { + public: + TraitTypeSet() {}; + + TraitTypeSet(std::initializer_list types) { + for (auto type : types) { + _types[type] = true; + } + }; + + bool contains(TraitType type) const { return _types[type]; } + + bool hasAny() const { return std::find(_types.begin(), _types.end(), true) != _types.end(); } + int size() const { return std::count(_types.begin(), _types.end(), true); } + + void insert(TraitType type) { _types[type] = true; } + void erase(TraitType type) { _types[type] = false; } + void clear() { std::fill(_types.begin(), _types.end(), false); } + private: + std::vector _types = { AvatarTraits::TotalTraitTypes, false }; + }; + const TraitTypeSet SimpleTraitTypes = { SkeletonModelURL }; using TraitVersion = uint32_t; @@ -35,6 +56,6 @@ namespace AvatarTraits { using TraitWireSize = uint16_t; using SimpleTraitVersions = std::vector; -} +}; #endif // hifi_AvatarTraits_h diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index 2518dedf37..8b3ded1e1c 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -63,7 +63,7 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { auto changedTraitsCopy { _changedTraits }; _changedTraits.clear(); - if (_performInitialSend || changedTraitsCopy.count(AvatarTraits::SkeletonModelURL)) { + if (_performInitialSend || changedTraitsCopy.contains(AvatarTraits::SkeletonModelURL)) { traitsPacketList->startSegment(); _owningAvatar->packTrait(AvatarTraits::SkeletonModelURL, *traitsPacketList); traitsPacketList->endSegment(); diff --git a/libraries/avatars/src/ClientTraitsHandler.h b/libraries/avatars/src/ClientTraitsHandler.h index 3a2b70776c..1d4c67d0c4 100644 --- a/libraries/avatars/src/ClientTraitsHandler.h +++ b/libraries/avatars/src/ClientTraitsHandler.h @@ -26,10 +26,10 @@ public: void sendChangedTraitsToMixer(); - bool hasChangedTraits() { return _changedTraits.size(); } + bool hasChangedTraits() { return _changedTraits.hasAny(); } void markTraitChanged(AvatarTraits::TraitType changedTrait) { _changedTraits.insert(changedTrait); } - bool hasTraitChanged(AvatarTraits::TraitType checkTrait) { return _changedTraits.count(checkTrait) > 0; } + bool hasTraitChanged(AvatarTraits::TraitType checkTrait) { return _changedTraits.contains(checkTrait) > 0; } void resetForNewMixer();