From 55b0060df937c3d6d9a2b50073688cbb83c48662 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 12 May 2016 14:40:27 -0700 Subject: [PATCH 01/59] Convert JointData from relative frame to absolute. --- libraries/animation/src/Rig.cpp | 82 +++++++++++++------- libraries/animation/src/Rig.h | 12 +-- libraries/avatars/src/AvatarData.cpp | 6 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/render-utils/src/Model.cpp | 4 - libraries/render-utils/src/Model.h | 4 - 6 files changed, 63 insertions(+), 48 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 67dfbec24a..378bd55667 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -165,6 +165,7 @@ void Rig::destroyAnimGraph() { void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) { _geometryOffset = AnimPose(geometry.offset); + _invGeometryOffset = _geometryOffset.inverse(); setModelOffset(modelOffset); _animSkeleton = std::make_shared(geometry); @@ -193,6 +194,7 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff void Rig::reset(const FBXGeometry& geometry) { _geometryOffset = AnimPose(geometry.offset); + _invGeometryOffset = _geometryOffset.inverse(); _animSkeleton = std::make_shared(geometry); _internalPoseSet._relativePoses.clear(); @@ -272,24 +274,6 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) { } } -bool Rig::getJointStateRotation(int index, glm::quat& rotation) const { - if (isIndexValid(index)) { - rotation = _internalPoseSet._relativePoses[index].rot; - return !isEqual(rotation, _animSkeleton->getRelativeDefaultPose(index).rot); - } else { - return false; - } -} - -bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const { - if (isIndexValid(index)) { - translation = _internalPoseSet._relativePoses[index].trans; - return !isEqual(translation, _animSkeleton->getRelativeDefaultPose(index).trans); - } else { - return false; - } -} - void Rig::clearJointState(int index) { if (isIndexValid(index)) { _internalPoseSet._overrideFlags[index] = false; @@ -446,6 +430,23 @@ void Rig::calcAnimAlpha(float speed, const std::vector& referenceSpeeds, *alphaOut = alpha; } +bool Rig::getJointData(int index, JointData& jointDataOut) const { + if (isIndexValid(index)) { + jointDataOut.rotation = _internalPoseSet._absolutePoses[index].rot; + jointDataOut.rotationSet = !isEqual(jointDataOut.rotation, _animSkeleton->getAbsoluteDefaultPose(index).rot); + + // geometry offset is used here so that translations are in meters, this is what the avatar mixer expects + jointDataOut.translation = _geometryOffset * _internalPoseSet._absolutePoses[index].trans; + jointDataOut.translationSet = !isEqual(jointDataOut.translation, _animSkeleton->getAbsoluteDefaultPose(index).trans); + return true; + } else { + jointDataOut.translationSet = false; + jointDataOut.rotationSet = false; + return false; + } +} + + void Rig::setEnableInverseKinematics(bool enable) { _enableInverseKinematics = enable; } @@ -1232,21 +1233,44 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { jointDataVec.resize((int)getJointStateCount()); for (auto i = 0; i < jointDataVec.size(); i++) { JointData& data = jointDataVec[i]; - data.rotationSet |= getJointStateRotation(i, data.rotation); - // geometry offset is used here so that translations are in meters. - // this is what the avatar mixer expects - data.translationSet |= getJointStateTranslation(i, data.translation); - data.translation = _geometryOffset * data.translation; + getJointData(i, data); } } void Rig::copyJointsFromJointData(const QVector& jointDataVec) { - AnimPose invGeometryOffset = _geometryOffset.inverse(); - for (int i = 0; i < jointDataVec.size(); i++) { - const JointData& data = jointDataVec.at(i); - setJointRotation(i, data.rotationSet, data.rotation, 1.0f); - // geometry offset is used here to undo the fact that avatar mixer translations are in meters. - setJointTranslation(i, data.translationSet, invGeometryOffset * data.translation, 1.0f); + + if (_animSkeleton) { + + std::vector overrideFlags(_internalPoseSet._overridePoses.size(), false); + AnimPoseVec overridePoses = _animSkeleton->getAbsoluteDefaultPoses(); // start with the default poses. + + ASSERT(overrideFlags.size() == absoluteOverridePoses.size()); + + for (int i = 0; i < jointDataVec.size(); i++) { + if (isIndexValid(i)) { + const JointData& data = jointDataVec.at(i); + if (data.rotationSet) { + overrideFlags[i] = true; + overridePoses[i].rot = data.rotation; + } + if (data.translationSet) { + overrideFlags[i] = true; + // convert from meters back into geometry units. + overridePoses[i].trans = _invGeometryOffset * data.translation; + } + } + } + + ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); + + _animSkeleton->convertAbsolutePosesToRelative(overridePoses); + + for (int i = 0; i < jointDataVec.size(); i++) { + if (overrideFlags[i]) { + _internalPoseSet._overrideFlags[i] = true; + _internalPoseSet._overridePoses[i] = overridePoses[i]; + } + } } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 363006d48c..7446fddc47 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -104,12 +104,6 @@ public: void setModelOffset(const glm::mat4& modelOffsetMat); - // geometry space - bool getJointStateRotation(int index, glm::quat& rotation) const; - - // geometry space - bool getJointStateTranslation(int index, glm::vec3& translation) const; - void clearJointState(int index); void clearJointStates(); void clearJointAnimationPriority(int index); @@ -119,8 +113,6 @@ public: // geometry space void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority); - - // geometry space void setJointRotation(int index, bool valid, const glm::quat& rotation, float priority); // legacy @@ -237,8 +229,12 @@ protected: void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); void calcAnimAlpha(float speed, const std::vector& referenceSpeeds, float* alphaOut) const; + // geometry space + bool getJointData(int index, JointData& jointDataOut) const; + AnimPose _modelOffset; // model to rig space AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets) + AnimPose _invGeometryOffset; struct PoseSet { AnimPoseVec _relativePoses; // geometry space relative to parent. diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9c556dc42b..784044da2e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -121,6 +121,8 @@ void AvatarData::setHandPosition(const glm::vec3& handPosition) { _handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition()); } +#define WANT_DEBUG + QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { // TODO: DRY this up to a shared method // that can pack any type given the number of bytes @@ -329,7 +331,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { } #ifdef WANT_DEBUG - if (sendAll) { + //if (sendAll) { qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll << "rotations:" << rotationSentCount << "translations:" << translationSentCount << "largest:" << maxTranslationDimension @@ -339,7 +341,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { << (beforeTranslations - beforeRotations) << "+" << (destinationBuffer - beforeTranslations) << "=" << (destinationBuffer - startPosition); - } + //} #endif return avatarDataByteArray.left(destinationBuffer - startPosition); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index b98a87e439..e0d854ab71 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -174,7 +174,8 @@ const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57; enum class AvatarMixerPacketVersion : PacketVersion { TranslationSupport = 17, - SoftAttachmentSupport + SoftAttachmentSupport, + AbsoluteFortyEightBitRotations }; #endif // hifi_PacketHeaders_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 2fe4427333..e4c414d30b 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -726,10 +726,6 @@ glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { return translatedPoint; } -bool Model::getJointState(int index, glm::quat& rotation) const { - return _rig->getJointStateRotation(index, rotation); -} - void Model::clearJointState(int index) { _rig->clearJointState(index); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 581184918d..6a7c9ec560 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -252,10 +252,6 @@ protected: /// Returns the scaled equivalent of a point in model space. glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const; - /// Fetches the joint state at the specified index. - /// \return whether or not the joint state is "valid" (that is, non-default) - bool getJointState(int index, glm::quat& rotation) const; - /// Clear the joint states void clearJointState(int index); From 36c175d4ccf22b5c64b22b4a10714e2f31bd147c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 12 May 2016 15:55:48 -0700 Subject: [PATCH 02/59] Ensure that JointData is in the absolute rig coordinate frame. --- libraries/animation/src/Rig.cpp | 42 ++++++++++++++++----------------- libraries/animation/src/Rig.h | 3 --- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 378bd55667..34c917da74 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -430,23 +430,6 @@ void Rig::calcAnimAlpha(float speed, const std::vector& referenceSpeeds, *alphaOut = alpha; } -bool Rig::getJointData(int index, JointData& jointDataOut) const { - if (isIndexValid(index)) { - jointDataOut.rotation = _internalPoseSet._absolutePoses[index].rot; - jointDataOut.rotationSet = !isEqual(jointDataOut.rotation, _animSkeleton->getAbsoluteDefaultPose(index).rot); - - // geometry offset is used here so that translations are in meters, this is what the avatar mixer expects - jointDataOut.translation = _geometryOffset * _internalPoseSet._absolutePoses[index].trans; - jointDataOut.translationSet = !isEqual(jointDataOut.translation, _animSkeleton->getAbsoluteDefaultPose(index).trans); - return true; - } else { - jointDataOut.translationSet = false; - jointDataOut.rotationSet = false; - return false; - } -} - - void Rig::setEnableInverseKinematics(bool enable) { _enableInverseKinematics = enable; } @@ -1230,10 +1213,22 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const { } void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { + + const AnimPose geometryToRigPose(_geometryToRigTransform); + jointDataVec.resize((int)getJointStateCount()); for (auto i = 0; i < jointDataVec.size(); i++) { JointData& data = jointDataVec[i]; - getJointData(i, data); + if (isIndexValid(i)) { + AnimPose defaultPose = geometryToRigPose * _animSkeleton->getAbsoluteDefaultPose(i); + data.rotation = _internalPoseSet._absolutePoses[i].rot; + data.rotationSet = !isEqual(data.rotation, defaultPose.rot); + data.translation = _internalPoseSet._absolutePoses[i].trans; + data.translationSet = !isEqual(data.translation, defaultPose.trans); + } else { + data.translationSet = false; + data.rotationSet = false; + } } } @@ -1243,8 +1238,11 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { std::vector overrideFlags(_internalPoseSet._overridePoses.size(), false); AnimPoseVec overridePoses = _animSkeleton->getAbsoluteDefaultPoses(); // start with the default poses. + for (int i = 0; i < overridePoses.size(); i++) { + overridePoses[i] = AnimPose(_geometryToRigTransform) * overridePoses[i]; + } - ASSERT(overrideFlags.size() == absoluteOverridePoses.size()); + ASSERT(overrideFlags.size() == overridePoses.size()); for (int i = 0; i < jointDataVec.size(); i++) { if (isIndexValid(i)) { @@ -1255,8 +1253,7 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { } if (data.translationSet) { overrideFlags[i] = true; - // convert from meters back into geometry units. - overridePoses[i].trans = _invGeometryOffset * data.translation; + overridePoses[i].trans = data.translation; } } } @@ -1265,10 +1262,11 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { _animSkeleton->convertAbsolutePosesToRelative(overridePoses); + AnimPose rigToGeometryPose(_rigToGeometryTransform); for (int i = 0; i < jointDataVec.size(); i++) { if (overrideFlags[i]) { _internalPoseSet._overrideFlags[i] = true; - _internalPoseSet._overridePoses[i] = overridePoses[i]; + _internalPoseSet._overridePoses[i] = rigToGeometryPose * overridePoses[i]; } } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 7446fddc47..891d9fdb92 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -229,9 +229,6 @@ protected: void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); void calcAnimAlpha(float speed, const std::vector& referenceSpeeds, float* alphaOut) const; - // geometry space - bool getJointData(int index, JointData& jointDataOut) const; - AnimPose _modelOffset; // model to rig space AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets) AnimPose _invGeometryOffset; From d86a608825bcf189057a794e68f8a9e2d990200c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 12 May 2016 17:10:48 -0700 Subject: [PATCH 03/59] Properly convert from absolute rig frame to relative geom frame --- libraries/animation/src/Rig.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 34c917da74..289612d712 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1236,14 +1236,17 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { if (_animSkeleton) { + // transform all the default poses into rig space. + const AnimPose geometryToRigPose(_geometryToRigTransform); std::vector overrideFlags(_internalPoseSet._overridePoses.size(), false); AnimPoseVec overridePoses = _animSkeleton->getAbsoluteDefaultPoses(); // start with the default poses. - for (int i = 0; i < overridePoses.size(); i++) { - overridePoses[i] = AnimPose(_geometryToRigTransform) * overridePoses[i]; + for (auto& pose : overridePoses) { + pose = geometryToRigPose * pose; } ASSERT(overrideFlags.size() == overridePoses.size()); + // copy over data from the jointDataVec, which is also in rig space. for (int i = 0; i < jointDataVec.size(); i++) { if (isIndexValid(i)) { const JointData& data = jointDataVec.at(i); @@ -1260,13 +1263,20 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); + // convert resulting poses into geometry space. + const AnimPose rigToGeometryPose(_rigToGeometryTransform); + for (auto& pose : overridePoses) { + pose = rigToGeometryPose * pose; + } + + // convert all poses from absolute to parent relative. _animSkeleton->convertAbsolutePosesToRelative(overridePoses); - AnimPose rigToGeometryPose(_rigToGeometryTransform); + // copy the geometry space parent relative poses into _overridePoses for (int i = 0; i < jointDataVec.size(); i++) { if (overrideFlags[i]) { _internalPoseSet._overrideFlags[i] = true; - _internalPoseSet._overridePoses[i] = rigToGeometryPose * overridePoses[i]; + _internalPoseSet._overridePoses[i] = overridePoses[i]; } } } From a251b9e3dfc1be0d6e47408a4fa5b549634c7e1e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 13 May 2016 11:16:31 -0700 Subject: [PATCH 04/59] Moved translations back into parent relative frame. --- libraries/animation/src/AnimSkeleton.cpp | 12 ++++++ libraries/animation/src/AnimSkeleton.h | 2 + libraries/animation/src/Rig.cpp | 54 ++++++++++++++++-------- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index 2d37be9b87..351c09beee 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -107,6 +107,18 @@ void AnimSkeleton::convertAbsolutePosesToRelative(AnimPoseVec& poses) const { } } +void AnimSkeleton::convertAbsoluteRotationsToRelative(std::vector& rotations) const { + // poses start off absolute and leave in relative frame + int lastIndex = std::min((int)rotations.size(), (int)_joints.size()); + for (int i = lastIndex - 1; i >= 0; --i) { + int parentIndex = _joints[i].parentIndex; + if (parentIndex != -1) { + rotations[i] = glm::inverse(rotations[parentIndex]) * rotations[i]; + } + } +} + + void AnimSkeleton::mirrorRelativePoses(AnimPoseVec& poses) const { convertRelativePosesToAbsolute(poses); mirrorAbsolutePoses(poses); diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index e2cd20d63e..68cce11326 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -55,6 +55,8 @@ public: void convertRelativePosesToAbsolute(AnimPoseVec& poses) const; void convertAbsolutePosesToRelative(AnimPoseVec& poses) const; + void convertAbsoluteRotationsToRelative(std::vector& rotations) const; + void mirrorRelativePoses(AnimPoseVec& poses) const; void mirrorAbsolutePoses(AnimPoseVec& poses) const; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 289612d712..9bba9ffc33 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1220,11 +1220,16 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { for (auto i = 0; i < jointDataVec.size(); i++) { JointData& data = jointDataVec[i]; if (isIndexValid(i)) { - AnimPose defaultPose = geometryToRigPose * _animSkeleton->getAbsoluteDefaultPose(i); + // rotations are in absolute rig frame. + glm::quat defaultAbsRot = geometryToRigPose.rot * _animSkeleton->getAbsoluteDefaultPose(i).rot; data.rotation = _internalPoseSet._absolutePoses[i].rot; - data.rotationSet = !isEqual(data.rotation, defaultPose.rot); - data.translation = _internalPoseSet._absolutePoses[i].trans; - data.translationSet = !isEqual(data.translation, defaultPose.trans); + data.rotationSet = !isEqual(data.rotation, defaultAbsRot); + + // translations are in relative frame but scaled so that they are in meters, + // instead of geometry units. + glm::vec3 defaultRelTrans = _geometryOffset.scale * _animSkeleton->getRelativeDefaultPose(i).trans; + data.translation = _geometryOffset.scale * _internalPoseSet._relativePoses[i].trans; + data.translationSet = !isEqual(data.translation, defaultRelTrans); } else { data.translationSet = false; data.rotationSet = false; @@ -1239,44 +1244,57 @@ void Rig::copyJointsFromJointData(const QVector& jointDataVec) { // transform all the default poses into rig space. const AnimPose geometryToRigPose(_geometryToRigTransform); std::vector overrideFlags(_internalPoseSet._overridePoses.size(), false); - AnimPoseVec overridePoses = _animSkeleton->getAbsoluteDefaultPoses(); // start with the default poses. - for (auto& pose : overridePoses) { - pose = geometryToRigPose * pose; + + // start with the default rotations in absolute rig frame + std::vector rotations; + rotations.reserve(_animSkeleton->getAbsoluteDefaultPoses().size()); + for (auto& pose : _animSkeleton->getAbsoluteDefaultPoses()) { + rotations.push_back(geometryToRigPose.rot * pose.rot); } - ASSERT(overrideFlags.size() == overridePoses.size()); + // start translations in relative frame but scaled to meters. + std::vector translations; + translations.reserve(_animSkeleton->getRelativeDefaultPoses().size()); + for (auto& pose : _animSkeleton->getRelativeDefaultPoses()) { + translations.push_back(_geometryOffset.scale * pose.trans); + } - // copy over data from the jointDataVec, which is also in rig space. + ASSERT(overrideFlags.size() == rotations.size()); + + // copy over rotations from the jointDataVec, which is also in absolute rig frame for (int i = 0; i < jointDataVec.size(); i++) { if (isIndexValid(i)) { const JointData& data = jointDataVec.at(i); if (data.rotationSet) { overrideFlags[i] = true; - overridePoses[i].rot = data.rotation; + rotations[i] = data.rotation; } if (data.translationSet) { overrideFlags[i] = true; - overridePoses[i].trans = data.translation; + translations[i] = data.translation; } } } ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); - // convert resulting poses into geometry space. - const AnimPose rigToGeometryPose(_rigToGeometryTransform); - for (auto& pose : overridePoses) { - pose = rigToGeometryPose * pose; + // convert resulting rotations into geometry space. + const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform)); + for (auto& rot : rotations) { + rot = rigToGeometryRot * rot; } - // convert all poses from absolute to parent relative. - _animSkeleton->convertAbsolutePosesToRelative(overridePoses); + // convert all rotations from absolute to parent relative. + _animSkeleton->convertAbsoluteRotationsToRelative(rotations); // copy the geometry space parent relative poses into _overridePoses for (int i = 0; i < jointDataVec.size(); i++) { if (overrideFlags[i]) { _internalPoseSet._overrideFlags[i] = true; - _internalPoseSet._overridePoses[i] = overridePoses[i]; + _internalPoseSet._overridePoses[i].scale = Vectors::ONE; + _internalPoseSet._overridePoses[i].rot = rotations[i]; + // scale translations from meters back into geometry units. + _internalPoseSet._overridePoses[i].trans = _invGeometryOffset.scale * translations[i]; } } } From 818d1f4601507256321dbacdef89c72d367495b0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 13 May 2016 16:19:32 -0700 Subject: [PATCH 05/59] Added six byte quaternion compression routines & tests --- libraries/shared/src/GLMHelpers.cpp | 81 ++++++++++++++++++++++++++++ libraries/shared/src/GLMHelpers.h | 8 +++ tests/shared/src/GLMHelpersTests.cpp | 47 ++++++++++++++++ tests/shared/src/GLMHelpersTests.h | 1 + 4 files changed, 137 insertions(+) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index bd8bffefd2..e81958f407 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -135,6 +135,87 @@ int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatO return sizeof(quatParts); } +#define HI_BYTE(x) (uint8_t)(x >> 8) +#define LO_BYTE(x) (uint8_t)(0xff & x) + +int packOrientationQuatToSixBytes(unsigned char* buffer, const glm::quat& quatInput) { + + // find largest component + uint8_t largestComponent = 0; + for (int i = 1; i < 4; i++) { + if (fabs(quatInput[i]) > fabs(quatInput[largestComponent])) { + largestComponent = i; + } + } + + // ensure that the sign of the dropped component is always negative. + glm::quat q = quatInput[largestComponent] > 0 ? -quatInput : quatInput; + + const float MAGNITUDE = 1.0f / sqrt(2.0f); + const uint32_t NUM_BITS_PER_COMPONENT = 15; + const uint32_t RANGE = (1 << NUM_BITS_PER_COMPONENT) - 1; + + // quantize the smallest three components into integers + uint16_t components[3]; + for (int i = 0, j = 0; i < 4; i++) { + if (i != largestComponent) { + // transform component into 0..1 range. + float value = (q[i] + MAGNITUDE) / (2.0f * MAGNITUDE); + + // quantize 0..1 into 0..range + components[j] = (uint16_t)(value * RANGE); + j++; + } + } + + // encode the largestComponent into the high bits of the first two components + components[0] = (0x7fff & components[0]) | ((0x01 & largestComponent) << 15); + components[1] = (0x7fff & components[1]) | ((0x02 & largestComponent) << 14); + + buffer[0] = HI_BYTE(components[0]); + buffer[1] = LO_BYTE(components[0]); + buffer[2] = HI_BYTE(components[1]); + buffer[3] = LO_BYTE(components[1]); + buffer[4] = HI_BYTE(components[2]); + buffer[5] = LO_BYTE(components[2]); + + return 6; +} + +int unpackOrientationQuatFromSixBytes(const unsigned char* buffer, glm::quat& quatOutput) { + + uint16_t components[3]; + components[0] = ((uint16_t)(0x7f & buffer[0]) << 8) | buffer[1]; + components[1] = ((uint16_t)(0x7f & buffer[2]) << 8) | buffer[3]; + components[2] = ((uint16_t)(0x7f & buffer[4]) << 8) | buffer[5]; + + // largestComponent is encoded into the highest bits of the first 2 components + uint8_t largestComponent = ((0x80 & buffer[2]) >> 6) | ((0x80 & buffer[0]) >> 7); + + const uint32_t NUM_BITS_PER_COMPONENT = 15; + const float RANGE = (float)((1 << NUM_BITS_PER_COMPONENT) - 1); + const float MAGNITUDE = 1.0f / sqrtf(2.0f); + float floatComponents[3]; + for (int i = 0; i < 3; i++) { + floatComponents[i] = ((float)components[i] / RANGE) * (2.0f * MAGNITUDE) - MAGNITUDE; + } + + // missingComponent is always negative. + float missingComponent = -sqrtf(1.0f - floatComponents[0] * floatComponents[0] - floatComponents[1] * floatComponents[1] - floatComponents[2] * floatComponents[2]); + + for (int i = 0, j = 0; i < 4; i++) { + if (i != largestComponent) { + quatOutput[i] = floatComponents[j]; + j++; + } else { + quatOutput[i] = missingComponent; + } + } + + return 6; +} + + // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 8b1446d4e5..ae9ec25195 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -97,6 +97,14 @@ int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destina int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput); +// alternate compression method that picks the smallest three quaternion components. +// and packs them into 15 bits each. An additional 2 bits are used to encode which component +// was omitted. Also because the components are encoded from the -1/sqrt(2) to 1/sqrt(2) which +// gives us some extra precision over the -1 to 1 range. The final result will have a maximum +// error of +- 4.3e-5 error per compoenent. +int packOrientationQuatToSixBytes(unsigned char* buffer, const glm::quat& quatInput); +int unpackOrientationQuatFromSixBytes(const unsigned char* buffer, glm::quat& quatOutput); + // Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they // are never greater than 1000 to 1, this allows us to encode each component in 16bits int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); diff --git a/tests/shared/src/GLMHelpersTests.cpp b/tests/shared/src/GLMHelpersTests.cpp index afb634ecbd..a796d62ba5 100644 --- a/tests/shared/src/GLMHelpersTests.cpp +++ b/tests/shared/src/GLMHelpersTests.cpp @@ -54,4 +54,51 @@ void GLMHelpersTests::testEulerDecomposition() { } } +static void testQuatCompression(glm::quat testQuat) { + float MAX_COMPONENT_ERROR = 4.3e-5f; + + glm::quat q; + uint8_t bytes[6]; + packOrientationQuatToSixBytes(bytes, testQuat); + unpackOrientationQuatFromSixBytes(bytes, q); + if (glm::dot(q, testQuat) < 0.0f) { + q = -q; + } + QCOMPARE_WITH_ABS_ERROR(q.x, testQuat.x, MAX_COMPONENT_ERROR); + QCOMPARE_WITH_ABS_ERROR(q.y, testQuat.y, MAX_COMPONENT_ERROR); + QCOMPARE_WITH_ABS_ERROR(q.z, testQuat.z, MAX_COMPONENT_ERROR); + QCOMPARE_WITH_ABS_ERROR(q.w, testQuat.w, MAX_COMPONENT_ERROR); +} + +void GLMHelpersTests::testSixByteOrientationCompression() { + const glm::quat ROT_X_90 = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat ROT_Y_180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0, 0.0f)); + const glm::quat ROT_Z_30 = glm::angleAxis(PI / 6.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + + testQuatCompression(ROT_X_90); + testQuatCompression(ROT_Y_180); + testQuatCompression(ROT_Z_30); + testQuatCompression(ROT_X_90 * ROT_Y_180); + testQuatCompression(ROT_Y_180 * ROT_X_90); + testQuatCompression(ROT_Z_30 * ROT_X_90); + testQuatCompression(ROT_X_90 * ROT_Z_30); + testQuatCompression(ROT_Z_30 * ROT_Y_180); + testQuatCompression(ROT_Y_180 * ROT_Z_30); + testQuatCompression(ROT_X_90 * ROT_Y_180 * ROT_Z_30); + testQuatCompression(ROT_Y_180 * ROT_Z_30 * ROT_X_90); + testQuatCompression(ROT_Z_30 * ROT_X_90 * ROT_Y_180); + + testQuatCompression(-ROT_X_90); + testQuatCompression(-ROT_Y_180); + testQuatCompression(-ROT_Z_30); + testQuatCompression(-(ROT_X_90 * ROT_Y_180)); + testQuatCompression(-(ROT_Y_180 * ROT_X_90)); + testQuatCompression(-(ROT_Z_30 * ROT_X_90)); + testQuatCompression(-(ROT_X_90 * ROT_Z_30)); + testQuatCompression(-(ROT_Z_30 * ROT_Y_180)); + testQuatCompression(-(ROT_Y_180 * ROT_Z_30)); + testQuatCompression(-(ROT_X_90 * ROT_Y_180 * ROT_Z_30)); + testQuatCompression(-(ROT_Y_180 * ROT_Z_30 * ROT_X_90)); + testQuatCompression(-(ROT_Z_30 * ROT_X_90 * ROT_Y_180)); +} diff --git a/tests/shared/src/GLMHelpersTests.h b/tests/shared/src/GLMHelpersTests.h index 5e880899e8..40d552a07b 100644 --- a/tests/shared/src/GLMHelpersTests.h +++ b/tests/shared/src/GLMHelpersTests.h @@ -19,6 +19,7 @@ class GLMHelpersTests : public QObject { Q_OBJECT private slots: void testEulerDecomposition(); + void testSixByteOrientationCompression(); }; float getErrorDifference(const float& a, const float& b); From 3d91c5b54def5317b7f4e6f6ee6097f85654ca5f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 13 May 2016 16:24:20 -0700 Subject: [PATCH 06/59] AvatarData.cpp: hooked up 6 byte quat compression --- libraries/avatars/src/AvatarData.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 784044da2e..3db3cea4cf 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -263,7 +263,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { for (int i = 0; i < _jointData.size(); i ++) { const JointData& data = _jointData[ i ]; if (validity & (1 << validityBit)) { - destinationBuffer += packOrientationQuatToBytes(destinationBuffer, data.rotation); + destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation); } if (++validityBit == BITS_IN_BYTE) { validityBit = 0; @@ -650,10 +650,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { if (validRotations[i]) { _hasNewJointRotations = true; data.rotationSet = true; - sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, data.rotation); + sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); } } - } // numJoints * 8 bytes + } // numJoints * 6 bytes // joint translations // get translation validity bits -- these indicate which translations were packed From 424517e3de2a9647cc6c99503c1f6b45066cd629 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 16 May 2016 19:11:50 -0700 Subject: [PATCH 07/59] Fix for Malformed packet errors --- libraries/avatars/src/AvatarData.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3db3cea4cf..251d83c19b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -37,6 +37,8 @@ #include "AvatarLogging.h" +#define WANT_DEBUG + quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND; using namespace std; @@ -121,8 +123,6 @@ void AvatarData::setHandPosition(const glm::vec3& handPosition) { _handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition()); } -#define WANT_DEBUG - QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { // TODO: DRY this up to a shared method // that can pack any type given the number of bytes @@ -331,7 +331,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { } #ifdef WANT_DEBUG - //if (sendAll) { + if (sendAll) { qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll << "rotations:" << rotationSentCount << "translations:" << translationSentCount << "largest:" << maxTranslationDimension @@ -341,7 +341,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { << (beforeTranslations - beforeRotations) << "+" << (destinationBuffer - beforeTranslations) << "=" << (destinationBuffer - startPosition); - //} + } #endif return avatarDataByteArray.left(destinationBuffer - startPosition); @@ -372,6 +372,12 @@ void AvatarData::doneEncoding(bool cullSmallChanges) { } bool AvatarData::shouldLogError(const quint64& now) { +#ifdef WANT_DEBUG + if (now > 0) { + return true; + } +#endif + if (now > _errorLogExpiry) { _errorLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY; return true; @@ -631,9 +637,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } } // 1 + bytesOfValidity bytes - // each joint rotation component is stored in two bytes (sizeof(uint16_t)) - int COMPONENTS_PER_QUATERNION = 4; - minPossibleSize += numValidJointRotations * COMPONENTS_PER_QUATERNION * sizeof(uint16_t); + // each joint rotation is stored in 6 bytes. + const size_t COMPRESSED_QUATERNION_SIZE = 6; + minPossibleSize += numValidJointRotations * COMPRESSED_QUATERNION_SIZE; if (minPossibleSize > maxAvailableSize) { if (shouldLogError(now)) { qCDebug(avatars) << "Malformed AvatarData packet after JointData rotation validity;" From b82356a249f00b6678bd161d6f88eb366bf2f39f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 17 May 2016 15:02:04 -0700 Subject: [PATCH 08/59] AvatarMixer: Clients will show incompatible version dialog For this to work, the server needs to send an empty AvatarIdentity packet back to the sender when it receives a packet mismatch error. This AvatarIdentity packet will be different then what the client expects and will trigger the incompatible version dialog. Previously, the avatar-mixer was just silently dropping incoming mismatched version packets. Causing the client to never get a response, and thus never showing the incompatible version dialog. --- assignment-client/src/avatars/AvatarMixer.cpp | 16 ++++++++++++++++ assignment-client/src/avatars/AvatarMixer.h | 3 ++- libraries/networking/src/LimitedNodeList.cpp | 7 ++++--- libraries/networking/src/LimitedNodeList.h | 4 +++- libraries/networking/src/udt/PacketHeaders.cpp | 4 +++- libraries/networking/src/udt/PacketHeaders.h | 2 +- 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index a109934d10..610c9bcc40 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -45,6 +45,9 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); + + auto nodeList = DependencyManager::get(); + connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); } AvatarMixer::~AvatarMixer() { @@ -509,6 +512,19 @@ void AvatarMixer::domainSettingsRequestComplete() { _broadcastThread.start(); } +void AvatarMixer::handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID) { + // if this client is using packet versions we don't expect. + if ((type == PacketTypeEnum::Value::AvatarIdentity || type == PacketTypeEnum::Value::AvatarData) && !senderUUID.isNull()) { + // Echo an empty AvatarIdentity packet back to that client. + // This should trigger a version mismatch dialog on their side. + auto nodeList = DependencyManager::get(); + auto node = nodeList->nodeWithUUID(senderUUID); + if (node) { + auto poisonPacket = NLPacket::create(PacketType::AvatarIdentity, 0); + nodeList->sendPacket(std::move(poisonPacket), *node); + } + } +} void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) { const QString AVATAR_MIXER_SETTINGS_KEY = "avatar_mixer"; diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index c7761a2cba..d1a9249c83 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -38,7 +38,8 @@ private slots: void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); void handleKillAvatarPacket(QSharedPointer message); void domainSettingsRequestComplete(); - + void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); + private: void broadcastAvatarData(); void parseDomainServerSettings(const QJsonObject& domainSettings); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2c10d0627e..9efe51183e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -176,9 +176,10 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { bool hasBeenOutput = false; QString senderString; + const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr(); + QUuid sourceID; if (NON_SOURCED_PACKETS.contains(headerType)) { - const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr(); hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, headerType); if (!hasBeenOutput) { @@ -186,7 +187,7 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort()); } } else { - QUuid sourceID = NLPacket::sourceIDInHeader(packet); + sourceID = NLPacket::sourceIDInHeader(packet); hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType); @@ -201,7 +202,7 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { << senderString << "sent" << qPrintable(QString::number(headerVersion)) << "but" << qPrintable(QString::number(versionForPacketType(headerType))) << "expected."; - emit packetVersionMismatch(headerType); + emit packetVersionMismatch(headerType, senderSockAddr, sourceID); } return false; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 0cbe9668b3..2ab8aaab39 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -236,7 +236,9 @@ public slots: signals: void dataSent(quint8 channelType, int bytes); - void packetVersionMismatch(PacketType type); + + // QUuid might be zero for non-sourced packet types. + void packetVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void nodeAdded(SharedNodePointer); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e4aab94090..81984521f8 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -48,9 +48,11 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: return VERSION_LIGHT_HAS_FALLOFF_RADIUS; + case PacketType::AvatarIdentity: case PacketType::AvatarData: case PacketType::BulkAvatarData: - return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); + case PacketType::KillAvatar: + return static_cast(AvatarMixerPacketVersion::AbsoluteSixByteRotations); case PacketType::ICEServerHeartbeat: return 18; // ICE Server Heartbeat signing case PacketType::AssetGetInfo: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index e0d854ab71..4c2141dff4 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -175,7 +175,7 @@ const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57; enum class AvatarMixerPacketVersion : PacketVersion { TranslationSupport = 17, SoftAttachmentSupport, - AbsoluteFortyEightBitRotations + AbsoluteSixByteRotations }; #endif // hifi_PacketHeaders_h From dc6e1afae668ddb683a9ce6b4413cee30a9b00e1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 17 May 2016 16:34:30 -0700 Subject: [PATCH 09/59] Changed empty AvatarIdentity packet to AvatarData packet Just in-case it actually gets through, it will fail to be parsed by AvatarData::parseDataFromBuffer() due to it's size. AvatarData::hasIdentityChangedAfterParsing() has no such checks. --- assignment-client/src/avatars/AvatarMixer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 610c9bcc40..cc94e4f1b7 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -515,13 +515,13 @@ void AvatarMixer::domainSettingsRequestComplete() { void AvatarMixer::handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID) { // if this client is using packet versions we don't expect. if ((type == PacketTypeEnum::Value::AvatarIdentity || type == PacketTypeEnum::Value::AvatarData) && !senderUUID.isNull()) { - // Echo an empty AvatarIdentity packet back to that client. + // Echo an empty AvatarData packet back to that client. // This should trigger a version mismatch dialog on their side. auto nodeList = DependencyManager::get(); auto node = nodeList->nodeWithUUID(senderUUID); if (node) { - auto poisonPacket = NLPacket::create(PacketType::AvatarIdentity, 0); - nodeList->sendPacket(std::move(poisonPacket), *node); + auto emptyPacket = NLPacket::create(PacketType::AvatarData, 0); + nodeList->sendPacket(std::move(emptyPacket), *node); } } } From 2c6b0e5c95f4aa86c3096db047809def5bae66b7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 17 May 2016 17:32:09 -0700 Subject: [PATCH 10/59] Fix for linux warning. --- libraries/shared/src/GLMHelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index e81958f407..e73e936fb9 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -151,7 +151,7 @@ int packOrientationQuatToSixBytes(unsigned char* buffer, const glm::quat& quatIn // ensure that the sign of the dropped component is always negative. glm::quat q = quatInput[largestComponent] > 0 ? -quatInput : quatInput; - const float MAGNITUDE = 1.0f / sqrt(2.0f); + const float MAGNITUDE = 1.0f / sqrtf(2.0f); const uint32_t NUM_BITS_PER_COMPONENT = 15; const uint32_t RANGE = (1 << NUM_BITS_PER_COMPONENT) - 1; From b48134e30cefb6d9fa00ae7bddfbd32bcbc68919 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 11:40:45 -0700 Subject: [PATCH 11/59] WIP commit testing for joint mapping transmission --- interface/src/avatar/Avatar.cpp | 4 -- interface/src/avatar/Avatar.h | 2 - libraries/avatars/src/AvatarData.cpp | 67 ++++++++++++++++++++++------ libraries/avatars/src/AvatarData.h | 1 + 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9ae636af36..820a0491d1 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -543,10 +543,6 @@ void Avatar::simulateAttachments(float deltaTime) { } } -void Avatar::updateJointMappings() { - // no-op; joint mappings come from skeleton model -} - float Avatar::getBoundingRadius() const { return getBounds().getLargestDimension() / 2.0f; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 2580ac1d37..288fc9d781 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -235,8 +235,6 @@ protected: virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual void fixupModelsInScene(); - virtual void updateJointMappings() override; - virtual void updatePalms(); render::ItemID _renderItemID{ render::Item::INVALID_ITEM_ID }; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 251d83c19b..4b7e5cfb3c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -602,8 +602,19 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f); } // 1 byte + // joint rotations int numJoints = *sourceBuffer++; + + + // do not process any jointData until we've received a valid jointIndices hash from + // an earlier AvatarIdentity packet. Because if we do, we risk applying the joint data + // the wrong bones, resulting in a twisted avatar, An un-animated avatar is preferable to this. + bool skipJoints = false; + if (_networkJointIndexMap.empty()) { + skipJoints = true; + } + int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); minPossibleSize += bytesOfValidity; if (minPossibleSize > maxAvailableSize) { @@ -654,9 +665,13 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { for (int i = 0; i < numJoints; i++) { JointData& data = _jointData[i]; if (validRotations[i]) { - _hasNewJointRotations = true; - data.rotationSet = true; - sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); + if (skipJoints) { + sourceBuffer += COMPRESSED_QUATERNION_SIZE; + } else { + sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); + _hasNewJointRotations = true; + data.rotationSet = true; + } } } } // numJoints * 6 bytes @@ -684,7 +699,8 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } // 1 + bytesOfValidity bytes // each joint translation component is stored in 6 bytes. 1 byte for translationCompressionRadix - minPossibleSize += numValidJointTranslations * 6 + 1; + const size_t COMPRESSED_TRANSLATION_SIZE = 6; + minPossibleSize += numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE + 1; if (minPossibleSize > maxAvailableSize) { if (shouldLogError(now)) { qCDebug(avatars) << "Malformed AvatarData packet after JointData translation validity;" @@ -701,10 +717,13 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { for (int i = 0; i < numJoints; i++) { JointData& data = _jointData[i]; if (validTranslations[i]) { - sourceBuffer += - unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, translationCompressionRadix); - _hasNewJointTranslations = true; - data.translationSet = true; + if (skipJoints) { + sourceBuffer += COMPRESSED_TRANSLATION_SIZE; + } else { + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, translationCompressionRadix); + _hasNewJointTranslations = true; + data.translationSet = true; + } } } } // numJoints * 12 bytes @@ -966,14 +985,25 @@ bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray& data) { QDataStream packetStream(data); QUuid avatarUUID; - QUrl unusedModelURL; // legacy faceModel support QUrl skeletonModelURL; QVector attachmentData; QString displayName; - packetStream >> avatarUUID >> unusedModelURL >> skeletonModelURL >> attachmentData >> displayName; - + QHash networkJointIndices; + packetStream >> avatarUUID >> skeletonModelURL >> attachmentData >> displayName >> networkJointIndices; bool hasIdentityChanged = false; + if (!_jointIndices.empty() && _networkJointIndexMap.empty() && !networkJointIndices.empty()) { + // build networkJointIndexMap from _jointIndices and networkJointIndices. + _networkJointIndexMap.fill(networkJointIndices.size(), -1); + for (auto iter = networkJointIndices.cbegin(); iter != networkJointIndices.end(); ++iter) { + int jointIndex = getJointIndex(iter.key()); + _networkJointIndexMap[iter.value()] = jointIndex; + } + } + + // AJT: just got a new networkJointIndicesMap. + qCDebug(avatars) << "AJT: receiving networkJointIndices.size = " << networkJointIndices.size(); + if (_firstSkeletonCheck || (skeletonModelURL != _skeletonModelURL)) { setSkeletonModelURL(skeletonModelURL); hasIdentityChanged = true; @@ -999,9 +1029,10 @@ QByteArray AvatarData::identityByteArray() { QUrl emptyURL(""); const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL; - QUrl unusedModelURL; // legacy faceModel support + // AJT: just got a sending networkJointIndices + qCDebug(avatars) << "AJT: sending _jointIndices.size = " << _jointIndices.size(); - identityStream << QUuid() << unusedModelURL << urlToSend << _attachmentData << _displayName; + identityStream << QUuid() << urlToSend << _attachmentData << _displayName << _jointIndices; return identityData; } @@ -1106,6 +1137,8 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { void AvatarData::setJointMappingsFromNetworkReply() { QNetworkReply* networkReply = static_cast(sender()); + qCDebug(avatars) << "AJT: GOT HERE! finished fst network request"; + QByteArray line; while (!(line = networkReply->readLine()).isEmpty()) { line = line.trimmed(); @@ -1140,6 +1173,11 @@ void AvatarData::setJointMappingsFromNetworkReply() { _jointIndices.insert(_jointNames.at(i), i + 1); } + // now that we have the jointIndices send them to the AvatarMixer. + sendIdentityPacket(); + + qCDebug(avatars) << "AJT: _jointIndices.size = " << _jointIndices.size(); + networkReply->deleteLater(); } @@ -1180,6 +1218,9 @@ void AvatarData::sendIdentityPacket() { void AvatarData::updateJointMappings() { _jointIndices.clear(); _jointNames.clear(); + _networkJointIndexMap.clear(); + + qCDebug(avatars) << "AJT: GOT HERE! kicking off fst network request"; if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a7b97ef4c0..43bc682bda 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -366,6 +366,7 @@ protected: float _displayNameAlpha; QHash _jointIndices; ///< 1-based, since zero is returned for missing keys + QVector _networkJointIndexMap; // maps network joint indices to local model joint indices. QStringList _jointNames; ///< in order of depth-first traversal quint64 _errorLogExpiry; ///< time in future when to log an error From c48fce4f5ab1cebf53e191d40dbd9b41d218faf4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 15:24:10 -0700 Subject: [PATCH 12/59] WIP commit, socket errors when AvatarIdentity is larger then MTU --- assignment-client/src/avatars/AvatarMixer.cpp | 4 +- libraries/avatars/src/AvatarData.cpp | 48 ++++++++++------- libraries/avatars/src/AvatarData.h | 14 ++++- libraries/avatars/src/AvatarHashMap.cpp | 52 ++++++------------- 4 files changed, 60 insertions(+), 58 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index cc94e4f1b7..46599396ca 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -417,7 +417,9 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes AvatarData& avatar = nodeData->getAvatar(); // parse the identity packet and update the change timestamp if appropriate - if (avatar.hasIdentityChangedAfterParsing(message->getMessage())) { + AvatarData::Identity identity; + AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity); + if (avatar.processAvatarIdentity(identity)) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->flagIdentityChange(); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4b7e5cfb3c..abf3f52ed6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -612,7 +612,8 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { // the wrong bones, resulting in a twisted avatar, An un-animated avatar is preferable to this. bool skipJoints = false; if (_networkJointIndexMap.empty()) { - skipJoints = true; + qCDebug(avatars) << "AJT: parseAvatarDataPacket _networkJointIndexMap.size = " << _networkJointIndexMap.size(); + skipJoints = false; } int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); @@ -726,7 +727,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } } } - } // numJoints * 12 bytes + } // numJoints * 6 bytes #ifdef WANT_DEBUG if (numValidJointRotations > 15) { @@ -981,42 +982,45 @@ void AvatarData::clearJointsData() { } } -bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray& data) { +void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) { QDataStream packetStream(data); + packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.jointIndices; + + // AJT: just got a new networkJointIndicesMap. + qCDebug(avatars) << "AJT: receiving identity.jointIndices.size = " << identityOut.jointIndices.size(); +} + +bool AvatarData::processAvatarIdentity(const Identity& identity) { - QUuid avatarUUID; - QUrl skeletonModelURL; - QVector attachmentData; - QString displayName; - QHash networkJointIndices; - packetStream >> avatarUUID >> skeletonModelURL >> attachmentData >> displayName >> networkJointIndices; bool hasIdentityChanged = false; - if (!_jointIndices.empty() && _networkJointIndexMap.empty() && !networkJointIndices.empty()) { + qCDebug(avatars) << "AJT: processAvatarIdentity got here!"; + + if (!_jointIndices.empty() && _networkJointIndexMap.empty() && !identity.jointIndices.empty()) { // build networkJointIndexMap from _jointIndices and networkJointIndices. - _networkJointIndexMap.fill(networkJointIndices.size(), -1); - for (auto iter = networkJointIndices.cbegin(); iter != networkJointIndices.end(); ++iter) { + _networkJointIndexMap.fill(identity.jointIndices.size(), -1); + for (auto iter = identity.jointIndices.cbegin(); iter != identity.jointIndices.end(); ++iter) { int jointIndex = getJointIndex(iter.key()); _networkJointIndexMap[iter.value()] = jointIndex; + qCDebug(avatars) << "AJT: mapping " << iter.value() << " -> " << jointIndex; } } - // AJT: just got a new networkJointIndicesMap. - qCDebug(avatars) << "AJT: receiving networkJointIndices.size = " << networkJointIndices.size(); + qCDebug(avatars) << "AJT: processAvatarIdentity got here!"; - if (_firstSkeletonCheck || (skeletonModelURL != _skeletonModelURL)) { - setSkeletonModelURL(skeletonModelURL); + if (_firstSkeletonCheck || (identity.skeletonModelURL != _skeletonModelURL)) { + setSkeletonModelURL(identity.skeletonModelURL); hasIdentityChanged = true; _firstSkeletonCheck = false; } - if (displayName != _displayName) { - setDisplayName(displayName); + if (identity.displayName != _displayName) { + setDisplayName(identity.displayName); hasIdentityChanged = true; } - if (attachmentData != _attachmentData) { - setAttachmentData(attachmentData); + if (identity.attachmentData != _attachmentData) { + setAttachmentData(identity.attachmentData); hasIdentityChanged = true; } @@ -1204,6 +1208,8 @@ void AvatarData::sendIdentityPacket() { QByteArray identityData = identityByteArray(); + qCDebug(avatars) << "AJT: sendIdentityPacket() size = " << identityData.size(); + auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); packetList->write(identityData); nodeList->eachMatchingNode( @@ -1213,6 +1219,8 @@ void AvatarData::sendIdentityPacket() { [&](const SharedNodePointer& node) { nodeList->sendPacketList(std::move(packetList), *node); }); + + qCDebug(avatars) << "AJT: sendIdentityPacket() done!"; } void AvatarData::updateJointMappings() { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 43bc682bda..feabfad544 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -280,7 +280,19 @@ public: const HeadData* getHeadData() const { return _headData; } - bool hasIdentityChangedAfterParsing(const QByteArray& data); + struct Identity { + QUuid uuid; + QUrl skeletonModelURL; + QVector attachmentData; + QString displayName; + QHash jointIndices; + }; + + static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut); + + // returns true if identity has changed, false otherwise. + bool processAvatarIdentity(const Identity& identity); + QByteArray identityByteArray(); const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index f14e2b0ad3..1b1cb14e41 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -50,26 +50,26 @@ AvatarSharedPointer AvatarHashMap::newSharedAvatar() { AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { qCDebug(avatars) << "Adding avatar with sessionUUID " << sessionUUID << "to AvatarHashMap."; - + auto avatar = newSharedAvatar(); avatar->setSessionUUID(sessionUUID); avatar->setOwningAvatarMixer(mixerWeakPointer); - + _avatarHash.insert(sessionUUID, avatar); emit avatarAddedEvent(sessionUUID); - + return avatar; } AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { QWriteLocker locker(&_hashLock); - + auto avatar = _avatarHash.value(sessionUUID); - + if (!avatar) { avatar = addAvatar(sessionUUID, mixerWeakPointer); } - + return avatar; } @@ -86,14 +86,14 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer mess // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (message->getBytesLeftToRead()) { QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - + int positionBeforeRead = message->getPosition(); QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); - + if (sessionUUID != _lastOwnerSessionUUID) { auto avatar = newOrExistingAvatar(sessionUUID, sendingNode); - + // have the matching (or new) avatar parse the data from the packet int bytesRead = avatar->parseDataFromBuffer(byteArray); message->seek(positionBeforeRead + bytesRead); @@ -107,33 +107,13 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer mess } void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode) { - // setup a data stream to parse the packet - QDataStream identityStream(message->getMessage()); + AvatarData::Identity identity; + AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity); - QUuid sessionUUID; - - while (!identityStream.atEnd()) { + // mesh URL for a UUID, find avatar in our list + auto avatar = newOrExistingAvatar(identity.uuid, sendingNode); - QUrl faceMeshURL, skeletonURL; - QVector attachmentData; - QString displayName; - identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> attachmentData >> displayName; - - // mesh URL for a UUID, find avatar in our list - auto avatar = newOrExistingAvatar(sessionUUID, sendingNode); - - if (avatar->getSkeletonModelURL().isEmpty() || (avatar->getSkeletonModelURL() != skeletonURL)) { - avatar->setSkeletonModelURL(skeletonURL); // Will expand "" to default and so will not continuously fire - } - - if (avatar->getAttachmentData() != attachmentData) { - avatar->setAttachmentData(attachmentData); - } - - if (avatar->getDisplayName() != displayName) { - avatar->setDisplayName(displayName); - } - } + avatar->processAvatarIdentity(identity); } void AvatarHashMap::processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode) { @@ -144,9 +124,9 @@ void AvatarHashMap::processKillAvatar(QSharedPointer message, S void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) { QWriteLocker locker(&_hashLock); - + auto removedAvatar = _avatarHash.take(sessionUUID); - + if (removedAvatar) { handleRemovedAvatar(removedAvatar); } From 135fa8c2aaa6fb8987d7fe5eda9b16518ecb8ec0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 15:41:21 -0700 Subject: [PATCH 13/59] Moved jointIndices transmission behind #ifdef --- libraries/avatars/src/AvatarData.cpp | 40 ++++++++++++---------------- libraries/avatars/src/AvatarData.h | 4 +++ 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index abf3f52ed6..09ea34a5c4 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -611,10 +611,11 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { // an earlier AvatarIdentity packet. Because if we do, we risk applying the joint data // the wrong bones, resulting in a twisted avatar, An un-animated avatar is preferable to this. bool skipJoints = false; +#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET if (_networkJointIndexMap.empty()) { - qCDebug(avatars) << "AJT: parseAvatarDataPacket _networkJointIndexMap.size = " << _networkJointIndexMap.size(); - skipJoints = false; + skipJoints = true; } +#endif int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); minPossibleSize += bytesOfValidity; @@ -984,29 +985,28 @@ void AvatarData::clearJointsData() { void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) { QDataStream packetStream(data); - packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.jointIndices; - // AJT: just got a new networkJointIndicesMap. - qCDebug(avatars) << "AJT: receiving identity.jointIndices.size = " << identityOut.jointIndices.size(); +#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET + packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.jointIndices; +#else + packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName; +#endif } bool AvatarData::processAvatarIdentity(const Identity& identity) { bool hasIdentityChanged = false; - qCDebug(avatars) << "AJT: processAvatarIdentity got here!"; - + #ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET if (!_jointIndices.empty() && _networkJointIndexMap.empty() && !identity.jointIndices.empty()) { // build networkJointIndexMap from _jointIndices and networkJointIndices. _networkJointIndexMap.fill(identity.jointIndices.size(), -1); for (auto iter = identity.jointIndices.cbegin(); iter != identity.jointIndices.end(); ++iter) { int jointIndex = getJointIndex(iter.key()); _networkJointIndexMap[iter.value()] = jointIndex; - qCDebug(avatars) << "AJT: mapping " << iter.value() << " -> " << jointIndex; } } - - qCDebug(avatars) << "AJT: processAvatarIdentity got here!"; +#endif if (_firstSkeletonCheck || (identity.skeletonModelURL != _skeletonModelURL)) { setSkeletonModelURL(identity.skeletonModelURL); @@ -1033,10 +1033,11 @@ QByteArray AvatarData::identityByteArray() { QUrl emptyURL(""); const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL; - // AJT: just got a sending networkJointIndices - qCDebug(avatars) << "AJT: sending _jointIndices.size = " << _jointIndices.size(); - +#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET identityStream << QUuid() << urlToSend << _attachmentData << _displayName << _jointIndices; +#else + identityStream << QUuid() << urlToSend << _attachmentData << _displayName; +#endif return identityData; } @@ -1141,8 +1142,6 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { void AvatarData::setJointMappingsFromNetworkReply() { QNetworkReply* networkReply = static_cast(sender()); - qCDebug(avatars) << "AJT: GOT HERE! finished fst network request"; - QByteArray line; while (!(line = networkReply->readLine()).isEmpty()) { line = line.trimmed(); @@ -1180,8 +1179,6 @@ void AvatarData::setJointMappingsFromNetworkReply() { // now that we have the jointIndices send them to the AvatarMixer. sendIdentityPacket(); - qCDebug(avatars) << "AJT: _jointIndices.size = " << _jointIndices.size(); - networkReply->deleteLater(); } @@ -1208,8 +1205,6 @@ void AvatarData::sendIdentityPacket() { QByteArray identityData = identityByteArray(); - qCDebug(avatars) << "AJT: sendIdentityPacket() size = " << identityData.size(); - auto packetList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); packetList->write(identityData); nodeList->eachMatchingNode( @@ -1219,16 +1214,15 @@ void AvatarData::sendIdentityPacket() { [&](const SharedNodePointer& node) { nodeList->sendPacketList(std::move(packetList), *node); }); - - qCDebug(avatars) << "AJT: sendIdentityPacket() done!"; } void AvatarData::updateJointMappings() { _jointIndices.clear(); _jointNames.clear(); - _networkJointIndexMap.clear(); - qCDebug(avatars) << "AJT: GOT HERE! kicking off fst network request"; +#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET + _networkJointIndexMap.clear(); +#endif if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index feabfad544..5af66fae4e 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -285,7 +285,9 @@ public: QUrl skeletonModelURL; QVector attachmentData; QString displayName; +#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET QHash jointIndices; +#endif }; static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut); @@ -378,7 +380,9 @@ protected: float _displayNameAlpha; QHash _jointIndices; ///< 1-based, since zero is returned for missing keys +#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET QVector _networkJointIndexMap; // maps network joint indices to local model joint indices. +#endif QStringList _jointNames; ///< in order of depth-first traversal quint64 _errorLogExpiry; ///< time in future when to log an error From e792e8eecfcf7e4565090720fd332c55d285f222 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 16:05:16 -0700 Subject: [PATCH 14/59] Fix for identity packet pong --- libraries/avatars/src/AvatarData.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 09ea34a5c4..e5fe31217f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -606,7 +606,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { // joint rotations int numJoints = *sourceBuffer++; - // do not process any jointData until we've received a valid jointIndices hash from // an earlier AvatarIdentity packet. Because if we do, we risk applying the joint data // the wrong bones, resulting in a twisted avatar, An un-animated avatar is preferable to this. @@ -1034,22 +1033,21 @@ QByteArray AvatarData::identityByteArray() { const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL; #ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - identityStream << QUuid() << urlToSend << _attachmentData << _displayName << _jointIndices; + identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _jointIndices; #else - identityStream << QUuid() << urlToSend << _attachmentData << _displayName; + identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName; #endif return identityData; } - void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { const QUrl& expanded = skeletonModelURL.isEmpty() ? AvatarData::defaultFullAvatarModelUrl() : skeletonModelURL; if (expanded == _skeletonModelURL) { return; } _skeletonModelURL = expanded; - qCDebug(avatars) << "Changing skeleton model for avatar to" << _skeletonModelURL.toString(); + qCDebug(avatars) << "Changing skeleton model for avatar" << getSessionUUID() << "to" << _skeletonModelURL.toString(); updateJointMappings(); } From eb80990c1096247c8dd191e7dcd5e7e798ebeaa8 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 16:08:56 -0700 Subject: [PATCH 15/59] Another fix for avatarIdentity pong --- libraries/avatars/src/AvatarData.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e5fe31217f..f956305c3f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1174,9 +1174,6 @@ void AvatarData::setJointMappingsFromNetworkReply() { _jointIndices.insert(_jointNames.at(i), i + 1); } - // now that we have the jointIndices send them to the AvatarMixer. - sendIdentityPacket(); - networkReply->deleteLater(); } From 0294066668af90f684cffe1bf852b238a8549e1e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 16:41:50 -0700 Subject: [PATCH 16/59] Removed pupilData and translationRadix from AvatarData packet. --- interface/src/avatar/MyAvatar.cpp | 4 ---- interface/src/ui/PreferencesDialog.cpp | 5 ----- libraries/avatars/src/AvatarData.cpp | 28 +++++++------------------- libraries/avatars/src/HeadData.cpp | 6 ++---- libraries/avatars/src/HeadData.h | 22 +++++++++----------- 5 files changed, 18 insertions(+), 47 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ddc0407f14..6d1d80b7f6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -670,8 +670,6 @@ void MyAvatar::saveData() { settings.setValue("headPitch", getHead()->getBasePitch()); - settings.setValue("pupilDilation", getHead()->getPupilDilation()); - settings.setValue("leanScale", _leanScale); settings.setValue("scale", _targetScale); @@ -778,8 +776,6 @@ void MyAvatar::loadData() { getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f)); - getHead()->setPupilDilation(loadSetting(settings, "pupilDilation", 0.0f)); - _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); setScale(glm::vec3(_targetScale)); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 9b1146340e..cb68b36c24 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -144,11 +144,6 @@ void setupPreferences() { preference->setStep(1); preferences->addPreference(preference); } - { - auto getter = [=]()->float { return myAvatar->getHead()->getPupilDilation(); }; - auto setter = [=](float value) { myAvatar->getHead()->setPupilDilation(value); }; - preferences->addPreference(new SliderPreference(AVATAR_TUNING, "Pupil dilation", getter, setter)); - } { auto getter = []()->float { return DependencyManager::get()->getEyeClosingThreshold(); }; auto setter = [](float value) { DependencyManager::get()->setEyeClosingThreshold(value); }; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f956305c3f..9d010e3dc4 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -219,9 +219,6 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); } - // pupil dilation - destinationBuffer += packFloatToByte(destinationBuffer, _headData->_pupilDilation, 1.0f); - // joint rotation data *destinationBuffer++ = _jointData.size(); unsigned char* validityPosition = destinationBuffer; @@ -306,15 +303,11 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { } } - if (validityBit != 0) { *destinationBuffer++ = validity; } - // TODO -- automatically pick translationCompressionRadix - int translationCompressionRadix = 12; - - *destinationBuffer++ = translationCompressionRadix; + const int TRANSLATION_COMPRESSION_RADIX = 12; validityBit = 0; validity = *validityPosition++; @@ -322,7 +315,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { const JointData& data = _jointData[ i ]; if (validity & (1 << validityBit)) { destinationBuffer += - packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, translationCompressionRadix); + packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); } if (++validityBit == BITS_IN_BYTE) { validityBit = 0; @@ -335,7 +328,6 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { qDebug() << "AvatarData::toByteArray" << cullSmallChanges << sendAll << "rotations:" << rotationSentCount << "translations:" << translationSentCount << "largest:" << maxTranslationDimension - << "radix:" << translationCompressionRadix << "size:" << (beforeRotations - startPosition) << "+" << (beforeTranslations - beforeRotations) << "+" @@ -408,7 +400,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { // audioLoudness = 4 // } // + 1 byte for varying data - // + 1 byte for pupilSize // + 1 byte for numJoints (0) // = 39 bytes int minPossibleSize = 39; @@ -598,11 +589,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } } // 1 + bitItemsDataSize bytes - { // pupil dilation - sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f); - } // 1 byte - - // joint rotations int numJoints = *sourceBuffer++; @@ -650,6 +636,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } // 1 + bytesOfValidity bytes // each joint rotation is stored in 6 bytes. + const size_t COMPRESSED_QUATERNION_SIZE = 6; minPossibleSize += numValidJointRotations * COMPRESSED_QUATERNION_SIZE; if (minPossibleSize > maxAvailableSize) { @@ -699,9 +686,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } } // 1 + bytesOfValidity bytes - // each joint translation component is stored in 6 bytes. 1 byte for translationCompressionRadix + // each joint translation component is stored in 6 bytes. const size_t COMPRESSED_TRANSLATION_SIZE = 6; - minPossibleSize += numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE + 1; + minPossibleSize += numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE; if (minPossibleSize > maxAvailableSize) { if (shouldLogError(now)) { qCDebug(avatars) << "Malformed AvatarData packet after JointData translation validity;" @@ -712,7 +699,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { return maxAvailableSize; } - int translationCompressionRadix = *sourceBuffer++; + const int TRANSLATION_COMPRESSION_RADIX = 12; { // joint data for (int i = 0; i < numJoints; i++) { @@ -721,7 +708,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { if (skipJoints) { sourceBuffer += COMPRESSED_TRANSLATION_SIZE; } else { - sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, translationCompressionRadix); + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); _hasNewJointTranslations = true; data.translationSet = true; } @@ -733,7 +720,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { if (numValidJointRotations > 15) { qDebug() << "RECEIVING -- rotations:" << numValidJointRotations << "translations:" << numValidJointTranslations - << "radix:" << translationCompressionRadix << "size:" << (int)(sourceBuffer - startPosition); } #endif diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index b98112d6e0..1aee85b2cd 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -43,10 +43,9 @@ HeadData::HeadData(AvatarData* owningAvatar) : _averageLoudness(0.0f), _browAudioLift(0.0f), _audioAverageLoudness(0.0f), - _pupilDilation(0.0f), _owningAvatar(owningAvatar) { - + } glm::quat HeadData::getRawOrientation() const { @@ -72,7 +71,7 @@ void HeadData::setOrientation(const glm::quat& orientation) { glm::vec3 newFront = glm::inverse(bodyOrientation) * (orientation * IDENTITY_FRONT); bodyOrientation = bodyOrientation * glm::angleAxis(atan2f(-newFront.x, -newFront.z), glm::vec3(0.0f, 1.0f, 0.0f)); _owningAvatar->setOrientation(bodyOrientation); - + // the rest goes to the head glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation)); _basePitch = eulers.x; @@ -186,4 +185,3 @@ void HeadData::fromJson(const QJsonObject& json) { } } } - diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index fef77c6f8f..535aa12847 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -34,7 +34,7 @@ class HeadData { public: explicit HeadData(AvatarData* owningAvatar); virtual ~HeadData() { }; - + // degrees float getBaseYaw() const { return _baseYaw; } void setBaseYaw(float yaw) { _baseYaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); } @@ -42,7 +42,7 @@ public: void setBasePitch(float pitch) { _basePitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } float getBaseRoll() const { return _baseRoll; } void setBaseRoll(float roll) { _baseRoll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } - + virtual void setFinalYaw(float finalYaw) { _baseYaw = finalYaw; } virtual void setFinalPitch(float finalPitch) { _basePitch = finalPitch; } virtual void setFinalRoll(float finalRoll) { _baseRoll = finalRoll; } @@ -64,26 +64,23 @@ public: void setBlendshape(QString name, float val); const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } void setBlendshapeCoefficients(const QVector& blendshapeCoefficients) { _blendshapeCoefficients = blendshapeCoefficients; } - - float getPupilDilation() const { return _pupilDilation; } - void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } - + const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } - - + + float getLeanSideways() const { return _leanSideways; } float getLeanForward() const { return _leanForward; } float getTorsoTwist() const { return _torsoTwist; } virtual float getFinalLeanSideways() const { return _leanSideways; } virtual float getFinalLeanForward() const { return _leanForward; } - + void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } void setLeanForward(float leanForward) { _leanForward = leanForward; } void setTorsoTwist(float torsoTwist) { _torsoTwist = torsoTwist; } - + friend class AvatarData; - + QJsonObject toJson() const; void fromJson(const QJsonObject& json); @@ -106,9 +103,8 @@ protected: float _browAudioLift; float _audioAverageLoudness; QVector _blendshapeCoefficients; - float _pupilDilation; AvatarData* _owningAvatar; - + private: // privatize copy ctor and assignment operator so copies of this object cannot be made HeadData(const HeadData&); From de1204c42d9bff5b4496da56595901fbbe62a5d3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 May 2016 18:19:28 -0700 Subject: [PATCH 17/59] Enable transmission of jointIndices --- libraries/avatars/src/AvatarData.cpp | 10 +++++++--- libraries/avatars/src/AvatarData.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9d010e3dc4..b70c021f61 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -37,7 +37,7 @@ #include "AvatarLogging.h" -#define WANT_DEBUG +//#define WANT_DEBUG quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND; @@ -984,11 +984,15 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) { #ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET if (!_jointIndices.empty() && _networkJointIndexMap.empty() && !identity.jointIndices.empty()) { + // build networkJointIndexMap from _jointIndices and networkJointIndices. - _networkJointIndexMap.fill(identity.jointIndices.size(), -1); + _networkJointIndexMap.fill(-1, identity.jointIndices.size()); for (auto iter = identity.jointIndices.cbegin(); iter != identity.jointIndices.end(); ++iter) { int jointIndex = getJointIndex(iter.key()); - _networkJointIndexMap[iter.value()] = jointIndex; + int networkJointIndex = iter.value(); + if (networkJointIndex >= 0 && networkJointIndex < identity.jointIndices.size()) { + _networkJointIndexMap[networkJointIndex - 1] = jointIndex; + } } } #endif diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5af66fae4e..1a1a07410d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -128,6 +128,8 @@ enum KeyState { DELETE_KEY_DOWN }; +#define TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET + class QDataStream; class AttachmentData; From 4e862941cb9307ebbcfb88c1a14e463c62a854c4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 May 2016 14:51:56 -0700 Subject: [PATCH 18/59] fix a race when restarting scripts -- avoid the old not-yet-stopped script from being considered the restart script --- libraries/script-engine/src/ScriptEngine.h | 3 +++ libraries/script-engine/src/ScriptEngines.cpp | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 80978e4527..b576e2a37f 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -146,6 +146,8 @@ public: bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget bool isRunning() const { return _isRunning; } // used by ScriptWidget + bool isStopping() const { return _isStopping; } + void flagAsStopping() { _isStopping = true; } bool isDebuggable() const { return _debuggable; } @@ -189,6 +191,7 @@ protected: QString _parentURL; std::atomic _isFinished { false }; std::atomic _isRunning { false }; + std::atomic _isStopping { false }; int _evaluatesPending { 0 }; bool _isInitialized { false }; QHash _timerFunctionMap; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 70eb055d22..5a2beb901d 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -351,6 +351,7 @@ void ScriptEngines::stopAllScripts(bool restart) { reloadScript(scriptName); }); } + it.value()->flagAsStopping(); QMetaObject::invokeMethod(it.value(), "stop"); //it.value()->stop(); qCDebug(scriptengine) << "stopping script..." << it.key(); @@ -369,6 +370,7 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { if (_scriptEnginesHash.contains(scriptURL)) { ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL]; if (restart) { + scriptEngine->flagAsStopping(); auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(scriptURL); connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { @@ -454,7 +456,7 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { QReadLocker lock(&_scriptEnginesHashLock); const QUrl scriptURL = normalizeScriptURL(rawScriptURL); auto it = _scriptEnginesHash.find(scriptURL); - if (it != _scriptEnginesHash.end()) { + if (it != _scriptEnginesHash.end() && !it.value()->isStopping()) { result = it.value(); } } From 9ad488ba7b1d1ce3709fbbba79ad8a2ef5e04821 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 May 2016 16:08:44 -0700 Subject: [PATCH 19/59] fix method name to match coding standard --- libraries/script-engine/src/ScriptEngine.h | 2 +- libraries/script-engine/src/ScriptEngines.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index b576e2a37f..512e79fb95 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -147,7 +147,7 @@ public: bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget bool isRunning() const { return _isRunning; } // used by ScriptWidget bool isStopping() const { return _isStopping; } - void flagAsStopping() { _isStopping = true; } + void setIsStopping() { _isStopping = true; } bool isDebuggable() const { return _debuggable; } diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 5a2beb901d..65e08938b3 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -351,7 +351,7 @@ void ScriptEngines::stopAllScripts(bool restart) { reloadScript(scriptName); }); } - it.value()->flagAsStopping(); + it.value()->setIsStopping(); QMetaObject::invokeMethod(it.value(), "stop"); //it.value()->stop(); qCDebug(scriptengine) << "stopping script..." << it.key(); @@ -370,7 +370,7 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { if (_scriptEnginesHash.contains(scriptURL)) { ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL]; if (restart) { - scriptEngine->flagAsStopping(); + scriptEngine->setIsStopping(); auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(scriptURL); connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { From 3f5ed4bef8603eae9bb4a08e9912953057244c1d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 19 May 2016 16:15:33 -0700 Subject: [PATCH 20/59] set isStopping on other calls to stop --- libraries/script-engine/src/ScriptEngines.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 65e08938b3..8b57487db0 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -160,6 +160,7 @@ void ScriptEngines::shutdownScripting() { scriptEngine->disconnect(this); // Gracefully stop the engine's scripting thread + scriptEngine->setIsStopping(); scriptEngine->stop(); // We need to wait for the engine to be done running before we proceed, because we don't @@ -353,7 +354,6 @@ void ScriptEngines::stopAllScripts(bool restart) { } it.value()->setIsStopping(); QMetaObject::invokeMethod(it.value(), "stop"); - //it.value()->stop(); qCDebug(scriptengine) << "stopping script..." << it.key(); } } @@ -370,13 +370,13 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { if (_scriptEnginesHash.contains(scriptURL)) { ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL]; if (restart) { - scriptEngine->setIsStopping(); auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(scriptURL); connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) { reloadScript(scriptName); }); } + scriptEngine->setIsStopping(); scriptEngine->stop(); stoppedScript = true; qCDebug(scriptengine) << "stopping script..." << scriptURL; From 13a057513a3e04c0659904f947834524bbba91e0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 19 May 2016 16:46:17 -0700 Subject: [PATCH 21/59] Removed jointIndices transmission experiment --- libraries/avatars/src/AvatarData.cpp | 58 +++------------------------- libraries/avatars/src/AvatarData.h | 8 ---- 2 files changed, 6 insertions(+), 60 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b70c021f61..ab7647b9fc 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -592,16 +592,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { // joint rotations int numJoints = *sourceBuffer++; - // do not process any jointData until we've received a valid jointIndices hash from - // an earlier AvatarIdentity packet. Because if we do, we risk applying the joint data - // the wrong bones, resulting in a twisted avatar, An un-animated avatar is preferable to this. - bool skipJoints = false; -#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - if (_networkJointIndexMap.empty()) { - skipJoints = true; - } -#endif - int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); minPossibleSize += bytesOfValidity; if (minPossibleSize > maxAvailableSize) { @@ -653,13 +643,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { for (int i = 0; i < numJoints; i++) { JointData& data = _jointData[i]; if (validRotations[i]) { - if (skipJoints) { - sourceBuffer += COMPRESSED_QUATERNION_SIZE; - } else { - sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); - _hasNewJointRotations = true; - data.rotationSet = true; - } + sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); + _hasNewJointRotations = true; + data.rotationSet = true; } } } // numJoints * 6 bytes @@ -705,13 +691,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { for (int i = 0; i < numJoints; i++) { JointData& data = _jointData[i]; if (validTranslations[i]) { - if (skipJoints) { - sourceBuffer += COMPRESSED_TRANSLATION_SIZE; - } else { - sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); - _hasNewJointTranslations = true; - data.translationSet = true; - } + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); + _hasNewJointTranslations = true; + data.translationSet = true; } } } // numJoints * 6 bytes @@ -971,32 +953,13 @@ void AvatarData::clearJointsData() { void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) { QDataStream packetStream(data); -#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName >> identityOut.jointIndices; -#else packetStream >> identityOut.uuid >> identityOut.skeletonModelURL >> identityOut.attachmentData >> identityOut.displayName; -#endif } bool AvatarData::processAvatarIdentity(const Identity& identity) { bool hasIdentityChanged = false; - #ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - if (!_jointIndices.empty() && _networkJointIndexMap.empty() && !identity.jointIndices.empty()) { - - // build networkJointIndexMap from _jointIndices and networkJointIndices. - _networkJointIndexMap.fill(-1, identity.jointIndices.size()); - for (auto iter = identity.jointIndices.cbegin(); iter != identity.jointIndices.end(); ++iter) { - int jointIndex = getJointIndex(iter.key()); - int networkJointIndex = iter.value(); - if (networkJointIndex >= 0 && networkJointIndex < identity.jointIndices.size()) { - _networkJointIndexMap[networkJointIndex - 1] = jointIndex; - } - } - } -#endif - if (_firstSkeletonCheck || (identity.skeletonModelURL != _skeletonModelURL)) { setSkeletonModelURL(identity.skeletonModelURL); hasIdentityChanged = true; @@ -1021,12 +984,7 @@ QByteArray AvatarData::identityByteArray() { QDataStream identityStream(&identityData, QIODevice::Append); QUrl emptyURL(""); const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL; - -#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _jointIndices; -#else identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName; -#endif return identityData; } @@ -1205,10 +1163,6 @@ void AvatarData::updateJointMappings() { _jointIndices.clear(); _jointNames.clear(); -#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - _networkJointIndexMap.clear(); -#endif - if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1a1a07410d..817d8aef09 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -128,8 +128,6 @@ enum KeyState { DELETE_KEY_DOWN }; -#define TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - class QDataStream; class AttachmentData; @@ -287,9 +285,6 @@ public: QUrl skeletonModelURL; QVector attachmentData; QString displayName; -#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - QHash jointIndices; -#endif }; static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut); @@ -382,9 +377,6 @@ protected: float _displayNameAlpha; QHash _jointIndices; ///< 1-based, since zero is returned for missing keys -#ifdef TRANSMIT_JOINT_INDICES_IN_IDENTITY_PACKET - QVector _networkJointIndexMap; // maps network joint indices to local model joint indices. -#endif QStringList _jointNames; ///< in order of depth-first traversal quint64 _errorLogExpiry; ///< time in future when to log an error From 6ecbdc6b9a5ec1e67701f00464d729403de11a80 Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 19 May 2016 20:03:05 -0400 Subject: [PATCH 22/59] Modify evalLightAttenuation to "fade" edges of lights. This provides a more attractive light falloff around the bounds of a light - removing harsh edges. This also adds a new parameter to evalLightAttenuation - the unnormalized light vector. --- libraries/model/src/model/Light.slh | 9 ++++++--- libraries/render-utils/src/point_light.slf | 4 ++-- libraries/render-utils/src/spot_light.slf | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 7cc4691d63..51c78b9a4d 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -98,10 +98,13 @@ float getLightShowContour(Light l) { return l._control.w; } -float evalLightAttenuation(Light l, float d) { - float radius = getLightRadius(l); +float evalLightAttenuation(Light l, float d, vec3 ulightvec) { + float radius = getLightSquareRadius(l); float denom = d / radius + 1.0; - float attenuation = min(1.0, 1.0 / (denom * denom)); + float attenuation = 1.0 / (denom * denom); + // "Fade" the edges of light sources to make things look a bit more attractive. + // Note: this tends to look a bit odd at lower exponents. + attenuation *= clamp(0, 1, mix(0, 1, getLightCutoffSquareRadius(l) - dot(ulightvec, ulightvec))); return attenuation; } diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index fc72f094e7..581aa8c250 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -66,8 +66,8 @@ void main(void) { vec3 fragEyeDir = normalize(fragEyeVector.xyz); vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); - // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance); + // Eval attenuation + float radialAttenuation = evalLightAttenuation(light, fragLightDistance, fragLightVec); // Final Lighting color vec3 fragColor = (shading.w * frag.diffuse + shading.xyz); diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 4191ba3f63..1cb6ebb878 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -74,7 +74,7 @@ void main(void) { vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance); + float radialAttenuation = evalLightAttenuation(light, fragLightDistance, fragLightVec); float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); // Final Lighting color From a54e8206faeb7c689bae0e3731ca90a58d3e298c Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 19 May 2016 20:10:49 -0400 Subject: [PATCH 23/59] Switch back to using the light's radius + spacing --- libraries/model/src/model/Light.slh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 51c78b9a4d..6211505090 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -99,12 +99,14 @@ float getLightShowContour(Light l) { } float evalLightAttenuation(Light l, float d, vec3 ulightvec) { - float radius = getLightSquareRadius(l); + float radius = getLightRadius(l); float denom = d / radius + 1.0; float attenuation = 1.0 / (denom * denom); + // "Fade" the edges of light sources to make things look a bit more attractive. // Note: this tends to look a bit odd at lower exponents. attenuation *= clamp(0, 1, mix(0, 1, getLightCutoffSquareRadius(l) - dot(ulightvec, ulightvec))); + return attenuation; } From 75532cda084c34c09b759eb120d00bfcc7d61ea5 Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 19 May 2016 20:52:28 -0400 Subject: [PATCH 24/59] Document evalLightAttenuation's parameters. --- libraries/model/src/model/Light.slh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 6211505090..46eb352d16 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -98,6 +98,9 @@ float getLightShowContour(Light l) { return l._control.w; } +// Light is the light source its self, d is the light's distance, and ulightvec is the unnormalized light vector. +// Note that ulightvec should be calculated as light position - fragment position. +// Additionally, length(light position) != dot(light position, light position). float evalLightAttenuation(Light l, float d, vec3 ulightvec) { float radius = getLightRadius(l); float denom = d / radius + 1.0; From b95ba8141c59723e525fbc600ac8abcfa8872ce3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 19 May 2016 20:24:44 -0700 Subject: [PATCH 25/59] AvatarData packet overhaul, uses a structure instead of raw memcpy --- libraries/avatars/src/AvatarData.cpp | 454 +++++++++++---------------- libraries/avatars/src/AvatarData.h | 2 + libraries/shared/src/Packed.h | 12 + 3 files changed, 199 insertions(+), 269 deletions(-) create mode 100644 libraries/shared/src/Packed.h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ab7647b9fc..4379a0d72c 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -48,6 +48,38 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f); const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData"; +namespace AvatarDataPacket { + + PACKED_BEGIN struct Header { + float position[3]; // skeletal model's position + float globalPosition[3]; // avatar's position + uint16_t localOrientation[3]; // avatar's local euler angles (degrees, compressed) relative to the thing it's attached to + uint16_t scale; // (compressed) 'ratio' encoding uses sign bit as flag. + float lookAtPosition[3]; // world space position that eyes are focusing on. + float audioLoudness; // current loundess of microphone + uint8_t flags; + } PACKED_END; + const size_t HEADER_SIZE = 49; + + PACKED_BEGIN struct ParentInfo { + uint8_t parentUUID[16]; // rfc 4122 encoded + uint16_t parentJointIndex; + } PACKED_END; + const size_t PARENT_INFO_SIZE = 18; + + PACKED_BEGIN struct FaceTrackerInfo { + float leftEyeBlink; + float rightEyeBlink; + float averageLoudness; + float browAudioLift; + uint8_t numBlendshapeCoefficients; + // float blendshapeCoefficients[numBlendshapeCoefficients]; + } PACKED_END; + const size_t FACE_TRACKER_INFO_SIZE = 17; +} + +#define ASSERT(COND) do { if (!(COND)) { int* bad = nullptr; *bad = 0xbad; } } while(0) + AvatarData::AvatarData() : SpatiallyNestable(NestableType::Avatar, QUuid()), _handPosition(0.0f), @@ -68,6 +100,10 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); + + ASSERT(sizeof AvatarDataPacket::Header == AvatarDataPacket::HEADER_SIZE); + ASSERT(sizeof AvatarDataPacket::ParentInfo == AvatarDataPacket::PARENT_INFO_SIZE); + ASSERT(sizeof AvatarDataPacket::FaceTrackerInfo == AvatarDataPacket::FACE_TRACKER_INFO_SIZE); } AvatarData::~AvatarData() { @@ -141,81 +177,67 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; - const glm::vec3& position = getLocalPosition(); - memcpy(destinationBuffer, &position, sizeof(position)); - destinationBuffer += sizeof(position); + auto header = reinterpret_cast(destinationBuffer); + header->position[0] = getLocalPosition().x; + header->position[1] = getLocalPosition().y; + header->position[2] = getLocalPosition().z; + header->globalPosition[0] = _globalPosition.x; + header->globalPosition[1] = _globalPosition.y; + header->globalPosition[2] = _globalPosition.z; - memcpy(destinationBuffer, &_globalPosition, sizeof(_globalPosition)); - destinationBuffer += sizeof(_globalPosition); - - // Body rotation glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation())); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.y); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.x); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.z); + packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 0), bodyEulerAngles.y); + packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 1), bodyEulerAngles.x); + packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 2), bodyEulerAngles.z); + packFloatRatioToTwoByte((uint8_t*)(&header->scale), _targetScale); + header->lookAtPosition[0] = _headData->_lookAtPosition.x; + header->lookAtPosition[1] = _headData->_lookAtPosition.y; + header->lookAtPosition[2] = _headData->_lookAtPosition.z; + header->audioLoudness = _headData->_audioLoudness; - // Body scale - destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); - - // Lookat Position - memcpy(destinationBuffer, &_headData->_lookAtPosition, sizeof(_headData->_lookAtPosition)); - destinationBuffer += sizeof(_headData->_lookAtPosition); - - // Instantaneous audio loudness (used to drive facial animation) - memcpy(destinationBuffer, &_headData->_audioLoudness, sizeof(float)); - destinationBuffer += sizeof(float); - - // bitMask of less than byte wide items - unsigned char bitItems = 0; - - // key state - setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState); + setSemiNibbleAt(header->flags, KEY_STATE_START_BIT, _keyState); // hand state bool isFingerPointing = _handState & IS_FINGER_POINTING_FLAG; - setSemiNibbleAt(bitItems, HAND_STATE_START_BIT, _handState & ~IS_FINGER_POINTING_FLAG); + setSemiNibbleAt(header->flags, HAND_STATE_START_BIT, _handState & ~IS_FINGER_POINTING_FLAG); if (isFingerPointing) { - setAtBit(bitItems, HAND_STATE_FINGER_POINTING_BIT); + setAtBit(header->flags, HAND_STATE_FINGER_POINTING_BIT); } // faceshift state if (_headData->_isFaceTrackerConnected) { - setAtBit(bitItems, IS_FACESHIFT_CONNECTED); + setAtBit(header->flags, IS_FACESHIFT_CONNECTED); } // eye tracker state if (_headData->_isEyeTrackerConnected) { - setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); + setAtBit(header->flags, IS_EYE_TRACKER_CONNECTED); } // referential state QUuid parentID = getParentID(); if (!parentID.isNull()) { - setAtBit(bitItems, HAS_REFERENTIAL); + setAtBit(header->flags, HAS_REFERENTIAL); } - *destinationBuffer++ = bitItems; + destinationBuffer += sizeof(AvatarDataPacket::Header); if (!parentID.isNull()) { + auto parentInfo = reinterpret_cast(destinationBuffer); QByteArray referentialAsBytes = parentID.toRfc4122(); - memcpy(destinationBuffer, referentialAsBytes.data(), referentialAsBytes.size()); - destinationBuffer += referentialAsBytes.size(); - memcpy(destinationBuffer, &_parentJointIndex, sizeof(_parentJointIndex)); - destinationBuffer += sizeof(_parentJointIndex); + memcpy(parentInfo->parentUUID, referentialAsBytes.data(), referentialAsBytes.size()); + parentInfo->parentJointIndex = _parentJointIndex; + destinationBuffer += sizeof(AvatarDataPacket::ParentInfo); } // If it is connected, pack up the data if (_headData->_isFaceTrackerConnected) { - memcpy(destinationBuffer, &_headData->_leftEyeBlink, sizeof(float)); - destinationBuffer += sizeof(float); + auto faceTrackerInfo = reinterpret_cast(destinationBuffer); - memcpy(destinationBuffer, &_headData->_rightEyeBlink, sizeof(float)); - destinationBuffer += sizeof(float); + faceTrackerInfo->leftEyeBlink = _headData->_leftEyeBlink; + faceTrackerInfo->rightEyeBlink = _headData->_rightEyeBlink; + faceTrackerInfo->averageLoudness = _headData->_averageLoudness; + faceTrackerInfo->browAudioLift = _headData->_browAudioLift; + faceTrackerInfo->numBlendshapeCoefficients = _headData->_blendshapeCoefficients.size(); + destinationBuffer += sizeof(AvatarDataPacket::FaceTrackerInfo); - memcpy(destinationBuffer, &_headData->_averageLoudness, sizeof(float)); - destinationBuffer += sizeof(float); - - memcpy(destinationBuffer, &_headData->_browAudioLift, sizeof(float)); - destinationBuffer += sizeof(float); - - *destinationBuffer++ = _headData->_blendshapeCoefficients.size(); - memcpy(destinationBuffer, _headData->_blendshapeCoefficients.data(), - _headData->_blendshapeCoefficients.size() * sizeof(float)); + // followed by a variable number of float coefficients + memcpy(destinationBuffer, _headData->_blendshapeCoefficients.data(), _headData->_blendshapeCoefficients.size() * sizeof(float)); destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); } @@ -377,6 +399,16 @@ bool AvatarData::shouldLogError(const quint64& now) { return false; } +#define PACKET_READ_CHECK(ITEM_NAME, SIZE_TO_READ) \ + if ((endPosition - sourceBuffer) < (int)SIZE_TO_READ) { \ + if (shouldLogError(now)) { \ + qCWarning(avatars) << "AvatarData packet too small, attempting to read " << \ + #ITEM_NAME << ", only " << (endPosition - sourceBuffer) << \ + " bytes left, " << getSessionUUID(); \ + } \ + return buffer.size(); \ + } + // read data in packet starting at byte offset and return number of bytes parsed int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { @@ -386,124 +418,76 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } const unsigned char* startPosition = reinterpret_cast(buffer.data()); + const unsigned char* endPosition = startPosition + buffer.size(); const unsigned char* sourceBuffer = startPosition; quint64 now = usecTimestampNow(); - // The absolute minimum size of the update data is as follows: - // 36 bytes of "plain old data" { - // position = 12 bytes - // bodyYaw = 2 (compressed float) - // bodyPitch = 2 (compressed float) - // bodyRoll = 2 (compressed float) - // targetScale = 2 (compressed float) - // lookAt = 12 - // audioLoudness = 4 - // } - // + 1 byte for varying data - // + 1 byte for numJoints (0) - // = 39 bytes - int minPossibleSize = 39; + PACKET_READ_CHECK(Header, sizeof(AvatarDataPacket::Header)); + auto header = reinterpret_cast(sourceBuffer); + sourceBuffer += sizeof(AvatarDataPacket::Header); - int maxAvailableSize = buffer.size(); - if (minPossibleSize > maxAvailableSize) { + glm::vec3 position = glm::vec3(header->position[0], header->position[1], header->position[2]); + _globalPosition = glm::vec3(header->globalPosition[0], header->globalPosition[1], header->globalPosition[2]); + if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) { if (shouldLogError(now)) { - qCDebug(avatars) << "Malformed AvatarData packet at the start; " - << " displayName = '" << _displayName << "'" - << " minPossibleSize = " << minPossibleSize - << " maxAvailableSize = " << maxAvailableSize; + qCWarning(avatars) << "Discard AvatarData packet: position NaN, uuid " << getSessionUUID(); } - // this packet is malformed so we report all bytes as consumed - return maxAvailableSize; + return buffer.size(); + } + setLocalPosition(position); + + float pitch, yaw, roll; + unpackFloatAngleFromTwoByte(header->localOrientation + 0, &yaw); + unpackFloatAngleFromTwoByte(header->localOrientation + 1, &pitch); + unpackFloatAngleFromTwoByte(header->localOrientation + 2, &roll); + if (glm::isnan(yaw) || glm::isnan(pitch) || glm::isnan(roll)) { + if (shouldLogError(now)) { + qCWarning(avatars) << "Discard AvatarData packet: localOriention is NaN, uuid " << getSessionUUID(); + } + return buffer.size(); } - { // Body world position, rotation, and scale - // position - glm::vec3 position; - memcpy(&position, sourceBuffer, sizeof(position)); - sourceBuffer += sizeof(position); + glm::quat currentOrientation = getLocalOrientation(); + glm::vec3 newEulerAngles(pitch, yaw, roll); + glm::quat newOrientation = glm::quat(glm::radians(newEulerAngles)); + if (currentOrientation != newOrientation) { + _hasNewJointRotations = true; + setLocalOrientation(newOrientation); + } - memcpy(&_globalPosition, sourceBuffer, sizeof(_globalPosition)); - sourceBuffer += sizeof(_globalPosition); - - if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Discard nan AvatarData::position; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; + float scale; + unpackFloatRatioFromTwoByte((uint8_t*)&header->scale, scale); + if (glm::isnan(scale)) { + if (shouldLogError(now)) { + qCWarning(avatars) << "Discard AvatarData packet: scale NaN, uuid " << getSessionUUID(); } - setLocalPosition(position); + return buffer.size(); + } + _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, scale)); - // rotation (NOTE: This needs to become a quaternion to save two bytes) - float yaw, pitch, roll; - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &yaw); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &pitch); - sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &roll); - if (glm::isnan(yaw) || glm::isnan(pitch) || glm::isnan(roll)) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Discard nan AvatarData::yaw,pitch,roll; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; + glm::vec3 lookAt = glm::vec3(header->lookAtPosition[0], header->lookAtPosition[1], header->lookAtPosition[2]); + if (glm::isnan(lookAt.x) || glm::isnan(lookAt.y) || glm::isnan(lookAt.z)) { + if (shouldLogError(now)) { + qCWarning(avatars) << "Discard AvatarData packet: lookAtPosition is NaN, uuid " << getSessionUUID(); } + return buffer.size(); + } + _headData->_lookAtPosition = lookAt; - // TODO is this safe? will the floats not exactly match? - // Andrew says: - // Yes, there is a possibility that the transmitted will not quite match the extracted despite being originally - // extracted from the exact same quaternion. I followed the code through and it appears the risk is that the - // avatar's SkeletonModel might fall into the CPU expensive part of Model::updateClusterMatrices() when otherwise it - // would not have required it. However, we know we can update many simultaneously animating avatars, and most - // avatars will be moving constantly anyway, so I don't think we need to worry. - glm::quat currentOrientation = getLocalOrientation(); - glm::vec3 newEulerAngles(pitch, yaw, roll); - glm::quat newOrientation = glm::quat(glm::radians(newEulerAngles)); - if (currentOrientation != newOrientation) { - _hasNewJointRotations = true; - setLocalOrientation(newOrientation); + float audioLoudness = header->audioLoudness; + if (glm::isnan(audioLoudness)) { + if (shouldLogError(now)) { + qCWarning(avatars) << "Discard AvatarData packet: audioLoudness is NaN, uuid " << getSessionUUID(); } - - // scale - float scale; - sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, scale); - if (glm::isnan(scale)) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Discard nan AvatarData::scale; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; - } - _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, scale)); - } // 20 bytes - - { // Lookat Position - glm::vec3 lookAt; - memcpy(&lookAt, sourceBuffer, sizeof(lookAt)); - sourceBuffer += sizeof(lookAt); - if (glm::isnan(lookAt.x) || glm::isnan(lookAt.y) || glm::isnan(lookAt.z)) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Discard nan AvatarData::lookAt; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; - } - _headData->_lookAtPosition = lookAt; - } // 12 bytes - - { // AudioLoudness - // Instantaneous audio loudness (used to drive facial animation) - float audioLoudness; - memcpy(&audioLoudness, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - if (glm::isnan(audioLoudness)) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Discard nan AvatarData::audioLoudness; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; - } - _headData->_audioLoudness = audioLoudness; - } // 4 bytes + return buffer.size(); + } + _headData->_audioLoudness = audioLoudness; { // bitFlags and face data - unsigned char bitItems = *sourceBuffer++; + uint8_t bitItems = header->flags; // key state, stored as a semi-nibble in the bitItems - _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); + _keyState = (KeyState)getSemiNibbleAt(bitItems, KEY_STATE_START_BIT); // hand state, stored as a semi-nibble plus a bit in the bitItems // we store the hand state as well as other items in a shared bitset. The hand state is an octal, but is split @@ -520,95 +504,48 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); if (hasReferential) { - const int sizeOfPackedUuid = 16; - QByteArray referentialAsBytes((const char*)sourceBuffer, sizeOfPackedUuid); - _parentID = QUuid::fromRfc4122(referentialAsBytes); - sourceBuffer += sizeOfPackedUuid; - memcpy(&_parentJointIndex, sourceBuffer, sizeof(_parentJointIndex)); - sourceBuffer += sizeof(_parentJointIndex); + PACKET_READ_CHECK(ParentInfo, sizeof(AvatarDataPacket::ParentInfo)); + auto parentInfo = reinterpret_cast(sourceBuffer); + sourceBuffer += sizeof(AvatarDataPacket::ParentInfo); + + const size_t RFC_4122_SIZE = 16; + QByteArray byteArray((const char*)parentInfo->parentUUID, RFC_4122_SIZE); + _parentID = QUuid::fromRfc4122(byteArray); + _parentJointIndex = parentInfo->parentJointIndex; } else { _parentID = QUuid(); } if (_headData->_isFaceTrackerConnected) { - float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift; - minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift); - minPossibleSize++; // one byte for blendDataSize - if (minPossibleSize > maxAvailableSize) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Malformed AvatarData packet after BitItems;" - << " displayName = '" << _displayName << "'" - << " minPossibleSize = " << minPossibleSize - << " maxAvailableSize = " << maxAvailableSize; - } - return maxAvailableSize; - } - // unpack face data - memcpy(&leftEyeBlink, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); + PACKET_READ_CHECK(FaceTrackerInfo, sizeof(AvatarDataPacket::FaceTrackerInfo)); + auto faceTrackerInfo = reinterpret_cast(sourceBuffer); + sourceBuffer += sizeof(AvatarDataPacket::FaceTrackerInfo); - memcpy(&rightEyeBlink, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); + _headData->_leftEyeBlink = faceTrackerInfo->leftEyeBlink; + _headData->_rightEyeBlink = faceTrackerInfo->rightEyeBlink; + _headData->_averageLoudness = faceTrackerInfo->averageLoudness; + _headData->_browAudioLift = faceTrackerInfo->browAudioLift; - memcpy(&averageLoudness, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - memcpy(&browAudioLift, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); - - if (glm::isnan(leftEyeBlink) || glm::isnan(rightEyeBlink) - || glm::isnan(averageLoudness) || glm::isnan(browAudioLift)) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Discard nan AvatarData::faceData; displayName = '" << _displayName << "'"; - } - return maxAvailableSize; - } - _headData->_leftEyeBlink = leftEyeBlink; - _headData->_rightEyeBlink = rightEyeBlink; - _headData->_averageLoudness = averageLoudness; - _headData->_browAudioLift = browAudioLift; - - int numCoefficients = (int)(*sourceBuffer++); - int blendDataSize = numCoefficients * sizeof(float); - minPossibleSize += blendDataSize; - if (minPossibleSize > maxAvailableSize) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Malformed AvatarData packet after Blendshapes;" - << " displayName = '" << _displayName << "'" - << " minPossibleSize = " << minPossibleSize - << " maxAvailableSize = " << maxAvailableSize; - } - return maxAvailableSize; - } - - _headData->_blendshapeCoefficients.resize(numCoefficients); - memcpy(_headData->_blendshapeCoefficients.data(), sourceBuffer, blendDataSize); - sourceBuffer += numCoefficients * sizeof(float); - - //bitItemsDataSize = 4 * sizeof(float) + 1 + blendDataSize; + int numCoefficients = faceTrackerInfo->numBlendshapeCoefficients; + const int coefficientsSize = sizeof(float) * numCoefficients; + PACKET_READ_CHECK(FaceTrackerCoefficients, coefficientsSize); + _headData->_blendshapeCoefficients.resize(numCoefficients); // make sure there's room for the copy! + memcpy(_headData->_blendshapeCoefficients.data(), sourceBuffer, coefficientsSize); + sourceBuffer += coefficientsSize; } - } // 1 + bitItemsDataSize bytes + } - // joint rotations + PACKET_READ_CHECK(NumJoints, sizeof(uint8_t)); int numJoints = *sourceBuffer++; - int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); - minPossibleSize += bytesOfValidity; - if (minPossibleSize > maxAvailableSize) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Malformed AvatarData packet after JointValidityBits;" - << " displayName = '" << _displayName << "'" - << " minPossibleSize = " << minPossibleSize - << " maxAvailableSize = " << maxAvailableSize; - } - return maxAvailableSize; - } - int numValidJointRotations = 0; _jointData.resize(numJoints); + const int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); + PACKET_READ_CHECK(JointRotationValidityBits, bytesOfValidity); + + int numValidJointRotations = 0; QVector validRotations; validRotations.resize(numJoints); - { // rotation validity bits unsigned char validity = 0; int validityBit = 0; @@ -623,39 +560,26 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { validRotations[i] = valid; validityBit = (validityBit + 1) % BITS_IN_BYTE; } - } // 1 + bytesOfValidity bytes - - // each joint rotation is stored in 6 bytes. - - const size_t COMPRESSED_QUATERNION_SIZE = 6; - minPossibleSize += numValidJointRotations * COMPRESSED_QUATERNION_SIZE; - if (minPossibleSize > maxAvailableSize) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Malformed AvatarData packet after JointData rotation validity;" - << " displayName = '" << _displayName << "'" - << " minPossibleSize = " << minPossibleSize - << " maxAvailableSize = " << maxAvailableSize; - } - return maxAvailableSize; } - { // joint data - for (int i = 0; i < numJoints; i++) { - JointData& data = _jointData[i]; - if (validRotations[i]) { - sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); - _hasNewJointRotations = true; - data.rotationSet = true; - } + // each joint rotation is stored in 6 bytes. + const int COMPRESSED_QUATERNION_SIZE = 6; + PACKET_READ_CHECK(JointRotations, numValidJointRotations * COMPRESSED_QUATERNION_SIZE); + for (int i = 0; i < numJoints; i++) { + JointData& data = _jointData[i]; + if (validRotations[i]) { + sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); + _hasNewJointRotations = true; + data.rotationSet = true; } - } // numJoints * 6 bytes + } + + PACKET_READ_CHECK(JointTranslationValidityBits, bytesOfValidity); - // joint translations // get translation validity bits -- these indicate which translations were packed int numValidJointTranslations = 0; QVector validTranslations; validTranslations.resize(numJoints); - { // translation validity bits unsigned char validity = 0; int validityBit = 0; @@ -673,30 +597,18 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } // 1 + bytesOfValidity bytes // each joint translation component is stored in 6 bytes. - const size_t COMPRESSED_TRANSLATION_SIZE = 6; - minPossibleSize += numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE; - if (minPossibleSize > maxAvailableSize) { - if (shouldLogError(now)) { - qCDebug(avatars) << "Malformed AvatarData packet after JointData translation validity;" - << " displayName = '" << _displayName << "'" - << " minPossibleSize = " << minPossibleSize - << " maxAvailableSize = " << maxAvailableSize; - } - return maxAvailableSize; - } - + const int COMPRESSED_TRANSLATION_SIZE = 6; + PACKET_READ_CHECK(JointTranslation, numValidJointTranslations * COMPRESSED_QUATERNION_SIZE); const int TRANSLATION_COMPRESSION_RADIX = 12; - { // joint data - for (int i = 0; i < numJoints; i++) { - JointData& data = _jointData[i]; - if (validTranslations[i]) { - sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); - _hasNewJointTranslations = true; - data.translationSet = true; - } + for (int i = 0; i < numJoints; i++) { + JointData& data = _jointData[i]; + if (validTranslations[i]) { + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); + _hasNewJointTranslations = true; + data.translationSet = true; } - } // numJoints * 6 bytes + } #ifdef WANT_DEBUG if (numValidJointRotations > 15) { @@ -707,6 +619,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { #endif int numBytesRead = sourceBuffer - startPosition; + + // AJT: Maybe make this a warning. + ASSERT(numBytesRead == buffer.size()); + _averageBytesReceived.updateAverage(numBytesRead); return numBytesRead; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 817d8aef09..dfb27411b8 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -53,6 +53,7 @@ typedef unsigned long long quint64; #include #include #include +#include #include "AABox.h" #include "HeadData.h" @@ -165,6 +166,7 @@ class AvatarData : public QObject, public SpatiallyNestable { Q_PROPERTY(QUuid sessionUUID READ getSessionUUID) public: + static const QString FRAME_NAME; static void fromFrame(const QByteArray& frameData, AvatarData& avatar); diff --git a/libraries/shared/src/Packed.h b/libraries/shared/src/Packed.h new file mode 100644 index 0000000000..3300634b96 --- /dev/null +++ b/libraries/shared/src/Packed.h @@ -0,0 +1,12 @@ +#ifndef hifi_Packed_h +#define hifi_Packed_h + +#if defined(_MSC_VER) +#define PACKED_BEGIN __pragma(pack(push, 1)) +#define PACKED_END __pragma(pack(pop)); +#else +#define PACKED_BEGIN +#define PACKED_END __attribute__((__packed__)); +#endif + +#endif From c73943ee19574a95bc9ecce380929dab71d4bffc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 19 May 2016 20:32:08 -0700 Subject: [PATCH 26/59] macosx warning fixes --- libraries/avatars/src/AvatarData.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4379a0d72c..7a20f24da8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -101,9 +101,9 @@ AvatarData::AvatarData() : setBodyYaw(-90.0f); setBodyRoll(0.0f); - ASSERT(sizeof AvatarDataPacket::Header == AvatarDataPacket::HEADER_SIZE); - ASSERT(sizeof AvatarDataPacket::ParentInfo == AvatarDataPacket::PARENT_INFO_SIZE); - ASSERT(sizeof AvatarDataPacket::FaceTrackerInfo == AvatarDataPacket::FACE_TRACKER_INFO_SIZE); + ASSERT(sizeof(AvatarDataPacket::Header) == AvatarDataPacket::HEADER_SIZE); + ASSERT(sizeof(AvatarDataPacket::ParentInfo) == AvatarDataPacket::PARENT_INFO_SIZE); + ASSERT(sizeof(AvatarDataPacket::FaceTrackerInfo) == AvatarDataPacket::FACE_TRACKER_INFO_SIZE); } AvatarData::~AvatarData() { @@ -598,7 +598,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { // each joint translation component is stored in 6 bytes. const int COMPRESSED_TRANSLATION_SIZE = 6; - PACKET_READ_CHECK(JointTranslation, numValidJointTranslations * COMPRESSED_QUATERNION_SIZE); + PACKET_READ_CHECK(JointTranslation, numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE); const int TRANSLATION_COMPRESSION_RADIX = 12; for (int i = 0; i < numJoints; i++) { From aa58cad93e51ef078a3d6230c15d99b94cf5f86f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 20 May 2016 09:54:54 -0700 Subject: [PATCH 27/59] code review --- libraries/script-engine/src/ScriptEngine.cpp | 7 +++++++ libraries/script-engine/src/ScriptEngine.h | 4 +++- libraries/script-engine/src/ScriptEngines.cpp | 5 +---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 67b87ae5e0..d8e0397347 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -938,6 +938,13 @@ void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) { } void ScriptEngine::stop() { + _isStopping = true; // this can be done on any thread + + // marshal us over to the correct thread + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "stop"); + return; + } if (!_isFinished) { _isFinished = true; emit runningStateChanged(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 512e79fb95..6af6aef338 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -84,7 +84,7 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts - Q_INVOKABLE void stop(); + Q_INVOKABLE void stop(); // this can be called from any thread // Stop any evaluating scripts and wait for the scripting thread to finish. void waitTillDoneRunning(); @@ -146,6 +146,8 @@ public: bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget bool isRunning() const { return _isRunning; } // used by ScriptWidget + + // these are used by code in ScriptEngines.cpp during the "reload all" operation bool isStopping() const { return _isStopping; } void setIsStopping() { _isStopping = true; } diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 8b57487db0..0d1f0de3c9 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -160,7 +160,6 @@ void ScriptEngines::shutdownScripting() { scriptEngine->disconnect(this); // Gracefully stop the engine's scripting thread - scriptEngine->setIsStopping(); scriptEngine->stop(); // We need to wait for the engine to be done running before we proceed, because we don't @@ -352,8 +351,7 @@ void ScriptEngines::stopAllScripts(bool restart) { reloadScript(scriptName); }); } - it.value()->setIsStopping(); - QMetaObject::invokeMethod(it.value(), "stop"); + it.value()->stop(); qCDebug(scriptengine) << "stopping script..." << it.key(); } } @@ -376,7 +374,6 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { reloadScript(scriptName); }); } - scriptEngine->setIsStopping(); scriptEngine->stop(); stoppedScript = true; qCDebug(scriptengine) << "stopping script..." << scriptURL; From 35065ab05ecb7384907f47a6360fda08c187cfd1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 20 May 2016 10:12:38 -0700 Subject: [PATCH 28/59] remove unused setter --- libraries/script-engine/src/ScriptEngine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 6af6aef338..2222503781 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -149,7 +149,6 @@ public: // these are used by code in ScriptEngines.cpp during the "reload all" operation bool isStopping() const { return _isStopping; } - void setIsStopping() { _isStopping = true; } bool isDebuggable() const { return _debuggable; } From 1ef0f8055bcd0f9b0a981bd24f16f6d6b8cb67fc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 20 May 2016 10:12:59 -0700 Subject: [PATCH 29/59] fix grammar in comment --- libraries/script-engine/src/ScriptEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 2222503781..ef7e075021 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -147,7 +147,7 @@ public: bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget bool isRunning() const { return _isRunning; } // used by ScriptWidget - // these are used by code in ScriptEngines.cpp during the "reload all" operation + // this is used by code in ScriptEngines.cpp during the "reload all" operation bool isStopping() const { return _isStopping; } bool isDebuggable() const { return _debuggable; } From 180f4ba4f509e2c70d6f86905d5e4c49ecd704c9 Mon Sep 17 00:00:00 2001 From: Geenz Date: Sun, 22 May 2016 21:02:28 -0400 Subject: [PATCH 30/59] Tweaked light attenuation formula some more. Keeping the ulightvec parameter for now - I want to revisit this later. --- libraries/model/src/model/Light.slh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 46eb352d16..de15e50908 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -106,9 +106,11 @@ float evalLightAttenuation(Light l, float d, vec3 ulightvec) { float denom = d / radius + 1.0; float attenuation = 1.0 / (denom * denom); + float cutoff = getLightCutoffRadius(l); + // "Fade" the edges of light sources to make things look a bit more attractive. // Note: this tends to look a bit odd at lower exponents. - attenuation *= clamp(0, 1, mix(0, 1, getLightCutoffSquareRadius(l) - dot(ulightvec, ulightvec))); + attenuation *= min(1, max(0, -(d - cutoff))); return attenuation; } From ff3fca3dc345c048009fc8ba03263850734aef9f Mon Sep 17 00:00:00 2001 From: Geenz Date: Sun, 22 May 2016 21:50:48 -0400 Subject: [PATCH 31/59] Remove no longer necessary light vector parameter. --- libraries/model/src/model/Light.slh | 6 ++---- libraries/render-utils/src/point_light.slf | 2 +- libraries/render-utils/src/spot_light.slf | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index de15e50908..7cb745ff53 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -98,10 +98,8 @@ float getLightShowContour(Light l) { return l._control.w; } -// Light is the light source its self, d is the light's distance, and ulightvec is the unnormalized light vector. -// Note that ulightvec should be calculated as light position - fragment position. -// Additionally, length(light position) != dot(light position, light position). -float evalLightAttenuation(Light l, float d, vec3 ulightvec) { +// Light is the light source its self, d is the light's distance calculated as length(unnormalized light vector). +float evalLightAttenuation(Light l, float d) { float radius = getLightRadius(l); float denom = d / radius + 1.0; float attenuation = 1.0 / (denom * denom); diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 581aa8c250..8c9ff2c8ad 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -67,7 +67,7 @@ void main(void) { vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance, fragLightVec); + float radialAttenuation = evalLightAttenuation(light, fragLightDistance); // Final Lighting color vec3 fragColor = (shading.w * frag.diffuse + shading.xyz); diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 1cb6ebb878..63e87e95c0 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -74,7 +74,7 @@ void main(void) { vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance, fragLightVec); + float radialAttenuation = evalLightAttenuation(light, fragLightDistance4); float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); // Final Lighting color From bd6f6d2eef4916646334b16878bf8cc565c3ce7d Mon Sep 17 00:00:00 2001 From: Geenz Date: Mon, 23 May 2016 09:53:22 -0400 Subject: [PATCH 32/59] Typo. Not quite sure how this got here. --- libraries/render-utils/src/spot_light.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 63e87e95c0..4191ba3f63 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -74,7 +74,7 @@ void main(void) { vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance4); + float radialAttenuation = evalLightAttenuation(light, fragLightDistance); float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); // Final Lighting color From 5fe01acaa84c30d284d0033b32b5496e6a3ad87e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 23 May 2016 10:03:13 -0700 Subject: [PATCH 33/59] Added more comments to AvatarDataPacket section. --- libraries/avatars/src/AvatarData.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7a20f24da8..b74fc8de2e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -61,12 +61,14 @@ namespace AvatarDataPacket { } PACKED_END; const size_t HEADER_SIZE = 49; + // only present if HAS_REFERENTIAL flag is set in header.flags PACKED_BEGIN struct ParentInfo { uint8_t parentUUID[16]; // rfc 4122 encoded uint16_t parentJointIndex; } PACKED_END; const size_t PARENT_INFO_SIZE = 18; + // only present if IS_FACESHIFT_CONNECTED flag is set in header.flags PACKED_BEGIN struct FaceTrackerInfo { float leftEyeBlink; float rightEyeBlink; @@ -76,6 +78,17 @@ namespace AvatarDataPacket { // float blendshapeCoefficients[numBlendshapeCoefficients]; } PACKED_END; const size_t FACE_TRACKER_INFO_SIZE = 17; + + // variable length structure follows + /* + struct JointData { + uint8_t numJoints; + uint8_t rotationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed rotation follows. + SixByteQuat rotation[numValidRotations]; // encodeded and compressed by packOrientationQuatToSixBytes() + uint8_t translationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed translation follows. + SixByteTrans translation[numValidTranslations]; // encodeded and compressed by packFloatVec3ToSignedTwoByteFixed() + }; + */ } #define ASSERT(COND) do { if (!(COND)) { int* bad = nullptr; *bad = 0xbad; } } while(0) From 9aad38b2c2582a73d72ad0ad22740d07fe0e7ab4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 23 May 2016 10:39:39 -0700 Subject: [PATCH 34/59] merge fix --- libraries/avatars/src/AvatarData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7d571a826f..61ee649273 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -296,7 +296,7 @@ public: QUrl skeletonModelURL; QVector attachmentData; QString displayName; - AvatarEntityMap avatarEntityMap; + AvatarEntityMap avatarEntityData; }; static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut); From 4342a071086731f25aa1f936acb3831e2d7043fd Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 23 May 2016 11:11:37 -0700 Subject: [PATCH 35/59] Updated AvatarDataPacket section with sequence number info. --- libraries/avatars/src/AvatarData.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1ca4b1beb1..cc61036915 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -49,6 +49,7 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f); const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData"; namespace AvatarDataPacket { + // NOTE: AvatarDataPackets start with a uint16_t sequence number that is not reflected in the Header structure. PACKED_BEGIN struct Header { float position[3]; // skeletal model's position From fdcd667d3c4f54c8958de1c89c9007adf8130582 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 23 May 2016 13:33:42 -0700 Subject: [PATCH 36/59] Fix hand controller pointer after input changes. --- interface/resources/controllers/hydra.json | 8 +- interface/resources/controllers/vive.json | 4 +- .../controllers/handControllerPointer.js | 112 ++++++------------ 3 files changed, 46 insertions(+), 78 deletions(-) diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index 42237033af..8233685763 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -16,8 +16,12 @@ { "from": "Hydra.L0", "to": "Standard.Back" }, { "from": "Hydra.R0", "to": "Standard.Start" }, - { "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, - { "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.L1", "Hydra.L2" ], "to": "Standard.LeftPrimaryThumb" }, + { "from": [ "Hydra.R1", "Hydra.R2" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.L3" ], "to": "Standard.L3" }, + { "from": [ "Hydra.R3" ], "to": "Standard.R3" }, + { "from": [ "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" }, + { "from": [ "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" }, { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Hydra.RightHand", "to": "Standard.RightHand" } diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index 4085d71c27..fec93c9132 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -17,8 +17,8 @@ { "from": "Vive.RS", "to": "Standard.RS" }, { "from": "Vive.RSTouch", "to": "Standard.RSTouch" }, - { "from": "Vive.LeftApplicationMenu", "to": "Standard.Back" }, - { "from": "Vive.RightApplicationMenu", "to": "Standard.Start" }, + { "from": "Vive.LeftApplicationMenu", "to": "Standard.LeftSecondaryThumb" }, + { "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand" }, { "from": "Vive.RightHand", "to": "Standard.RightHand" } diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index f4e4492a88..e7be3af5dd 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -22,10 +22,7 @@ // (For now, the thumb buttons on both controllers are always on.) // When over a HUD element, the reticle is shown where the active hand controller beam intersects the HUD. // Otherwise, the active hand controller shows a red ball where a click will act. -// -// Bugs: -// On Windows, the upper left corner of Interface must be in the upper left corner of the screen, and the title bar must be 50px high. (System bug.) -// While hardware mouse move switches to mouse move, hardware mouse click (without amove) does not. + // UTILITIES ------------- @@ -270,75 +267,43 @@ function toggleHand() { } // Create clickMappings as needed, on demand. -var clickMappings = {}, clickMapping, clickMapToggle; -var hardware; // undefined -function checkHardware() { - var newHardware = Controller.Hardware.Hydra ? 'Hydra' : (Controller.Hardware.Vive ? 'Vive' : null); // not undefined - if (hardware === newHardware) { - return; - } - print('Setting mapping for new controller hardware:', newHardware); - if (clickMapToggle) { - clickMapToggle.setState(false); - } - hardware = newHardware; - if (clickMappings[hardware]) { - clickMapping = clickMappings[hardware]; - } else { - clickMapping = Controller.newMapping(Script.resolvePath('') + '-click-' + hardware); - Script.scriptEnding.connect(clickMapping.disable); - function mapToAction(button, action) { - clickMapping.from(Controller.Hardware[hardware][button]).peek().to(Controller.Actions[action]); - } - function makeHandToggle(button, hand, optionalWhen) { - var whenThunk = optionalWhen || function () { - return true; - }; - function maybeToggle() { - if (activeHand !== Controller.Standard[hand]) { - toggleHand(); - } +var clickMapping = Controller.newMapping(Script.resolvePath('') + '-click'); +Script.scriptEnding.connect(clickMapping.disable); - } - clickMapping.from(Controller.Hardware[hardware][button]).peek().when(whenThunk).to(maybeToggle); - } - function makeViveWhen(click, x, y) { - var viveClick = Controller.Hardware.Vive[click], - viveX = Controller.Standard[x], // Standard after filtering by mapping - viveY = Controller.Standard[y]; - return function () { - var clickValue = Controller.getValue(viveClick); - var xValue = Controller.getValue(viveX); - var yValue = Controller.getValue(viveY); - return clickValue && !xValue && !yValue; - }; - } - switch (hardware) { - case 'Hydra': - makeHandToggle('R3', 'RightHand'); - makeHandToggle('L3', 'LeftHand'); - - mapToAction('R3', 'ReticleClick'); - mapToAction('L3', 'ReticleClick'); - mapToAction('R4', 'ContextMenu'); - mapToAction('L4', 'ContextMenu'); - break; - case 'Vive': - // When touchpad click is NOT treated as movement, treat as left click - makeHandToggle('RS', 'RightHand', makeViveWhen('RS', 'RX', 'RY')); - makeHandToggle('LS', 'LeftHand', makeViveWhen('LS', 'LX', 'LY')); - clickMapping.from(Controller.Hardware.Vive.RS).when(makeViveWhen('RS', 'RX', 'RY')).to(Controller.Actions.ReticleClick); - clickMapping.from(Controller.Hardware.Vive.LS).when(makeViveWhen('LS', 'LX', 'LY')).to(Controller.Actions.ReticleClick); - mapToAction('RightApplicationMenu', 'ContextMenu'); - mapToAction('LeftApplicationMenu', 'ContextMenu'); - break; - } - clickMappings[hardware] = clickMapping; - } - clickMapToggle = new LatchedToggle(clickMapping.enable, clickMapping.disable); - clickMapToggle.setState(true); +// Move these to vive.json +function makeCenterClickWhen(click, x, y) { + var clickKey = Controller.Standard[click], + xKey = Controller.Standard[x], // Standard after filtering by mapping + yKey = Controller.Standard[y]; + return function () { + var clickValue = Controller.getValue(clickKey); + var xValue = Controller.getValue(xKey); + var yValue = Controller.getValue(yKey); + var answer = clickValue && !xValue && !yValue; + return answer; + }; } -checkHardware(); +if (Controller.Hardware.Vive) { + clickMapping.from(Controller.Hardware.Vive.RS).when(makeCenterClickWhen('RS', 'RX', 'RY')).to(Controller.Standard.R3); + clickMapping.from(Controller.Hardware.Vive.LS).when(makeCenterClickWhen('LS', 'LX', 'LY')).to(Controller.Standard.L3); +} + + +clickMapping.from(Controller.Standard.R3).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.L3).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu); +clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu); +clickMapping.from(Controller.Standard.R3).peek().to(function (on) { + if (on && (activeHand !== Controller.Standard.RightHand)) { + toggleHand(); + } +}); +clickMapping.from(Controller.Standard.L3).peek().to(function (on) { + if (on && (activeHand !== Controller.Standard.LeftHand)) { + toggleHand(); + } +}); +clickMapping.enable(); // VISUAL AID ----------- // Same properties as handControllerGrab search sphere @@ -415,8 +380,8 @@ function update() { return turnOffVisualization(); } var controllerPose = Controller.getPoseValue(activeHand); - // Vive is effectively invalid when not in HMD - if (!controllerPose.valid || ((hardware === 'Vive') && !HMD.active)) { + // Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...) + if (!controllerPose.valid) { return turnOffVisualization(); } // Controller is cradled. var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), @@ -458,7 +423,6 @@ Script.scriptEnding.connect(function () { var SETTINGS_CHANGE_RECHECK_INTERVAL = 10 * 1000; // milliseconds function checkSettings() { updateFieldOfView(); - checkHardware(); } checkSettings(); var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL); From 1d9981e6242d7fda4e9e6db824948b5f6ad45a2a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 13:31:19 -0700 Subject: [PATCH 37/59] first cut at support for verifying all protocol version compatibility --- domain-server/src/DomainGatekeeper.cpp | 42 +++++++++++++---- domain-server/src/DomainGatekeeper.h | 5 +- domain-server/src/DomainServer.cpp | 39 +++++++++++++++ domain-server/src/DomainServer.h | 2 + domain-server/src/NodeConnectionData.cpp | 9 ++++ domain-server/src/NodeConnectionData.h | 2 + interface/src/Application.cpp | 23 ++++++++- interface/src/Application.h | 8 ++++ interface/src/Menu.cpp | 7 +++ interface/src/Menu.h | 1 + .../src/scripting/WindowScriptingInterface.h | 4 +- libraries/networking/src/DomainHandler.cpp | 47 +++++++++++++------ libraries/networking/src/DomainHandler.h | 12 ++++- libraries/networking/src/LimitedNodeList.cpp | 4 ++ libraries/networking/src/LimitedNodeList.h | 6 ++- libraries/networking/src/NLPacket.cpp | 9 ++-- libraries/networking/src/NLPacket.h | 4 +- libraries/networking/src/NodeList.cpp | 32 +++++++++++-- libraries/networking/src/NodeList.h | 15 ++++++ libraries/networking/src/PacketReceiver.cpp | 13 ++++- .../networking/src/udt/PacketHeaders.cpp | 43 ++++++++++++++++- libraries/networking/src/udt/PacketHeaders.h | 21 ++++++++- 22 files changed, 304 insertions(+), 44 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 61cc775e08..9d5ee75818 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -56,10 +56,24 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetVersion(); + + QDataStream packetStream(message->getMessage()); // read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it NodeConnectionData nodeConnection = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr()); + + QByteArray myProtocolVersion = protocolVersionsSignature(); + if (nodeConnection.protocolVersion != myProtocolVersion) { + QString protocolVersionError = "Protocol version mismatch - Domain version:" + QCoreApplication::applicationVersion(); + qDebug() << "Protocol Version mismatch - denying connection."; + sendConnectionDeniedPacket(protocolVersionError, message->getSenderSockAddr(), + DomainHandler::ConnectionRefusedReason::ProtocolMismatch); + return; + } + //qDebug() << __FUNCTION__ << "Protocol Version MATCH - continue with processing connection."; + if (nodeConnection.localSockAddr.isNull() || nodeConnection.publicSockAddr.isNull()) { qDebug() << "Unexpected data received for node local socket or public socket. Will not allow connection."; @@ -97,7 +111,9 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetSenderSockAddr(); @@ -332,7 +351,7 @@ SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const Node bool DomainGatekeeper::verifyUserSignature(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr) { - + // it's possible this user can be allowed to connect, but we need to check their username signature QByteArray publicKeyArray = _userPublicKeys.value(username); @@ -370,7 +389,8 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, } else { if (!senderSockAddr.isNull()) { qDebug() << "Error decrypting username signature for " << username << "- denying connection."; - sendConnectionDeniedPacket("Error decrypting username signature.", senderSockAddr); + sendConnectionDeniedPacket("Error decrypting username signature.", senderSockAddr, + DomainHandler::ConnectionRefusedReason::LoginError); } // free up the public key, we don't need it anymore @@ -382,13 +402,15 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, // we can't let this user in since we couldn't convert their public key to an RSA key we could use if (!senderSockAddr.isNull()) { qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection."; - sendConnectionDeniedPacket("Couldn't convert data to RSA key.", senderSockAddr); + sendConnectionDeniedPacket("Couldn't convert data to RSA key.", senderSockAddr, + DomainHandler::ConnectionRefusedReason::LoginError); } } } else { if (!senderSockAddr.isNull()) { qDebug() << "Insufficient data to decrypt username signature - denying connection."; - sendConnectionDeniedPacket("Insufficient data", senderSockAddr); + sendConnectionDeniedPacket("Insufficient data", senderSockAddr, + DomainHandler::ConnectionRefusedReason::LoginError); } } @@ -402,7 +424,8 @@ bool DomainGatekeeper::isVerifiedAllowedUser(const QString& username, const QByt if (username.isEmpty()) { qDebug() << "Connect request denied - no username provided."; - sendConnectionDeniedPacket("No username provided", senderSockAddr); + sendConnectionDeniedPacket("No username provided", senderSockAddr, + DomainHandler::ConnectionRefusedReason::LoginError); return false; } @@ -416,7 +439,8 @@ bool DomainGatekeeper::isVerifiedAllowedUser(const QString& username, const QByt } } else { qDebug() << "Connect request denied for user" << username << "- not in allowed users list."; - sendConnectionDeniedPacket("User not on whitelist.", senderSockAddr); + sendConnectionDeniedPacket("User not on whitelist.", senderSockAddr, + DomainHandler::ConnectionRefusedReason::NotAuthorized); return false; } @@ -452,7 +476,8 @@ bool DomainGatekeeper::isWithinMaxCapacity(const QString& username, const QByteA // deny connection from this user qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection."; - sendConnectionDeniedPacket("Too many connected users.", senderSockAddr); + sendConnectionDeniedPacket("Too many connected users.", senderSockAddr, + DomainHandler::ConnectionRefusedReason::TooManyUsers); return false; } @@ -516,7 +541,8 @@ void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply& requestReply) { } } -void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr) { +void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr, + DomainHandler::ConnectionRefusedReason reasonCode) { // this is an agent and we've decided we won't let them connect - send them a packet to deny connection QByteArray utfString = reason.toUtf8(); quint16 payloadSize = utfString.size(); diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index c4ac32fabf..09e3b04ed7 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -74,7 +76,8 @@ private: const HifiSockAddr& senderSockAddr); void sendConnectionTokenPacket(const QString& username, const HifiSockAddr& senderSockAddr); - void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr); + void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr, + DomainHandler::ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown); void pingPunchForConnectingPeer(const SharedNetworkPeer& peer); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index cfec72a24b..18ca7e2941 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -303,6 +303,36 @@ const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; + + +bool DomainServer::packetVersionMatch(const udt::Packet& packet) { + PacketType headerType = NLPacket::typeInHeader(packet); + PacketVersion headerVersion = NLPacket::versionInHeader(packet); + + //qDebug() << __FUNCTION__ << "type:" << headerType << "version:" << (int)headerVersion; + + auto nodeList = DependencyManager::get(); + + // This implements a special case that handles OLD clients which don't know how to negotiate matching + // protocol versions. We know these clients will sent DomainConnectRequest with older versions. We also + // know these clients will show a warning dialog if they get an EntityData with a protocol version they + // don't understand, so we can send them an empty EntityData with our latest version and they will + // warn the user that the protocol is not compatible + if (headerType == PacketType::DomainConnectRequest && + headerVersion < static_cast(DomainConnectRequestVersion::HasProtocolVersions)) { + + //qDebug() << __FUNCTION__ << "OLD VERSION checkin sending an intentional bad packet -------------------------------"; + + auto packetWithBadVersion = NLPacket::create(PacketType::EntityData); + nodeList->sendPacket(std::move(packetWithBadVersion), packet.getSenderSockAddr()); + return false; + } + + // let the normal nodeList implementation handle all other packets. + return nodeList->isPacketVerified(packet); +} + + void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; @@ -376,6 +406,10 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { // add whatever static assignments that have been parsed to the queue addStaticAssignmentsToQueue(); + + // set packetVersionMatch as the verify packet operator for the udt::Socket + //using std::placeholders::_1; + nodeList->setPacketFilterOperator(&DomainServer::packetVersionMatch); } const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token"; @@ -666,6 +700,8 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet message, SharedNodePointer sendingNode) { + + //qDebug() << __FUNCTION__ << "---------------"; QDataStream packetStream(message->getMessage()); NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false); @@ -746,6 +782,9 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode) { } void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr) { + + //qDebug() << __FUNCTION__ << "---------------"; + const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NUM_BYTES_RFC4122_UUID + 2; // setup the extended header for the domain list packets diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index fef3221b7d..c39e405380 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -99,6 +99,8 @@ private: void optionallyGetTemporaryName(const QStringList& arguments); + static bool packetVersionMatch(const udt::Packet& packet); + bool resetAccountManagerAccessToken(); void setupAutomaticNetworking(); diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index 28f769298c..5ddcbf1792 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -19,6 +19,15 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c if (isConnectRequest) { dataStream >> newHeader.connectUUID; + + // Read out the protocol version signature from the connect message + char* rawBytes; + uint length; + + // FIXME -- do we need to delete the rawBytes after it's been copied into the QByteArray? + dataStream.readBytes(rawBytes, length); + newHeader.protocolVersion = QByteArray(rawBytes, length); + //qDebug() << __FUNCTION__ << "...got protocol version from node... version:" << newHeader.protocolVersion; } dataStream >> newHeader.nodeType diff --git a/domain-server/src/NodeConnectionData.h b/domain-server/src/NodeConnectionData.h index 34119ffdab..9264db637e 100644 --- a/domain-server/src/NodeConnectionData.h +++ b/domain-server/src/NodeConnectionData.h @@ -28,6 +28,8 @@ public: HifiSockAddr senderSockAddr; QList interestList; QString placeName; + + QByteArray protocolVersion; }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b0e4880011..821cd83c31 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -631,6 +631,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); + + connect(&domainHandler, &DomainHandler::resetting, nodeList.data(), &NodeList::resetDomainServerCheckInVersion); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SEC; @@ -653,7 +655,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated); connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); - connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); + + connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, this, &Application::limitOfSilentDomainCheckInsReached); + //connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); + + connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // connect to appropriate slots on AccountManager @@ -4569,6 +4575,21 @@ void Application::setSessionUUID(const QUuid& sessionUUID) const { Physics::setSessionUUID(sessionUUID); } + +// If we're not getting anything back from the domain server checkin, it might be that the domain speaks an +// older version of the DomainConnectRequest protocal. We will attempt to send and older version of DomainConnectRequest. +// We won't actually complete the connection, but if the server responds, we know that it needs to be upgraded (or we +// need to be downgraded to talk to it). +void Application::limitOfSilentDomainCheckInsReached() { + //qDebug() << __FUNCTION__; + + auto nodeList = DependencyManager::get(); + + nodeList->downgradeDomainServerCheckInVersion(); // attempt to use an older domain checkin version + + nodeList->reset(); +} + bool Application::askToSetAvatarUrl(const QString& url) { QUrl realUrl(url); if (realUrl.isLocalFile()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 28dbcead47..edd1b6187d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -261,6 +261,12 @@ public slots: void resetSensors(bool andReload = false); void setActiveFaceTracker() const; +#if (PR_BUILD || DEV_BUILD) + void sendWrongProtocolVersionsSignature(bool checked) { + ::sendWrongProtocolVersionsSignature(checked); + } +#endif + #ifdef HAVE_IVIEWHMD void setActiveEyeTracker(); void calibrateEyeTracker1Point(); @@ -314,6 +320,8 @@ private slots: bool displayAvatarAttachmentConfirmationDialog(const QString& name) const; void setSessionUUID(const QUuid& sessionUUID) const; + void limitOfSilentDomainCheckInsReached(); + void domainChanged(const QString& domainHostname); void updateWindowTitle() const; void nodeAdded(SharedNodePointer node) const; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 538410a47d..a21aa71753 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -545,6 +545,13 @@ Menu::Menu() { addActionToQMenuAndActionHash(networkMenu, MenuOption::BandwidthDetails, 0, dialogsManager.data(), SLOT(bandwidthDetails())); + #if (PR_BUILD || DEV_BUILD) + addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongProtocolVersion, 0, false, + qApp, SLOT(sendWrongProtocolVersionsSignature(bool))); + #endif + + + // Developer > Timing >>> MenuWrapper* timingMenu = developerMenu->addMenu("Timing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 36d285e2cf..fcaf8e6caa 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -167,6 +167,7 @@ namespace MenuOption { const QString RunTimingTests = "Run Timing Tests"; const QString ScriptEditor = "Script Editor..."; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; + const QString SendWrongProtocolVersion = "Send wrong protocol version"; const QString SetHomeLocation = "Set Home Location"; const QString ShowDSConnectTable = "Show Domain Connection Timing"; const QString ShowBordersEntityNodes = "Show Entity Nodes"; diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 0f51a484c4..145d17faaf 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -16,6 +16,8 @@ #include #include +#include + class WebWindowClass; class WindowScriptingInterface : public QObject, public Dependency { @@ -45,7 +47,7 @@ public slots: signals: void domainChanged(const QString& domainHostname); void svoImportRequested(const QString& url); - void domainConnectionRefused(const QString& reason); + void domainConnectionRefused(const QString& reasonMessage, DomainHandler::ConnectionRefusedReason reason = DomainHandler::ConnectionRefusedReason::Unknown); private slots: WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 44ce63e6c6..08810010a6 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -355,34 +355,53 @@ void DomainHandler::processICEResponsePacket(QSharedPointer mes } } +bool DomainHandler::reasonSuggestsLogin(ConnectionRefusedReason reasonCode) { + switch (reasonCode) { + case ConnectionRefusedReason::LoginError: + case ConnectionRefusedReason::NotAuthorized: + return true; + + default: + case ConnectionRefusedReason::Unknown: + case ConnectionRefusedReason::ProtocolMismatch: + case ConnectionRefusedReason::TooManyUsers: + return false; + } + return false; +} + void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer message) { // Read deny reason from packet + ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown; quint16 reasonSize; message->readPrimitive(&reasonSize); - QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize)); + QString reasonMessage = QString::fromUtf8(message->readWithoutCopy(reasonSize)); // output to the log so the user knows they got a denied connection request // and check and signal for an access token so that we can make sure they are logged in - qCWarning(networking) << "The domain-server denied a connection request: " << reason; + qCWarning(networking) << "The domain-server denied a connection request: " << reasonMessage; qCWarning(networking) << "Make sure you are logged in."; - if (!_domainConnectionRefusals.contains(reason)) { - _domainConnectionRefusals.append(reason); - emit domainConnectionRefused(reason); + if (!_domainConnectionRefusals.contains(reasonMessage)) { + _domainConnectionRefusals.append(reasonMessage); + emit domainConnectionRefused(reasonMessage, reasonCode); } auto accountManager = DependencyManager::get(); - if (!_hasCheckedForAccessToken) { - accountManager->checkAndSignalForAccessToken(); - _hasCheckedForAccessToken = true; - } + // Some connection refusal reasons imply that a login is required. If so, suggest a new login + if (reasonSuggestsLogin(reasonCode)) { + if (!_hasCheckedForAccessToken) { + accountManager->checkAndSignalForAccessToken(); + _hasCheckedForAccessToken = true; + } - static const int CONNECTION_DENIALS_FOR_KEYPAIR_REGEN = 3; + static const int CONNECTION_DENIALS_FOR_KEYPAIR_REGEN = 3; - // force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts - if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) { - accountManager->generateNewUserKeypair(); - _connectionDenialsSinceKeypairRegen = 0; + // force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts + if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) { + accountManager->generateNewUserKeypair(); + _connectionDenialsSinceKeypairRegen = 0; + } } } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 03141d8fef..4d8505e549 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -84,6 +84,15 @@ public: bool isSocketKnown() const { return !_sockAddr.getAddress().isNull(); } void softReset(); + + enum class ConnectionRefusedReason : uint8_t { + Unknown, + ProtocolMismatch, + LoginError, + NotAuthorized, + TooManyUsers + }; + public slots: void setHostnameAndPort(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT); void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id); @@ -115,9 +124,10 @@ signals: void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); - void domainConnectionRefused(QString reason); + void domainConnectionRefused(QString reasonMessage, ConnectionRefusedReason reason = ConnectionRefusedReason::Unknown); private: + bool reasonSuggestsLogin(ConnectionRefusedReason reasonCode); void sendDisconnectPacket(); void hardReset(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2c10d0627e..714b69fd89 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -162,13 +162,17 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { } bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) { + //qDebug() << __FUNCTION__; return packetVersionMatch(packet) && packetSourceAndHashMatch(packet); } bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { + PacketType headerType = NLPacket::typeInHeader(packet); PacketVersion headerVersion = NLPacket::versionInHeader(packet); + //qDebug() << __FUNCTION__ << "headerType:" << headerType << "version:" << (int)headerVersion; + if (headerVersion != versionForPacketType(headerType)) { static QMultiHash sourcedVersionDebugSuppressMap; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 0cbe9668b3..3b648a138b 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -221,6 +221,10 @@ public: void setConnectionMaxBandwidth(int maxBandwidth) { _nodeSocket.setConnectionMaxBandwidth(maxBandwidth); } + void setPacketFilterOperator(udt::PacketFilterOperator filterOperator) { _nodeSocket.setPacketFilterOperator(filterOperator); } + bool packetVersionMatch(const udt::Packet& packet); + bool isPacketVerified(const udt::Packet& packet); + public slots: void reset(); void eraseAllNodes(); @@ -267,8 +271,6 @@ protected: void setLocalSocket(const HifiSockAddr& sockAddr); - bool isPacketVerified(const udt::Packet& packet); - bool packetVersionMatch(const udt::Packet& packet); bool packetSourceAndHashMatch(const udt::Packet& packet); void processSTUNResponse(std::unique_ptr packet); diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 575a2c7a9c..93f8659663 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -24,8 +24,8 @@ int NLPacket::maxPayloadSize(PacketType type, bool isPartOfMessage) { return Packet::maxPayloadSize(isPartOfMessage) - NLPacket::localHeaderSize(type); } -std::unique_ptr NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) { - auto packet = std::unique_ptr(new NLPacket(type, size, isReliable, isPartOfMessage)); +std::unique_ptr NLPacket::create(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage, PacketVersion version) { + auto packet = std::unique_ptr(new NLPacket(type, size, isReliable, isPartOfMessage, version)); packet->open(QIODevice::ReadWrite); @@ -61,13 +61,12 @@ std::unique_ptr NLPacket::createCopy(const NLPacket& other) { return std::unique_ptr(new NLPacket(other)); } -NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage) : +NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfMessage, PacketVersion version) : Packet((size == -1) ? -1 : NLPacket::localHeaderSize(type) + size, isReliable, isPartOfMessage), _type(type), - _version(versionForPacketType(type)) + _version((version == 0) ? versionForPacketType(type) : version) { adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type)); - writeTypeAndVersion(); } diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 4527094322..f49f8498a5 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -38,7 +38,7 @@ public: sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; static std::unique_ptr create(PacketType type, qint64 size = -1, - bool isReliable = false, bool isPartOfMessage = false); + bool isReliable = false, bool isPartOfMessage = false, PacketVersion version = 0); static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); @@ -73,7 +73,7 @@ public: protected: - NLPacket(PacketType type, qint64 size = -1, bool forceReliable = false, bool isPartOfMessage = false); + NLPacket(PacketType type, qint64 size = -1, bool forceReliable = false, bool isPartOfMessage = false, PacketVersion version = 0); NLPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); NLPacket(const NLPacket& other); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index c295ffc700..50677908a5 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -292,7 +292,9 @@ void NodeList::sendDomainServerCheckIn() { return; } - auto domainPacket = NLPacket::create(domainPacketType); + auto packetVersion = (domainPacketType == PacketType::DomainConnectRequest) ? _domainConnectRequestVersion : 0; + //qDebug() << __FUNCTION__ << " NLPacket::create() version:" << (int)packetVersion; + auto domainPacket = NLPacket::create(domainPacketType, -1, false, false, packetVersion); QDataStream packetStream(domainPacket.get()); @@ -312,12 +314,28 @@ void NodeList::sendDomainServerCheckIn() { // pack the connect UUID for this connect request packetStream << connectUUID; + + // include the protocol version signature in our connect request + if (_domainConnectRequestVersion >= static_cast(DomainConnectRequestVersion::HasProtocolVersions)) { + QByteArray protocolVersionSig = protocolVersionsSignature(); + packetStream.writeBytes(protocolVersionSig.constData(), protocolVersionSig.size()); + //qDebug() << __FUNCTION__ << " including protocol version --------------------------"; + } else { + //qDebug() << __FUNCTION__ << "_domainConnectRequestVersion less than HasProtocolVersions - not including protocol version"; + } + } else { + //qDebug() << __FUNCTION__ << "NOT a DomainConnnectRequest ----------- not including checkin details -------"; } // pack our data to send to the domain-server including // the hostname information (so the domain-server can see which place name we came in on) - packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList() - << DependencyManager::get()->getPlaceName(); + packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList(); + if (_domainConnectRequestVersion >= static_cast(DomainConnectRequestVersion::HasHostname)) { + packetStream << DependencyManager::get()->getPlaceName(); + //qDebug() << __FUNCTION__ << " including host name --------------------------"; + } else { + //qDebug() << __FUNCTION__ << "_domainConnectRequestVersion less than HasHostname - not including host name"; + } if (!_domainHandler.isConnected()) { DataServerAccountInfo& accountInfo = accountManager->getAccountInfo(); @@ -345,6 +363,7 @@ void NodeList::sendDomainServerCheckIn() { // increment the count of un-replied check-ins _numNoReplyDomainCheckIns++; + //qDebug() << __FUNCTION__ << " _numNoReplyDomainCheckIns:" << _numNoReplyDomainCheckIns << " --------------------------"; } } @@ -504,15 +523,22 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer message) { + //qDebug() << __FUNCTION__; + if (_domainHandler.getSockAddr().isNull()) { // refuse to process this packet if we aren't currently connected to the DS return; } + //qDebug() << __FUNCTION__ << "_numNoReplyDomainCheckIns:" << _numNoReplyDomainCheckIns; + // this is a packet from the domain server, reset the count of un-replied check-ins _numNoReplyDomainCheckIns = 0; + //qDebug() << __FUNCTION__ << "RESET.... _numNoReplyDomainCheckIns:" << _numNoReplyDomainCheckIns; + // emit our signal so listeners know we just heard from the DS + //qDebug() << __FUNCTION__ << "about to emit receivedDomainServerList() -----------------------------------------------"; emit receivedDomainServerList(); DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 4b196d5f7b..3158262c87 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -68,6 +68,13 @@ public: void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; } + /// downgrades the DomainConnnectRequest PacketVersion to attempt to probe for older domain servers + void downgradeDomainServerCheckInVersion() { + qDebug() << __FUNCTION__ << "----------------------------------------------------------"; + _domainConnectRequestVersion--; + + } + public slots: void reset(); void sendDomainServerCheckIn(); @@ -85,6 +92,12 @@ public slots: void processICEPingPacket(QSharedPointer message); + void resetDomainServerCheckInVersion() + { + qDebug() << __FUNCTION__ << "----------------------------------------------------------"; + _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); + } + signals: void limitOfSilentDomainCheckInsReached(); void receivedDomainServerList(); @@ -123,6 +136,8 @@ private: HifiSockAddr _assignmentServerSocket; bool _isShuttingDown { false }; QTimer _keepAlivePingTimer; + + PacketVersion _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); }; #endif // hifi_NodeList_h diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 530efc5fb3..cb47625d6d 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -309,22 +309,29 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(SharedNodePointer, matchingNode)); - + + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; + } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { success = metaMethod.invoke(listener.object, connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(QSharedPointer, matchingNode)); - + + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; + } else { success = metaMethod.invoke(listener.object, connectionType, Q_ARG(QSharedPointer, receivedMessage)); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } } else { listenerIsDead = true; } } else { + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "Got verified unsourced packet list." << "packetType:" << packetType; + // qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage()); emit dataReceived(NodeType::Unassigned, receivedMessage->getSize()); @@ -332,6 +339,8 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei if (listener.object) { success = listener.method.invoke(listener.object, Q_ARG(QSharedPointer, receivedMessage)); + + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } else { listenerIsDead = true; } diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index b04d582d6d..72875322f6 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -12,7 +12,9 @@ #include "PacketHeaders.h" #include +#include +#include #include #include @@ -58,9 +60,13 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::AssetUpload: // Removal of extension from Asset requests return 18; + + case PacketType::DomainConnectionDenied: + return static_cast(DomainConnectionDeniedVersion::IncludesReasonCode); + case PacketType::DomainConnectRequest: - // addition of referring hostname information - return 18; + return static_cast(DomainConnectRequestVersion::HasProtocolVersions); + default: return 17; } @@ -80,3 +86,36 @@ QDebug operator<<(QDebug debug, const PacketType& type) { debug.nospace().noquote() << (uint8_t) type << " (" << typeName << ")"; return debug.space(); } + +#if (PR_BUILD || DEV_BUILD) +static bool sendWrongProtocolVersion = false; +void sendWrongProtocolVersionsSignature(bool sendWrongVersion) { + sendWrongProtocolVersion = sendWrongVersion; +} +#endif + +QByteArray protocolVersionsSignature() { + static QByteArray protocolVersionSignature; + static std::once_flag once; + std::call_once(once, [&] { + QByteArray buffer; + QDataStream stream(&buffer, QIODevice::WriteOnly); + uint8_t numberOfProtocols = static_cast(PacketType::LAST_PACKET_TYPE) + 1; + stream << numberOfProtocols; + for (uint8_t packetType = 0; packetType < numberOfProtocols; packetType++) { + uint8_t packetTypeVersion = static_cast(versionForPacketType(static_cast(packetType))); + stream << packetTypeVersion; + } + QCryptographicHash hash(QCryptographicHash::Md5); + hash.addData(buffer); + protocolVersionSignature = hash.result(); + }); + + #if (PR_BUILD || DEV_BUILD) + if (sendWrongProtocolVersion) { + return QByteArray("INCORRECTVERSION"); // only for debugging version checking + } + #endif + + return protocolVersionSignature; +} diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 030b4af8c9..b6237e74d6 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -61,7 +61,7 @@ public: AssignmentClientStatus, NoisyMute, AvatarIdentity, - AvatarBillboard, + TYPE_UNUSED_1, DomainConnectRequest, DomainServerRequireDTLS, NodeJsonStats, @@ -94,7 +94,8 @@ public: ICEServerHeartbeatDenied, AssetMappingOperation, AssetMappingOperationReply, - ICEServerHeartbeatACK + ICEServerHeartbeatACK, + LAST_PACKET_TYPE = ICEServerHeartbeatACK }; }; @@ -109,6 +110,11 @@ extern const QSet NON_SOURCED_PACKETS; extern const QSet RELIABLE_PACKETS; PacketVersion versionForPacketType(PacketType packetType); +QByteArray protocolVersionsSignature(); /// returns a unqiue signature for all the current protocols + +#if (PR_BUILD || DEV_BUILD) +void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debugging version negotiation +#endif uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); @@ -179,4 +185,15 @@ enum class AvatarMixerPacketVersion : PacketVersion { AvatarEntities }; +enum class DomainConnectRequestVersion : PacketVersion { + NoHostname = 17, + HasHostname, + HasProtocolVersions +}; + +enum class DomainConnectionDeniedVersion : PacketVersion { + ReasonMessageOnly = 17, + IncludesReasonCode +}; + #endif // hifi_PacketHeaders_h From 12a1857280f835db093cd12ece0cd1583d43520b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 15:20:11 -0700 Subject: [PATCH 38/59] check point with protocol refusal working --- domain-server/src/DomainGatekeeper.cpp | 17 +++++++- interface/src/Application.cpp | 13 +++++- interface/src/Application.h | 1 + .../src/scripting/WindowScriptingInterface.h | 2 +- libraries/networking/src/DomainHandler.cpp | 41 ++++++++++++++++--- libraries/networking/src/DomainHandler.h | 2 +- libraries/networking/src/PacketReceiver.cpp | 10 ++--- 7 files changed, 72 insertions(+), 14 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 9d5ee75818..80137935ca 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -548,12 +548,27 @@ void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const H quint16 payloadSize = utfString.size(); // setup the DomainConnectionDenied packet - auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, payloadSize + sizeof(payloadSize)); + auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied); // , payloadSize + sizeof(payloadSize) // pack in the reason the connection was denied (the client displays this) if (payloadSize > 0) { + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); + qDebug() << __FUNCTION__ << "about to write reasonCode:" << (int)reasonCode; + uint8_t reasonCodeWire = (uint8_t)reasonCode; + qDebug() << __FUNCTION__ << "about to write reasonCodeWire:" << (int)reasonCodeWire; + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); + connectionDeniedPacket->writePrimitive(reasonCodeWire); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); + qDebug() << __FUNCTION__ << "about to write payloadSize:" << payloadSize; + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); connectionDeniedPacket->writePrimitive(payloadSize); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); + qDebug() << __FUNCTION__ << "about to write utfString:" << utfString; + qDebug() << __FUNCTION__ << "about to write utfString.size():" << utfString.size(); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); connectionDeniedPacket->write(utfString); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); + } // send the packet off diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eca3ecc679..58a273737c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -630,8 +630,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); - connect(&domainHandler, &DomainHandler::resetting, nodeList.data(), &NodeList::resetDomainServerCheckInVersion); + connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SECOND; @@ -1068,6 +1068,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : firstRun.set(false); } +void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCode) { + qDebug() << __FUNCTION__ << "message:" << reasonMessage << "code:" << reasonCode; + qDebug() << __FUNCTION__ << "DomainHandler::ConnectionRefusedReason::ProtocolMismatch:" << (int)DomainHandler::ConnectionRefusedReason::ProtocolMismatch; + + if (static_cast(reasonCode) == DomainHandler::ConnectionRefusedReason::ProtocolMismatch) { + qDebug() << __FUNCTION__ << " PROTOCOL MISMATCH!!!"; + notifyPacketVersionMismatch(); + } +} + + QString Application::getUserAgent() { if (QThread::currentThread() != thread()) { QString userAgent; diff --git a/interface/src/Application.h b/interface/src/Application.h index edb69eb2ad..69f48e9541 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -330,6 +330,7 @@ private slots: static void packetSent(quint64 length); void updateDisplayMode(); void updateInputModes(); + void domainConnectionRefused(const QString& reasonMessage, int reason); private: static void initDisplay(); diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 145d17faaf..72f4ccd866 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -47,7 +47,7 @@ public slots: signals: void domainChanged(const QString& domainHostname); void svoImportRequested(const QString& url); - void domainConnectionRefused(const QString& reasonMessage, DomainHandler::ConnectionRefusedReason reason = DomainHandler::ConnectionRefusedReason::Unknown); + void domainConnectionRefused(const QString& reasonMessage, int reason); private slots: WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index d80d4e76fd..67a41c866a 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -103,7 +103,9 @@ void DomainHandler::hardReset() { _sockAddr.clear(); _hasCheckedForAccessToken = false; - _domainConnectionRefusals.clear(); + + //qDebug() << __FUNCTION__ << "about to call _domainConnectionRefusals.clear();"; + //_domainConnectionRefusals.clear(); // clear any pending path we may have wanted to ask the previous DS about _pendingPath.clear(); @@ -142,6 +144,10 @@ void DomainHandler::setSocketAndID(const QString& hostname, quint16 port, const // set the new hostname _hostname = hostname; + // FIXME - is this the right place??? + qDebug() << __FUNCTION__ << "about to call _domainConnectionRefusals.clear();"; + _domainConnectionRefusals.clear(); + qCDebug(networking) << "Updated domain hostname to" << _hostname; // re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname @@ -366,25 +372,50 @@ bool DomainHandler::reasonSuggestsLogin(ConnectionRefusedReason reasonCode) { void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer message) { // Read deny reason from packet - ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown; + uint8_t reasonCodeWire; + + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); + message->readPrimitive(&reasonCodeWire); + qDebug() << __FUNCTION__ << "reasonCodeWire:" << reasonCodeWire; + ConnectionRefusedReason reasonCode = static_cast(reasonCodeWire); + qDebug() << __FUNCTION__ << "reasonCode:" << (int)reasonCode; + + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); + quint16 reasonSize; message->readPrimitive(&reasonSize); - QString reasonMessage = QString::fromUtf8(message->readWithoutCopy(reasonSize)); + qDebug() << __FUNCTION__ << "reasonSize:" << reasonSize; + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); + auto reasonText = message->readWithoutCopy(reasonSize); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "reasonText:" << reasonText; + QString reasonMessage = QString::fromUtf8(reasonText); + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "reasonMessage:" << reasonMessage; + + qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); // output to the log so the user knows they got a denied connection request // and check and signal for an access token so that we can make sure they are logged in qCWarning(networking) << "The domain-server denied a connection request: " << reasonMessage; - qCWarning(networking) << "Make sure you are logged in."; + + qDebug(networking) << "_domainConnectionRefusals:" << _domainConnectionRefusals; if (!_domainConnectionRefusals.contains(reasonMessage)) { + qDebug(networking) << "about to call _domainConnectionRefusals.append(reasonMessage);"; _domainConnectionRefusals.append(reasonMessage); - emit domainConnectionRefused(reasonMessage, reasonCode); + qDebug(networking) << "_domainConnectionRefusals:" << _domainConnectionRefusals; + + + emit domainConnectionRefused(reasonMessage, (int)reasonCode); + } else { + qDebug(networking) << "ALREADY EMITTED domainConnectionRefused() ----------------------------"; } auto accountManager = DependencyManager::get(); // Some connection refusal reasons imply that a login is required. If so, suggest a new login if (reasonSuggestsLogin(reasonCode)) { + qCWarning(networking) << "Make sure you are logged in."; + if (!_hasCheckedForAccessToken) { accountManager->checkAndSignalForAccessToken(); _hasCheckedForAccessToken = true; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 41a3e544f6..226186f1d0 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -124,7 +124,7 @@ signals: void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); - void domainConnectionRefused(QString reasonMessage, ConnectionRefusedReason reason = ConnectionRefusedReason::Unknown); + void domainConnectionRefused(QString reasonMessage, int reason); private: bool reasonSuggestsLogin(ConnectionRefusedReason reasonCode); diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index cb47625d6d..8df9a1038a 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -310,7 +310,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei Q_ARG(QSharedPointer, receivedMessage), Q_ARG(SharedNodePointer, matchingNode)); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; + //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { success = metaMethod.invoke(listener.object, @@ -318,19 +318,19 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei Q_ARG(QSharedPointer, receivedMessage), Q_ARG(QSharedPointer, matchingNode)); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; + //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } else { success = metaMethod.invoke(listener.object, connectionType, Q_ARG(QSharedPointer, receivedMessage)); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; + //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } } else { listenerIsDead = true; } } else { - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "Got verified unsourced packet list." << "packetType:" << packetType; + //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "Got verified unsourced packet list." << "packetType:" << packetType; // qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage()); emit dataReceived(NodeType::Unassigned, receivedMessage->getSize()); @@ -340,7 +340,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei success = listener.method.invoke(listener.object, Q_ARG(QSharedPointer, receivedMessage)); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; + //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } else { listenerIsDead = true; } From b9aa667c558be8c59dc58667d8656a696d5902f8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 May 2016 10:37:30 +1200 Subject: [PATCH 39/59] Fix QML test environment --- tests/ui/qml/main.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml index 1745658193..97f0c0a613 100644 --- a/tests/ui/qml/main.qml +++ b/tests/ui/qml/main.qml @@ -23,14 +23,17 @@ ApplicationWindow { Desktop { id: desktop anchors.fill: parent - rootMenu: StubMenu { id: rootMenu } + + //rootMenu: StubMenu { id: rootMenu } //Component.onCompleted: offscreenWindow = appWindow + /* MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: desktop.popupMenu(Qt.vector2d(mouseX, mouseY)); } + */ Row { id: testButtons From 2eef07e414854815b17ef8a155ea5dce9939dae9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 15:38:08 -0700 Subject: [PATCH 40/59] cleanup and dead code removal --- domain-server/src/DomainGatekeeper.cpp | 26 +------------------ domain-server/src/DomainServer.cpp | 13 +--------- domain-server/src/NodeConnectionData.cpp | 5 ++-- interface/src/Application.cpp | 13 ---------- interface/src/Application.h | 4 +-- .../src/scripting/WindowScriptingInterface.h | 4 +-- libraries/networking/src/DomainHandler.cpp | 24 ----------------- libraries/networking/src/LimitedNodeList.cpp | 4 --- libraries/networking/src/NLPacket.cpp | 1 + libraries/networking/src/NodeList.cpp | 17 ------------ libraries/networking/src/NodeList.h | 13 +++------- libraries/networking/src/PacketReceiver.cpp | 11 -------- 12 files changed, 11 insertions(+), 124 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 80137935ca..bc89b99e8a 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -55,10 +55,6 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetSize() == 0) { return; } - - //qDebug() << __FUNCTION__ << "packetVersion:" << message->getVersion(); - - QDataStream packetStream(message->getMessage()); // read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it @@ -72,8 +68,6 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetSenderSockAddr(); @@ -548,27 +537,14 @@ void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const H quint16 payloadSize = utfString.size(); // setup the DomainConnectionDenied packet - auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied); // , payloadSize + sizeof(payloadSize) + auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied); // pack in the reason the connection was denied (the client displays this) if (payloadSize > 0) { - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); - qDebug() << __FUNCTION__ << "about to write reasonCode:" << (int)reasonCode; uint8_t reasonCodeWire = (uint8_t)reasonCode; - qDebug() << __FUNCTION__ << "about to write reasonCodeWire:" << (int)reasonCodeWire; - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); connectionDeniedPacket->writePrimitive(reasonCodeWire); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); - qDebug() << __FUNCTION__ << "about to write payloadSize:" << payloadSize; - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); connectionDeniedPacket->writePrimitive(payloadSize); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); - qDebug() << __FUNCTION__ << "about to write utfString:" << utfString; - qDebug() << __FUNCTION__ << "about to write utfString.size():" << utfString.size(); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); connectionDeniedPacket->write(utfString); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "connectionDeniedPacket->getDataSize():" << connectionDeniedPacket->getDataSize(); - } // send the packet off diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 18ca7e2941..f6fbb3f470 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -309,8 +309,6 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { PacketType headerType = NLPacket::typeInHeader(packet); PacketVersion headerVersion = NLPacket::versionInHeader(packet); - //qDebug() << __FUNCTION__ << "type:" << headerType << "version:" << (int)headerVersion; - auto nodeList = DependencyManager::get(); // This implements a special case that handles OLD clients which don't know how to negotiate matching @@ -320,9 +318,6 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { // warn the user that the protocol is not compatible if (headerType == PacketType::DomainConnectRequest && headerVersion < static_cast(DomainConnectRequestVersion::HasProtocolVersions)) { - - //qDebug() << __FUNCTION__ << "OLD VERSION checkin sending an intentional bad packet -------------------------------"; - auto packetWithBadVersion = NLPacket::create(PacketType::EntityData); nodeList->sendPacket(std::move(packetWithBadVersion), packet.getSenderSockAddr()); return false; @@ -407,8 +402,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { // add whatever static assignments that have been parsed to the queue addStaticAssignmentsToQueue(); - // set packetVersionMatch as the verify packet operator for the udt::Socket - //using std::placeholders::_1; + // set a custum packetVersionMatch as the verify packet operator for the udt::Socket nodeList->setPacketFilterOperator(&DomainServer::packetVersionMatch); } @@ -701,8 +695,6 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet message, SharedNodePointer sendingNode) { - //qDebug() << __FUNCTION__ << "---------------"; - QDataStream packetStream(message->getMessage()); NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false); @@ -782,9 +774,6 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode) { } void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr) { - - //qDebug() << __FUNCTION__ << "---------------"; - const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NUM_BYTES_RFC4122_UUID + 2; // setup the extended header for the domain list packets diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index 5ddcbf1792..13bb9123d8 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -24,10 +24,11 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c char* rawBytes; uint length; - // FIXME -- do we need to delete the rawBytes after it's been copied into the QByteArray? dataStream.readBytes(rawBytes, length); newHeader.protocolVersion = QByteArray(rawBytes, length); - //qDebug() << __FUNCTION__ << "...got protocol version from node... version:" << newHeader.protocolVersion; + + // NOTE: QDataStream::readBytes() - The buffer is allocated using new []. Destroy it with the delete [] operator. + delete[] rawBytes; } dataStream >> newHeader.nodeType diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58a273737c..bf897015f8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -654,11 +654,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated); connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); - connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, this, &Application::limitOfSilentDomainCheckInsReached); - //connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); - - connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); // connect to appropriate slots on AccountManager @@ -1069,16 +1065,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCode) { - qDebug() << __FUNCTION__ << "message:" << reasonMessage << "code:" << reasonCode; - qDebug() << __FUNCTION__ << "DomainHandler::ConnectionRefusedReason::ProtocolMismatch:" << (int)DomainHandler::ConnectionRefusedReason::ProtocolMismatch; - if (static_cast(reasonCode) == DomainHandler::ConnectionRefusedReason::ProtocolMismatch) { - qDebug() << __FUNCTION__ << " PROTOCOL MISMATCH!!!"; notifyPacketVersionMismatch(); } } - QString Application::getUserAgent() { if (QThread::currentThread() != thread()) { QString userAgent; @@ -4595,12 +4586,8 @@ void Application::setSessionUUID(const QUuid& sessionUUID) const { // We won't actually complete the connection, but if the server responds, we know that it needs to be upgraded (or we // need to be downgraded to talk to it). void Application::limitOfSilentDomainCheckInsReached() { - //qDebug() << __FUNCTION__; - auto nodeList = DependencyManager::get(); - nodeList->downgradeDomainServerCheckInVersion(); // attempt to use an older domain checkin version - nodeList->reset(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 69f48e9541..a17250a58e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -262,9 +262,7 @@ public slots: void setActiveFaceTracker() const; #if (PR_BUILD || DEV_BUILD) - void sendWrongProtocolVersionsSignature(bool checked) { - ::sendWrongProtocolVersionsSignature(checked); - } + void sendWrongProtocolVersionsSignature(bool checked) { ::sendWrongProtocolVersionsSignature(checked); } #endif #ifdef HAVE_IVIEWHMD diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 72f4ccd866..dfe02a5064 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -16,8 +16,6 @@ #include #include -#include - class WebWindowClass; class WindowScriptingInterface : public QObject, public Dependency { @@ -47,7 +45,7 @@ public slots: signals: void domainChanged(const QString& domainHostname); void svoImportRequested(const QString& url); - void domainConnectionRefused(const QString& reasonMessage, int reason); + void domainConnectionRefused(const QString& reasonMessage, int reasonCode); private slots: WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 67a41c866a..1efcfc7f27 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -104,9 +104,6 @@ void DomainHandler::hardReset() { _hasCheckedForAccessToken = false; - //qDebug() << __FUNCTION__ << "about to call _domainConnectionRefusals.clear();"; - //_domainConnectionRefusals.clear(); - // clear any pending path we may have wanted to ask the previous DS about _pendingPath.clear(); } @@ -145,7 +142,6 @@ void DomainHandler::setSocketAndID(const QString& hostname, quint16 port, const _hostname = hostname; // FIXME - is this the right place??? - qDebug() << __FUNCTION__ << "about to call _domainConnectionRefusals.clear();"; _domainConnectionRefusals.clear(); qCDebug(networking) << "Updated domain hostname to" << _hostname; @@ -374,40 +370,20 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointergetPosition():" << message->getPosition(); message->readPrimitive(&reasonCodeWire); - qDebug() << __FUNCTION__ << "reasonCodeWire:" << reasonCodeWire; ConnectionRefusedReason reasonCode = static_cast(reasonCodeWire); - qDebug() << __FUNCTION__ << "reasonCode:" << (int)reasonCode; - - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); - quint16 reasonSize; message->readPrimitive(&reasonSize); - qDebug() << __FUNCTION__ << "reasonSize:" << reasonSize; - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); auto reasonText = message->readWithoutCopy(reasonSize); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "reasonText:" << reasonText; QString reasonMessage = QString::fromUtf8(reasonText); - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "reasonMessage:" << reasonMessage; - - qDebug() << __FUNCTION__ << "line:" << __LINE__ << "message->getPosition():" << message->getPosition(); // output to the log so the user knows they got a denied connection request // and check and signal for an access token so that we can make sure they are logged in qCWarning(networking) << "The domain-server denied a connection request: " << reasonMessage; - qDebug(networking) << "_domainConnectionRefusals:" << _domainConnectionRefusals; - if (!_domainConnectionRefusals.contains(reasonMessage)) { - qDebug(networking) << "about to call _domainConnectionRefusals.append(reasonMessage);"; _domainConnectionRefusals.append(reasonMessage); - qDebug(networking) << "_domainConnectionRefusals:" << _domainConnectionRefusals; - - emit domainConnectionRefused(reasonMessage, (int)reasonCode); - } else { - qDebug(networking) << "ALREADY EMITTED domainConnectionRefused() ----------------------------"; } auto accountManager = DependencyManager::get(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 714b69fd89..2c10d0627e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -162,17 +162,13 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { } bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) { - //qDebug() << __FUNCTION__; return packetVersionMatch(packet) && packetSourceAndHashMatch(packet); } bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { - PacketType headerType = NLPacket::typeInHeader(packet); PacketVersion headerVersion = NLPacket::versionInHeader(packet); - //qDebug() << __FUNCTION__ << "headerType:" << headerType << "version:" << (int)headerVersion; - if (headerVersion != versionForPacketType(headerType)) { static QMultiHash sourcedVersionDebugSuppressMap; diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 93f8659663..34a159ae6c 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -67,6 +67,7 @@ NLPacket::NLPacket(PacketType type, qint64 size, bool isReliable, bool isPartOfM _version((version == 0) ? versionForPacketType(type) : version) { adjustPayloadStartAndCapacity(NLPacket::localHeaderSize(_type)); + writeTypeAndVersion(); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 5f3f34dafb..082200fccc 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -293,7 +293,6 @@ void NodeList::sendDomainServerCheckIn() { } auto packetVersion = (domainPacketType == PacketType::DomainConnectRequest) ? _domainConnectRequestVersion : 0; - //qDebug() << __FUNCTION__ << " NLPacket::create() version:" << (int)packetVersion; auto domainPacket = NLPacket::create(domainPacketType, -1, false, false, packetVersion); QDataStream packetStream(domainPacket.get()); @@ -319,12 +318,7 @@ void NodeList::sendDomainServerCheckIn() { if (_domainConnectRequestVersion >= static_cast(DomainConnectRequestVersion::HasProtocolVersions)) { QByteArray protocolVersionSig = protocolVersionsSignature(); packetStream.writeBytes(protocolVersionSig.constData(), protocolVersionSig.size()); - //qDebug() << __FUNCTION__ << " including protocol version --------------------------"; - } else { - //qDebug() << __FUNCTION__ << "_domainConnectRequestVersion less than HasProtocolVersions - not including protocol version"; } - } else { - //qDebug() << __FUNCTION__ << "NOT a DomainConnnectRequest ----------- not including checkin details -------"; } // pack our data to send to the domain-server including @@ -332,9 +326,6 @@ void NodeList::sendDomainServerCheckIn() { packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList(); if (_domainConnectRequestVersion >= static_cast(DomainConnectRequestVersion::HasHostname)) { packetStream << DependencyManager::get()->getPlaceName(); - //qDebug() << __FUNCTION__ << " including host name --------------------------"; - } else { - //qDebug() << __FUNCTION__ << "_domainConnectRequestVersion less than HasHostname - not including host name"; } if (!_domainHandler.isConnected()) { @@ -363,7 +354,6 @@ void NodeList::sendDomainServerCheckIn() { // increment the count of un-replied check-ins _numNoReplyDomainCheckIns++; - //qDebug() << __FUNCTION__ << " _numNoReplyDomainCheckIns:" << _numNoReplyDomainCheckIns << " --------------------------"; } if (!_publicSockAddr.isNull() && !_domainHandler.isConnected() && !_domainHandler.getPendingDomainID().isNull()) { @@ -531,22 +521,15 @@ void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer message) { - //qDebug() << __FUNCTION__; - if (_domainHandler.getSockAddr().isNull()) { // refuse to process this packet if we aren't currently connected to the DS return; } - //qDebug() << __FUNCTION__ << "_numNoReplyDomainCheckIns:" << _numNoReplyDomainCheckIns; - // this is a packet from the domain server, reset the count of un-replied check-ins _numNoReplyDomainCheckIns = 0; - //qDebug() << __FUNCTION__ << "RESET.... _numNoReplyDomainCheckIns:" << _numNoReplyDomainCheckIns; - // emit our signal so listeners know we just heard from the DS - //qDebug() << __FUNCTION__ << "about to emit receivedDomainServerList() -----------------------------------------------"; emit receivedDomainServerList(); DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 3158262c87..b269554e77 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -69,11 +69,7 @@ public: void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; } /// downgrades the DomainConnnectRequest PacketVersion to attempt to probe for older domain servers - void downgradeDomainServerCheckInVersion() { - qDebug() << __FUNCTION__ << "----------------------------------------------------------"; - _domainConnectRequestVersion--; - - } + void downgradeDomainServerCheckInVersion() { _domainConnectRequestVersion--; } public slots: void reset(); @@ -92,11 +88,8 @@ public slots: void processICEPingPacket(QSharedPointer message); - void resetDomainServerCheckInVersion() - { - qDebug() << __FUNCTION__ << "----------------------------------------------------------"; - _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); - } + void resetDomainServerCheckInVersion() + { _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); } signals: void limitOfSilentDomainCheckInsReached(); diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 8df9a1038a..9cbff8abbd 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -309,29 +309,20 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(SharedNodePointer, matchingNode)); - - //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; - } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { success = metaMethod.invoke(listener.object, connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(QSharedPointer, matchingNode)); - - //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; - } else { success = metaMethod.invoke(listener.object, connectionType, Q_ARG(QSharedPointer, receivedMessage)); - //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } } else { listenerIsDead = true; } } else { - //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "Got verified unsourced packet list." << "packetType:" << packetType; - // qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage()); emit dataReceived(NodeType::Unassigned, receivedMessage->getSize()); @@ -339,8 +330,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei if (listener.object) { success = listener.method.invoke(listener.object, Q_ARG(QSharedPointer, receivedMessage)); - - //qDebug() << __FUNCTION__ << "line:" << __LINE__ << "success:" << success << "packetType:" << packetType; } else { listenerIsDead = true; } From 0553ff5f9fc0c7edcbd24e0e4e1c6f14b6a7b561 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 15:41:11 -0700 Subject: [PATCH 41/59] cleanup and dead code removal --- libraries/networking/src/PacketReceiver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 9cbff8abbd..423e753ae0 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -309,11 +309,13 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(SharedNodePointer, matchingNode)); + } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { success = metaMethod.invoke(listener.object, connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(QSharedPointer, matchingNode)); + } else { success = metaMethod.invoke(listener.object, connectionType, From 3b0081fbbba9276029f5b37a8efc11ecfd03eaea Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 15:42:55 -0700 Subject: [PATCH 42/59] cleanup and dead code removal --- libraries/networking/src/PacketReceiver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 423e753ae0..87c77967a5 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -315,7 +315,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(QSharedPointer, matchingNode)); - + } else { success = metaMethod.invoke(listener.object, connectionType, From 5668db9e4a6f54e4971fe34f9abce516f365b867 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 15:43:30 -0700 Subject: [PATCH 43/59] cleanup and dead code removal --- libraries/networking/src/PacketReceiver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 87c77967a5..530efc5fb3 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -309,7 +309,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei connectionType, Q_ARG(QSharedPointer, receivedMessage), Q_ARG(SharedNodePointer, matchingNode)); - + } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { success = metaMethod.invoke(listener.object, connectionType, From 183f38e4f06c28fa69bcd4dfba5bcc4b669c3d65 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 16:07:57 -0700 Subject: [PATCH 44/59] pop up warning if domain over capacity --- domain-server/src/DomainGatekeeper.cpp | 4 ++-- interface/src/Application.cpp | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index bc89b99e8a..9023510214 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -443,10 +443,10 @@ bool DomainGatekeeper::isWithinMaxCapacity(const QString& username, const QByteA // find out what our maximum capacity is const QVariant* maximumUserCapacityVariant = valueForKeyPath(_server->_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY); unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0; - + if (maximumUserCapacity > 0) { unsigned int connectedUsers = _server->countConnectedUsers(); - + if (connectedUsers >= maximumUserCapacity) { // too many users, deny the new connection unless this user is an allowed editor diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bf897015f8..f3322caffb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1065,8 +1065,20 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCode) { - if (static_cast(reasonCode) == DomainHandler::ConnectionRefusedReason::ProtocolMismatch) { - notifyPacketVersionMismatch(); + switch (static_cast(reasonCode)) { + case DomainHandler::ConnectionRefusedReason::ProtocolMismatch: + notifyPacketVersionMismatch(); + break; + case DomainHandler::ConnectionRefusedReason::TooManyUsers: + case DomainHandler::ConnectionRefusedReason::Unknown: { + QString message = "Unable to connect to the location you are visiting.\n"; + message += reasonMessage; + OffscreenUi::warning("", message); + break; + } + default: + // nothing to do. + break; } } From a3f1ece978987b203b50e438628b417fdfa1823e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 24 May 2016 16:10:12 -0700 Subject: [PATCH 45/59] Do button mapping in C++ and simplify vive.json accordingly. Vive and Hydra now use PrimaryThumb and SecondaryThumb. Fix warnings for Neuron. --- interface/resources/controllers/hydra.json | 10 +++---- interface/resources/controllers/neuron.json | 4 +-- interface/resources/controllers/vive.json | 10 ++++--- .../src/controllers/StandardControls.h | 4 +++ plugins/openvr/src/ViveControllerManager.cpp | 22 ++++++++++++++- plugins/openvr/src/ViveControllerManager.h | 1 + .../controllers/handControllerPointer.js | 28 +++---------------- 7 files changed, 42 insertions(+), 37 deletions(-) diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index 8233685763..066676140c 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -16,12 +16,10 @@ { "from": "Hydra.L0", "to": "Standard.Back" }, { "from": "Hydra.R0", "to": "Standard.Start" }, - { "from": [ "Hydra.L1", "Hydra.L2" ], "to": "Standard.LeftPrimaryThumb" }, - { "from": [ "Hydra.R1", "Hydra.R2" ], "to": "Standard.RightPrimaryThumb" }, - { "from": [ "Hydra.L3" ], "to": "Standard.L3" }, - { "from": [ "Hydra.R3" ], "to": "Standard.R3" }, - { "from": [ "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" }, - { "from": [ "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" }, + { "from": [ "Hydra.L1", "Hydra.L3" ], "to": "Standard.LeftPrimaryThumb" }, + { "from": [ "Hydra.R1", "Hydra.R3" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.R2", "Hydra.R4" ], "to": "Standard.RightSecondaryThumb" }, + { "from": [ "Hydra.L2", "Hydra.L4" ], "to": "Standard.LeftSecondaryThumb" }, { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Hydra.RightHand", "to": "Standard.RightHand" } diff --git a/interface/resources/controllers/neuron.json b/interface/resources/controllers/neuron.json index 2d61f80c35..d0962c72db 100644 --- a/interface/resources/controllers/neuron.json +++ b/interface/resources/controllers/neuron.json @@ -1,7 +1,7 @@ { "name": "Neuron to Standard", "channels": [ - { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, - { "from": "Hydra.RightHand", "to": "Standard.RightHand" } + { "from": "Neuron.LeftHand", "to": "Standard.LeftHand" }, + { "from": "Neuron.RightHand", "to": "Standard.RightHand" } ] } diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index fec93c9132..60a46ba3ce 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -1,23 +1,25 @@ { "name": "Vive to Standard", "channels": [ - { "from": "Vive.LY", "when": "Vive.LS", "filters": ["invert" ,{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LY" }, - { "from": "Vive.LX", "when": "Vive.LS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LX" }, + { "from": "Vive.LY", "when": "Vive.LSOuter", "filters": ["invert"], "to": "Standard.LY" }, + { "from": "Vive.LX", "when": "Vive.LSOuter", "to": "Standard.LX" }, { "from": "Vive.LT", "to": "Standard.LT" }, { "from": "Vive.LeftGrip", "to": "Standard.LB" }, { "from": "Vive.LS", "to": "Standard.LS" }, { "from": "Vive.LSTouch", "to": "Standard.LSTouch" }, - { "from": "Vive.RY", "when": "Vive.RS", "filters": ["invert", { "type": "deadZone", "min": 0.6 }], "to": "Standard.RY" }, - { "from": "Vive.RX", "when": "Vive.RS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.RX" }, + { "from": "Vive.RY", "when": "Vive.RSOuter", "filters": ["invert"], "to": "Standard.RY" }, + { "from": "Vive.RX", "when": "Vive.RSOuter", "to": "Standard.RX" }, { "from": "Vive.RT", "to": "Standard.RT" }, { "from": "Vive.RightGrip", "to": "Standard.RB" }, { "from": "Vive.RS", "to": "Standard.RS" }, { "from": "Vive.RSTouch", "to": "Standard.RSTouch" }, + { "from": "Vive.LSCenter", "to": "Standard.LeftPrimaryThumb" }, { "from": "Vive.LeftApplicationMenu", "to": "Standard.LeftSecondaryThumb" }, + { "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" }, { "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" }, { "from": "Vive.LeftHand", "to": "Standard.LeftHand" }, diff --git a/libraries/controllers/src/controllers/StandardControls.h b/libraries/controllers/src/controllers/StandardControls.h index f101ba6c51..79c23bc6ee 100644 --- a/libraries/controllers/src/controllers/StandardControls.h +++ b/libraries/controllers/src/controllers/StandardControls.h @@ -43,6 +43,8 @@ namespace controller { LEFT_SECONDARY_THUMB_TOUCH, LS_TOUCH, LEFT_THUMB_UP, + LS_CENTER, + LS_OUTER, RIGHT_PRIMARY_THUMB, RIGHT_SECONDARY_THUMB, @@ -50,6 +52,8 @@ namespace controller { RIGHT_SECONDARY_THUMB_TOUCH, RS_TOUCH, RIGHT_THUMB_UP, + RS_CENTER, + RS_OUTER, LEFT_PRIMARY_INDEX, LEFT_SECONDARY_INDEX, diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 12567b10d1..6e75454b5f 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -282,7 +282,22 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } - } + + // pseudo buttons the depend on both of the above for-loops + partitionTouchpad(controller::LS, controller::LX, controller::LY, controller::LS_CENTER, controller::LS_OUTER); + partitionTouchpad(controller::RS, controller::RX, controller::RY, controller::RS_CENTER, controller::RS_OUTER); + } + } +} + +void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPseudoButton, int outerPseudoButton) { + // Populate the L/RS_CENTER/OUTER pseudo buttons, corresponding to a partition of the L/RS space based on the X/Y values. + const float CENTER_DEADBAND = 0.6f; + if (_buttonPressedMap.find(sButton) != _buttonPressedMap.end()) { + float absX = abs(_axisStateMap[xAxis]); + float absY = abs(_axisStateMap[yAxis]); + bool isCenter = (absX < CENTER_DEADBAND) && (absY < CENTER_DEADBAND); // square deadband + _buttonPressedMap.insert(isCenter ? centerPseudoButton : outerPseudoButton); } } @@ -443,6 +458,11 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI // touch pad press makePair(LS, "LS"), makePair(RS, "RS"), + // Differentiate where we are in the touch pad click + makePair(LS_CENTER, "LSCenter"), + makePair(LS_OUTER, "LSOuter"), + makePair(RS_CENTER, "RSCenter"), + makePair(RS_OUTER, "RSOuter"), // triggers makePair(LT, "LT"), diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 672ad59cfe..bd5d4a39f4 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -61,6 +61,7 @@ private: void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand); void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); + void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int outerPseudoButton); class FilteredStick { public: diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index e7be3af5dd..ca3b5e8cf2 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -266,39 +266,19 @@ function toggleHand() { } } -// Create clickMappings as needed, on demand. var clickMapping = Controller.newMapping(Script.resolvePath('') + '-click'); Script.scriptEnding.connect(clickMapping.disable); -// Move these to vive.json -function makeCenterClickWhen(click, x, y) { - var clickKey = Controller.Standard[click], - xKey = Controller.Standard[x], // Standard after filtering by mapping - yKey = Controller.Standard[y]; - return function () { - var clickValue = Controller.getValue(clickKey); - var xValue = Controller.getValue(xKey); - var yValue = Controller.getValue(yKey); - var answer = clickValue && !xValue && !yValue; - return answer; - }; -} -if (Controller.Hardware.Vive) { - clickMapping.from(Controller.Hardware.Vive.RS).when(makeCenterClickWhen('RS', 'RX', 'RY')).to(Controller.Standard.R3); - clickMapping.from(Controller.Hardware.Vive.LS).when(makeCenterClickWhen('LS', 'LX', 'LY')).to(Controller.Standard.L3); -} - - -clickMapping.from(Controller.Standard.R3).peek().to(Controller.Actions.ReticleClick); -clickMapping.from(Controller.Standard.L3).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(Controller.Actions.ReticleClick); +clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(Controller.Actions.ReticleClick); clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu); clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(Controller.Actions.ContextMenu); -clickMapping.from(Controller.Standard.R3).peek().to(function (on) { +clickMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(function (on) { if (on && (activeHand !== Controller.Standard.RightHand)) { toggleHand(); } }); -clickMapping.from(Controller.Standard.L3).peek().to(function (on) { +clickMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(function (on) { if (on && (activeHand !== Controller.Standard.LeftHand)) { toggleHand(); } From 66a90cc3f8ad1e415ae38f29c025793ef6d478d5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 May 2016 11:31:39 +1200 Subject: [PATCH 46/59] Make file browser dialog resizable --- interface/resources/qml/dialogs/FileDialog.qml | 2 +- interface/resources/qml/windows-uit/ModalFrame.qml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 5cd972a38f..0b539f9667 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -25,7 +25,7 @@ import "fileDialog" //FIXME implement shortcuts for favorite location ModalWindow { id: root - //resizable: true + resizable: true implicitWidth: 640 implicitHeight: 480 diff --git a/interface/resources/qml/windows-uit/ModalFrame.qml b/interface/resources/qml/windows-uit/ModalFrame.qml index 77344829d5..415ae03284 100644 --- a/interface/resources/qml/windows-uit/ModalFrame.qml +++ b/interface/resources/qml/windows-uit/ModalFrame.qml @@ -18,13 +18,13 @@ Frame { HifiConstants { id: hifi } Rectangle { - id: modalFrame + id: frameContent readonly property bool hasTitle: window.title != "" anchors { fill: parent - topMargin: -hifi.dimensions.modalDialogMargin.y - (modalFrame.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0) + topMargin: -hifi.dimensions.modalDialogMargin.y - (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0) leftMargin: -hifi.dimensions.modalDialogMargin.x rightMargin: -hifi.dimensions.modalDialogMargin.x bottomMargin: -hifi.dimensions.modalDialogMargin.y @@ -38,7 +38,7 @@ Frame { color: hifi.colors.faintGray Item { - visible: modalFrame.hasTitle + visible: frameContent.hasTitle anchors.fill: parent anchors { topMargin: -parent.anchors.topMargin From fb9f6185db724c0fc3f30ec46ad70353e3a848de Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 17:19:53 -0700 Subject: [PATCH 47/59] CR feedback --- domain-server/src/DomainGatekeeper.cpp | 5 +++-- interface/src/Application.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 9023510214..b940d46849 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -535,9 +535,10 @@ void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const H // this is an agent and we've decided we won't let them connect - send them a packet to deny connection QByteArray utfString = reason.toUtf8(); quint16 payloadSize = utfString.size(); - + // setup the DomainConnectionDenied packet - auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied); + auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, + payloadSize + sizeof(payloadSize) + sizeof(uint8_t)); // pack in the reason the connection was denied (the client displays this) if (payloadSize > 0) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f3322caffb..48b418b93c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4594,7 +4594,7 @@ void Application::setSessionUUID(const QUuid& sessionUUID) const { // If we're not getting anything back from the domain server checkin, it might be that the domain speaks an -// older version of the DomainConnectRequest protocal. We will attempt to send and older version of DomainConnectRequest. +// older version of the DomainConnectRequest protocol. We will attempt to send and older version of DomainConnectRequest. // We won't actually complete the connection, but if the server responds, we know that it needs to be upgraded (or we // need to be downgraded to talk to it). void Application::limitOfSilentDomainCheckInsReached() { From ff45633c21ca3f9a496fa620e5fb7490968af874 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 24 May 2016 17:36:52 -0700 Subject: [PATCH 48/59] bump entities version/CR feedback --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 9de149d32d..a960edbdc8 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -49,7 +49,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_NO_FLY_ZONES; + return VERSION_ENTITIES_MORE_SHAPES; case PacketType::AvatarData: case PacketType::BulkAvatarData: return static_cast(AvatarMixerPacketVersion::AvatarEntities); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index b6237e74d6..a04a737c41 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -178,6 +178,7 @@ const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55; const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56; const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57; const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58; +const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59; enum class AvatarMixerPacketVersion : PacketVersion { TranslationSupport = 17, From 1c4eed640fcdd1747484e383b8d59b4f092dbaea Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 May 2016 13:10:26 +1200 Subject: [PATCH 49/59] Fix up file browser resize handle and outlining --- .../resources/qml/dialogs/FileDialog.qml | 2 ++ .../qml/styles-uit/HifiConstants.qml | 1 + .../qml/windows-uit/DefaultFrame.qml | 24 ++++++++++------ interface/resources/qml/windows-uit/Frame.qml | 28 +++++++++---------- .../resources/qml/windows-uit/ModalFrame.qml | 13 ++++++--- .../resources/qml/windows-uit/ModalWindow.qml | 2 ++ .../resources/qml/windows-uit/Window.qml | 1 + 7 files changed, 45 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 0b539f9667..7921e2549d 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -29,6 +29,8 @@ ModalWindow { implicitWidth: 640 implicitHeight: 480 + minSize: Qt.vector2d(300, 240) + HifiConstants { id: hifi } Settings { diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 16f150b2d9..f2698da574 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -141,6 +141,7 @@ Item { readonly property real textPadding: 8 readonly property real sliderHandleSize: 18 readonly property real sliderGrooveHeight: 8 + readonly property real frameIconSize: 22 readonly property real spinnerSize: 50 readonly property real tablePadding: 12 readonly property real tableRowHeight: largeScreen ? 26 : 23 diff --git a/interface/resources/qml/windows-uit/DefaultFrame.qml b/interface/resources/qml/windows-uit/DefaultFrame.qml index 04905656ce..6334086e4e 100644 --- a/interface/resources/qml/windows-uit/DefaultFrame.qml +++ b/interface/resources/qml/windows-uit/DefaultFrame.qml @@ -20,6 +20,14 @@ Frame { Rectangle { // Dialog frame id: frameContent + + readonly property int iconSize: hifi.dimensions.frameIconSize + readonly property int frameMargin: 9 + readonly property int frameMarginLeft: frameMargin + readonly property int frameMarginRight: frameMargin + readonly property int frameMarginTop: 2 * frameMargin + iconSize + readonly property int frameMarginBottom: iconSize + 11 + anchors { topMargin: -frameMarginTop leftMargin: -frameMarginLeft @@ -45,17 +53,17 @@ Frame { anchors { right: parent.right; top: parent.top; - topMargin: frameMargin + 1 // Move down a little to visually align with the title - rightMargin: frameMarginRight; + topMargin: frameContent.frameMargin + 1 // Move down a little to visually align with the title + rightMargin: frameContent.frameMarginRight; } - spacing: iconSize / 4 + spacing: frameContent.iconSize / 4 HiFiGlyphs { // "Pin" button visible: false text: (frame.pinned && !pinClickArea.containsMouse) || (!frame.pinned && pinClickArea.containsMouse) ? hifi.glyphs.pinInverted : hifi.glyphs.pin color: pinClickArea.containsMouse && !pinClickArea.pressed ? hifi.colors.redHighlight : hifi.colors.white - size: iconSize + size: frameContent.iconSize MouseArea { id: pinClickArea anchors.fill: parent @@ -70,7 +78,7 @@ Frame { visible: window ? window.closable : false text: closeClickArea.containsPress ? hifi.glyphs.closeInverted : hifi.glyphs.close color: closeClickArea.containsMouse ? hifi.colors.redHighlight : hifi.colors.white - size: iconSize + size: frameContent.iconSize MouseArea { id: closeClickArea anchors.fill: parent @@ -85,11 +93,11 @@ Frame { id: titleText anchors { left: parent.left - leftMargin: frameMarginLeft + hifi.dimensions.contentMargin.x + leftMargin: frameContent.frameMarginLeft + hifi.dimensions.contentMargin.x right: controlsRow.left - rightMargin: iconSize + rightMargin: frameContent.iconSize top: parent.top - topMargin: frameMargin + topMargin: frameContent.frameMargin } text: window ? window.title : "" color: hifi.colors.white diff --git a/interface/resources/qml/windows-uit/Frame.qml b/interface/resources/qml/windows-uit/Frame.qml index f21097ea62..9519a44cf0 100644 --- a/interface/resources/qml/windows-uit/Frame.qml +++ b/interface/resources/qml/windows-uit/Frame.qml @@ -22,12 +22,10 @@ Item { property bool gradientsSupported: desktop.gradientsSupported - readonly property int iconSize: 22 - readonly property int frameMargin: 9 - readonly property int frameMarginLeft: frameMargin - readonly property int frameMarginRight: frameMargin - readonly property int frameMarginTop: 2 * frameMargin + iconSize - readonly property int frameMarginBottom: iconSize + 11 + readonly property int frameMarginLeft: frameContent.frameMarginLeft + readonly property int frameMarginRight: frameContent.frameMarginRight + readonly property int frameMarginTop: frameContent.frameMarginTop + readonly property int frameMarginBottom: frameContent.frameMarginBottom // Frames always fill their parents, but their decorations may extend // beyond the window via negative margin sizes @@ -76,8 +74,8 @@ Item { id: sizeOutline x: -frameMarginLeft y: -frameMarginTop - width: window ? window.width + frameMarginLeft + frameMarginRight : 0 - height: window ? window.height + frameMarginTop + frameMarginBottom : 0 + width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0 + height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0 color: hifi.colors.baseGrayHighlight15 border.width: 3 border.color: hifi.colors.white50 @@ -88,11 +86,11 @@ Item { MouseArea { // Resize handle id: sizeDrag - width: iconSize - height: iconSize + width: hifi.dimensions.frameIconSize + height: hifi.dimensions.frameIconSize enabled: window ? window.resizable : false hoverEnabled: true - x: window ? window.width + frameMarginRight - iconSize : 0 + x: window ? window.width + frameMarginRight - hifi.dimensions.frameIconSize : 0 y: window ? window.height + 4 : 0 property vector2d pressOrigin property vector2d sizeOrigin @@ -124,10 +122,12 @@ Item { HiFiGlyphs { visible: sizeDrag.enabled x: -11 // Move a little to visually align - y: -4 // "" + y: window.modality == Qt.ApplicationModal ? -6 : -4 text: hifi.glyphs.resizeHandle - size: iconSize + 10 - color: sizeDrag.containsMouse || sizeDrag.pressed ? hifi.colors.white : hifi.colors.white50 + size: hifi.dimensions.frameIconSize + 10 + color: sizeDrag.containsMouse || sizeDrag.pressed + ? hifi.colors.white + : (window.colorScheme == hifi.colorSchemes.dark ? hifi.colors.white50 : hifi.colors.lightGrayText80) } } } diff --git a/interface/resources/qml/windows-uit/ModalFrame.qml b/interface/resources/qml/windows-uit/ModalFrame.qml index 415ae03284..13c560a519 100644 --- a/interface/resources/qml/windows-uit/ModalFrame.qml +++ b/interface/resources/qml/windows-uit/ModalFrame.qml @@ -22,12 +22,17 @@ Frame { readonly property bool hasTitle: window.title != "" + readonly property int frameMarginLeft: hifi.dimensions.modalDialogMargin.x + readonly property int frameMarginRight: hifi.dimensions.modalDialogMargin.x + readonly property int frameMarginTop: hifi.dimensions.modalDialogMargin.y + (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0) + readonly property int frameMarginBottom: hifi.dimensions.modalDialogMargin.y + anchors { fill: parent - topMargin: -hifi.dimensions.modalDialogMargin.y - (frameContent.hasTitle ? hifi.dimensions.modalDialogTitleHeight + 10 : 0) - leftMargin: -hifi.dimensions.modalDialogMargin.x - rightMargin: -hifi.dimensions.modalDialogMargin.x - bottomMargin: -hifi.dimensions.modalDialogMargin.y + topMargin: -frameMarginTop + leftMargin: -frameMarginLeft + rightMargin: -frameMarginRight + bottomMargin: -frameMarginBottom } border { diff --git a/interface/resources/qml/windows-uit/ModalWindow.qml b/interface/resources/qml/windows-uit/ModalWindow.qml index af099eb275..6b007160d5 100644 --- a/interface/resources/qml/windows-uit/ModalWindow.qml +++ b/interface/resources/qml/windows-uit/ModalWindow.qml @@ -19,4 +19,6 @@ Window { destroyOnCloseButton: true destroyOnInvisible: true frame: ModalFrame{} + + property int colorScheme: hifi.colorSchemes.light } diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index e9477f3c7e..d614b21ce2 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -52,6 +52,7 @@ Fadable { // property bool pinned: false property bool resizable: false property bool gradientsSupported: desktop.gradientsSupported + property int colorScheme: hifi.colorSchemes.dark property vector2d minSize: Qt.vector2d(100, 100) property vector2d maxSize: Qt.vector2d(1280, 800) From ea8ba7e2d19fe6dbb7a047048e291aa91609ae72 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 24 May 2016 18:12:40 -0700 Subject: [PATCH 50/59] Fixes based on code review feedback. * Use isNaN instead of glm::isnan * prefer abort() over writing to a nullptr, in release assert. * warn if packet size does not match expectations --- libraries/avatars/src/AvatarData.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index cc61036915..16e4bd5437 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -92,7 +92,7 @@ namespace AvatarDataPacket { */ } -#define ASSERT(COND) do { if (!(COND)) { int* bad = nullptr; *bad = 0xbad; } } while(0) +#define ASSERT(COND) do { if (!(COND)) { abort(); } } while(0) AvatarData::AvatarData() : SpatiallyNestable(NestableType::Avatar, QUuid()), @@ -442,7 +442,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { glm::vec3 position = glm::vec3(header->position[0], header->position[1], header->position[2]); _globalPosition = glm::vec3(header->globalPosition[0], header->globalPosition[1], header->globalPosition[2]); - if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) { + if (isNaN(position)) { if (shouldLogError(now)) { qCWarning(avatars) << "Discard AvatarData packet: position NaN, uuid " << getSessionUUID(); } @@ -454,7 +454,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { unpackFloatAngleFromTwoByte(header->localOrientation + 0, &yaw); unpackFloatAngleFromTwoByte(header->localOrientation + 1, &pitch); unpackFloatAngleFromTwoByte(header->localOrientation + 2, &roll); - if (glm::isnan(yaw) || glm::isnan(pitch) || glm::isnan(roll)) { + if (isNaN(yaw) || isNaN(pitch) || isNaN(roll)) { if (shouldLogError(now)) { qCWarning(avatars) << "Discard AvatarData packet: localOriention is NaN, uuid " << getSessionUUID(); } @@ -471,7 +471,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { float scale; unpackFloatRatioFromTwoByte((uint8_t*)&header->scale, scale); - if (glm::isnan(scale)) { + if (isNaN(scale)) { if (shouldLogError(now)) { qCWarning(avatars) << "Discard AvatarData packet: scale NaN, uuid " << getSessionUUID(); } @@ -480,7 +480,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, scale)); glm::vec3 lookAt = glm::vec3(header->lookAtPosition[0], header->lookAtPosition[1], header->lookAtPosition[2]); - if (glm::isnan(lookAt.x) || glm::isnan(lookAt.y) || glm::isnan(lookAt.z)) { + if (isNaN(lookAt)) { if (shouldLogError(now)) { qCWarning(avatars) << "Discard AvatarData packet: lookAtPosition is NaN, uuid " << getSessionUUID(); } @@ -489,7 +489,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData->_lookAtPosition = lookAt; float audioLoudness = header->audioLoudness; - if (glm::isnan(audioLoudness)) { + if (isNaN(audioLoudness)) { if (shouldLogError(now)) { qCWarning(avatars) << "Discard AvatarData packet: audioLoudness is NaN, uuid " << getSessionUUID(); } @@ -522,8 +522,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { auto parentInfo = reinterpret_cast(sourceBuffer); sourceBuffer += sizeof(AvatarDataPacket::ParentInfo); - const size_t RFC_4122_SIZE = 16; - QByteArray byteArray((const char*)parentInfo->parentUUID, RFC_4122_SIZE); + QByteArray byteArray((const char*)parentInfo->parentUUID, NUM_BYTES_RFC4122_UUID); _parentID = QUuid::fromRfc4122(byteArray); _parentJointIndex = parentInfo->parentJointIndex; } else { @@ -634,8 +633,11 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { int numBytesRead = sourceBuffer - startPosition; - // AJT: Maybe make this a warning. - ASSERT(numBytesRead == buffer.size()); + if (numBytesRead != buffer.size()) { + if (shouldLogError(now)) { + qCWarning(avatars) << "AvatarData packet size mismatch: expected " << numBytesRead << " received " << buffer.size(); + } + } _averageBytesReceived.updateAverage(numBytesRead); return numBytesRead; From 9ec6b774608026ef53d9d14e050b8b85e4997003 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 May 2016 13:49:01 +1200 Subject: [PATCH 51/59] Make file browser dialog movable --- interface/resources/qml/dialogs/FileDialog.qml | 1 + interface/resources/qml/windows-uit/DefaultFrame.qml | 2 +- interface/resources/qml/windows-uit/ModalFrame.qml | 7 +++++++ interface/resources/qml/windows-uit/ModalWindow.qml | 6 ++++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 7921e2549d..00a66c01cc 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -30,6 +30,7 @@ ModalWindow { implicitHeight: 480 minSize: Qt.vector2d(300, 240) + draggable: true HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows-uit/DefaultFrame.qml b/interface/resources/qml/windows-uit/DefaultFrame.qml index 6334086e4e..84f435480b 100644 --- a/interface/resources/qml/windows-uit/DefaultFrame.qml +++ b/interface/resources/qml/windows-uit/DefaultFrame.qml @@ -42,7 +42,7 @@ Frame { } radius: hifi.dimensions.borderRadius - // Allow dragging of the window + // Enable dragging of the window MouseArea { anchors.fill: parent drag.target: window diff --git a/interface/resources/qml/windows-uit/ModalFrame.qml b/interface/resources/qml/windows-uit/ModalFrame.qml index 13c560a519..44c0b6a456 100644 --- a/interface/resources/qml/windows-uit/ModalFrame.qml +++ b/interface/resources/qml/windows-uit/ModalFrame.qml @@ -42,6 +42,13 @@ Frame { radius: hifi.dimensions.borderRadius color: hifi.colors.faintGray + // Enable dragging of the window + MouseArea { + anchors.fill: parent + drag.target: window + enabled: window.draggable + } + Item { visible: frameContent.hasTitle anchors.fill: parent diff --git a/interface/resources/qml/windows-uit/ModalWindow.qml b/interface/resources/qml/windows-uit/ModalWindow.qml index 6b007160d5..f429e98ac3 100644 --- a/interface/resources/qml/windows-uit/ModalWindow.qml +++ b/interface/resources/qml/windows-uit/ModalWindow.qml @@ -14,11 +14,13 @@ import "." Window { id: window - anchors.centerIn: parent modality: Qt.ApplicationModal destroyOnCloseButton: true destroyOnInvisible: true - frame: ModalFrame{} + frame: ModalFrame { } property int colorScheme: hifi.colorSchemes.light + property bool draggable: false + + anchors.centerIn: draggable ? undefined : parent } From ba77aaf7efdb0607001d9f2f6a16b8d03460f6e9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 May 2016 11:06:08 -0700 Subject: [PATCH 52/59] remove collision of isPlaying property and slot --- libraries/script-engine/src/ScriptAudioInjector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/script-engine/src/ScriptAudioInjector.h index 0d16b26fdf..4de12af62c 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.h +++ b/libraries/script-engine/src/ScriptAudioInjector.h @@ -19,7 +19,7 @@ class ScriptAudioInjector : public QObject { Q_OBJECT - Q_PROPERTY(bool isPlaying READ isPlaying) + Q_PROPERTY(bool playing READ isPlaying) Q_PROPERTY(float loudness READ getLoudness) Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions) public: From 64720444cf4527f10eebb360018269af366cb72c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 May 2016 11:11:06 -0700 Subject: [PATCH 53/59] correct existing uses of the isPlaying property --- script-archive/FlockOfbirds.js | 84 +++++++++---------- .../ACAudioSearchAndInject.js | 6 +- script-archive/avatarSelector.js | 4 +- script-archive/baseball/baseballCrowd.js | 4 +- script-archive/controllers/hydra/airGuitar.js | 17 ++-- script-archive/drylake/ratCreator.js | 2 +- script-archive/entityScripts/movable.js | 58 ++++++------- script-archive/example/audio/birdSongs.js | 40 ++++----- script-archive/lobby.js | 72 ++++++++-------- script-archive/playTestSound.js | 25 +++--- 10 files changed, 155 insertions(+), 157 deletions(-) diff --git a/script-archive/FlockOfbirds.js b/script-archive/FlockOfbirds.js index f466fa2909..c2fb54f0a6 100644 --- a/script-archive/FlockOfbirds.js +++ b/script-archive/FlockOfbirds.js @@ -3,8 +3,8 @@ // examples // // Copyright 2014 High Fidelity, Inc. -// Creates a flock of birds that fly around and chirp, staying inside the corners of the box defined -// at the start of the script. +// Creates a flock of birds that fly around and chirp, staying inside the corners of the box defined +// at the start of the script. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -13,12 +13,12 @@ // The rectangular area in the domain where the flock will fly var lowerCorner = { x: 0, y: 0, z: 0 }; var upperCorner = { x: 30, y: 10, z: 30 }; -var STARTING_FRACTION = 0.25; +var STARTING_FRACTION = 0.25; var NUM_BIRDS = 50; var UPDATE_INTERVAL = 0.016; -var playSounds = true; -var SOUND_PROBABILITY = 0.001; +var playSounds = true; +var SOUND_PROBABILITY = 0.001; var STARTING_LIFETIME = (1.0 / SOUND_PROBABILITY) * UPDATE_INTERVAL * 10; var numPlaying = 0; var BIRD_SIZE = 0.08; @@ -36,17 +36,17 @@ var ALIGNMENT_FORCE = 1.5; var COHESION_FORCE = 1.0; var MAX_COHESION_VELOCITY = 0.5; -var followBirds = false; +var followBirds = false; var AVATAR_FOLLOW_RATE = 0.001; var AVATAR_FOLLOW_VELOCITY_TIMESCALE = 2.0; var AVATAR_FOLLOW_ORIENTATION_RATE = 0.005; -var floor = false; +var floor = false; var MAKE_FLOOR = false; var averageVelocity = { x: 0, y: 0, z: 0 }; var averagePosition = { x: 0, y: 0, z: 0 }; -var birdsLoaded = false; +var birdsLoaded = false; var oldAvatarOrientation; var oldAvatarPosition; @@ -79,10 +79,10 @@ function updateBirds(deltaTime) { birds[i].entityId = false; return; } - // Sum up average position and velocity + // Sum up average position and velocity if (Vec3.length(properties.velocity) > MIN_ALIGNMENT_VELOCITY) { sumVelocity = Vec3.sum(sumVelocity, properties.velocity); - birdVelocitiesCounted += 1; + birdVelocitiesCounted += 1; } sumPosition = Vec3.sum(sumPosition, properties.position); birdPositionsCounted += 1; @@ -93,10 +93,10 @@ function updateBirds(deltaTime) { var randomVelocity = randomVector(RANDOM_FLAP_VELOCITY); randomVelocity.y = FLAP_UP + Math.random() * FLAP_UP; - // Alignment Velocity - var alignmentVelocityMagnitude = Math.min(MAX_ALIGNMENT_VELOCITY, Vec3.length(Vec3.multiply(ALIGNMENT_FORCE, averageVelocity))); + // Alignment Velocity + var alignmentVelocityMagnitude = Math.min(MAX_ALIGNMENT_VELOCITY, Vec3.length(Vec3.multiply(ALIGNMENT_FORCE, averageVelocity))); var alignmentVelocity = Vec3.multiply(alignmentVelocityMagnitude, Vec3.normalize(averageVelocity)); - alignmentVelocity.y *= VERTICAL_ALIGNMENT_COUPLING; + alignmentVelocity.y *= VERTICAL_ALIGNMENT_COUPLING; // Cohesion var distanceFromCenter = Vec3.length(Vec3.subtract(averagePosition, properties.position)); @@ -107,10 +107,10 @@ function updateBirds(deltaTime) { Entities.editEntity(birds[i].entityId, { velocity: Vec3.sum(properties.velocity, newVelocity) }); - } + } // Check whether to play a chirp - if (playSounds && (!birds[i].audioId || !birds[i].audioId.isPlaying) && (Math.random() < ((numPlaying > 0) ? SOUND_PROBABILITY / numPlaying : SOUND_PROBABILITY))) { + if (playSounds && (!birds[i].audioId || !birds[i].audioId.playing) && (Math.random() < ((numPlaying > 0) ? SOUND_PROBABILITY / numPlaying : SOUND_PROBABILITY))) { var options = { position: properties.position, volume: BIRD_MASTER_VOLUME @@ -126,43 +126,43 @@ function updateBirds(deltaTime) { // Change size, and update lifetime to keep bird alive Entities.editEntity(birds[i].entityId, { dimensions: Vec3.multiply(1.5, properties.dimensions), lifetime: properties.ageInSeconds + STARTING_LIFETIME}); - + } else if (birds[i].audioId) { - // If bird is playing a chirp - if (!birds[i].audioId.isPlaying) { + // If bird is playing a chirp + if (!birds[i].audioId.playing) { Entities.editEntity(birds[i].entityId, { dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }}); numPlaying--; - } + } } // Keep birds in their 'cage' var bounce = false; - var newVelocity = properties.velocity; - var newPosition = properties.position; + var newVelocity = properties.velocity; + var newPosition = properties.position; if (properties.position.x < lowerCorner.x) { - newPosition.x = lowerCorner.x; + newPosition.x = lowerCorner.x; newVelocity.x *= -1.0; bounce = true; } else if (properties.position.x > upperCorner.x) { - newPosition.x = upperCorner.x; + newPosition.x = upperCorner.x; newVelocity.x *= -1.0; bounce = true; } if (properties.position.y < lowerCorner.y) { - newPosition.y = lowerCorner.y; + newPosition.y = lowerCorner.y; newVelocity.y *= -1.0; bounce = true; } else if (properties.position.y > upperCorner.y) { - newPosition.y = upperCorner.y; + newPosition.y = upperCorner.y; newVelocity.y *= -1.0; bounce = true; - } + } if (properties.position.z < lowerCorner.z) { - newPosition.z = lowerCorner.z; + newPosition.z = lowerCorner.z; newVelocity.z *= -1.0; bounce = true; } else if (properties.position.z > upperCorner.z) { - newPosition.z = upperCorner.z; + newPosition.z = upperCorner.z; newVelocity.z *= -1.0; bounce = true; } @@ -171,7 +171,7 @@ function updateBirds(deltaTime) { } } } - // Update average velocity and position of flock + // Update average velocity and position of flock if (birdVelocitiesCounted > 0) { averageVelocity = Vec3.multiply(1.0 / birdVelocitiesCounted, sumVelocity); //print(Vec3.length(averageVelocity)); @@ -184,10 +184,10 @@ function updateBirds(deltaTime) { MyAvatar.orientation = Quat.mix(MyAvatar.orientation, birdDirection, AVATAR_FOLLOW_ORIENTATION_RATE); } } - } + } if (birdPositionsCounted > 0) { averagePosition = Vec3.multiply(1.0 / birdPositionsCounted, sumPosition); - // If Following birds, update position + // If Following birds, update position if (followBirds) { MyAvatar.position = Vec3.sum(Vec3.multiply(AVATAR_FOLLOW_RATE, MyAvatar.position), Vec3.multiply(1.0 - AVATAR_FOLLOW_RATE, averagePosition)); } @@ -211,12 +211,12 @@ Script.scriptEnding.connect(function() { }); function loadBirds(howMany) { - oldAvatarOrientation = MyAvatar.orientation; + oldAvatarOrientation = MyAvatar.orientation; oldAvatarPosition = MyAvatar.position; var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw"]; /* Here are more sounds/species you can use - , "mexicanWhipoorwill.raw", + , "mexicanWhipoorwill.raw", "rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav", "browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav", "gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav", @@ -252,19 +252,19 @@ function loadBirds(howMany) { { red: 216, green: 153, blue: 99 }, { red: 242, green: 226, blue: 64 } ]; - + var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/"; - + for (var i = 0; i < howMany; i++) { var whichBird = Math.floor(Math.random() * sound_filenames.length); - var position = { - x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION, - y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION, + var position = { + x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION, + y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION, z: lowerCorner.z + (upperCorner.z - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.z - lowerCorner.z) * STARTING_FRACTION - }; + }; birds.push({ - sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[whichBird]), + sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[whichBird]), entityId: Entities.addEntity({ type: "Sphere", position: position, @@ -282,8 +282,8 @@ function loadBirds(howMany) { } if (MAKE_FLOOR) { var FLOOR_THICKNESS = 0.05; - floor = Entities.addEntity({ type: "Box", position: { x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0, - y: lowerCorner.y, + floor = Entities.addEntity({ type: "Box", position: { x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0, + y: lowerCorner.y, z: lowerCorner.z + (upperCorner.z - lowerCorner.z) / 2.0 }, dimensions: { x: (upperCorner.x - lowerCorner.x), y: FLOOR_THICKNESS, z: (upperCorner.z - lowerCorner.z)}, color: {red: 100, green: 100, blue: 100} diff --git a/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js b/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js index 381a7ee902..30567b4fc7 100644 --- a/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js +++ b/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js @@ -49,7 +49,7 @@ function debug() { // Display the arguments not just [Object object]. EntityViewer.setCenterRadius(QUERY_RADIUS); // ENTITY DATA CACHE -// +// var entityCache = {}; // A dictionary of unexpired EntityData objects. var examinationCount = 0; function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. @@ -146,7 +146,7 @@ function EntityDatum(entityIdentifier) { // Just the data of an entity that we n return; } that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC - if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. + if (!that.injector.playing) { // Subtle: a looping sound will not check playbackGap. if (repeat()) { // WAITING => PLAYING // Setup next play just once, now. Changes won't be looked at while we wait. that.playAfter = randomizedNextPlay(); @@ -208,7 +208,7 @@ function updateAllEntityData() { // A fast update of all entities we know about. stats.entities++; if (datum.url) { stats.sounds++; - if (datum.injector && datum.injector.isPlaying) { + if (datum.injector && datum.injector.playing) { stats.playing++; } } diff --git a/script-archive/avatarSelector.js b/script-archive/avatarSelector.js index dc2916a1a8..47740ef0b3 100644 --- a/script-archive/avatarSelector.js +++ b/script-archive/avatarSelector.js @@ -283,7 +283,7 @@ function actionStartEvent(event) { if (avatarIndex < avatars.length) { var actionPlace = avatars[avatarIndex]; - print("Changing avatar to " + actionPlace.name + print("Changing avatar to " + actionPlace.name + " after click on panel " + panelIndex + " with avatar index " + avatarIndex); MyAvatar.useFullAvatarURL(actionPlace.content_url); @@ -395,7 +395,7 @@ function update(deltaTime) { Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); // if the reticle is up then we may need to play the next muzak - if (currentMuzakInjector && !currentMuzakInjector.isPlaying) { + if (currentMuzakInjector && !currentMuzakInjector.playing) { playNextMuzak(); } } diff --git a/script-archive/baseball/baseballCrowd.js b/script-archive/baseball/baseballCrowd.js index de9b53f9ec..1459ce6e67 100644 --- a/script-archive/baseball/baseballCrowd.js +++ b/script-archive/baseball/baseballCrowd.js @@ -21,7 +21,7 @@ var CHATTER_VOLUME = 0.20 var EXTRA_VOLUME = 0.25 function playChatter() { - if (chatter.downloaded && !chatter.isPlaying) { + if (chatter.downloaded && !chatter.playing) { Audio.playSound(chatter, { loop: true, volume: CHATTER_VOLUME }); } } @@ -31,7 +31,7 @@ chatter.ready.connect(playChatter); var currentInjector = null; function playRandomExtras() { - if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) { + if ((!currentInjector || !currentInjector.playing) && (Math.random() < (1.0 / 1800.0))) { // play a random extra sound about every 30s currentInjector = Audio.playSound( extras[Math.floor(Math.random() * extras.length)], diff --git a/script-archive/controllers/hydra/airGuitar.js b/script-archive/controllers/hydra/airGuitar.js index f8606808c1..73c7099eed 100644 --- a/script-archive/controllers/hydra/airGuitar.js +++ b/script-archive/controllers/hydra/airGuitar.js @@ -22,12 +22,12 @@ function printVector(v) { return; } -function vMinus(a, b) { +function vMinus(a, b) { var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; return rval; } -// The model file to be used for the guitar +// The model file to be used for the guitar var guitarModel = HIFI_PUBLIC_BUCKET + "models/attachments/guitar.fst"; // Load sounds that will be played @@ -47,7 +47,7 @@ chords[6] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Me chords[7] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+E+short.raw"); chords[8] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+G+short.raw"); -// Steel Guitar +// Steel Guitar chords[9] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+A.raw"); chords[10] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+B.raw"); chords[11] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+E.raw"); @@ -83,8 +83,8 @@ if (leftHanded) { } var lastPosition = { x: 0.0, - y: 0.0, - z: 0.0 }; + y: 0.0, + z: 0.0 }; var audioInjector = null; var selectorPressed = false; @@ -106,7 +106,7 @@ function checkHands(deltaTime) { var chord = Controller.getValue(chordTrigger); if (volume > 1.0) volume = 1.0; - if ((chord > 0.1) && audioInjector && audioInjector.isPlaying) { + if ((chord > 0.1) && audioInjector && audioInjector.playing) { // If chord finger trigger pulled, stop current chord print("stopping chord because cord trigger pulled"); audioInjector.stop(); @@ -119,7 +119,7 @@ function checkHands(deltaTime) { guitarSelector += NUM_CHORDS; if (guitarSelector >= NUM_CHORDS * NUM_GUITARS) { guitarSelector = 0; - } + } print("new guitarBase: " + guitarSelector); stopAudio(true); selectorPressed = true; @@ -160,7 +160,7 @@ function checkHands(deltaTime) { } function stopAudio(killInjector) { - if (audioInjector && audioInjector.isPlaying) { + if (audioInjector && audioInjector.playing) { print("stopped sound"); audioInjector.stop(); } @@ -212,4 +212,3 @@ function scriptEnding() { Script.update.connect(checkHands); Script.scriptEnding.connect(scriptEnding); Controller.keyPressEvent.connect(keyPressEvent); - diff --git a/script-archive/drylake/ratCreator.js b/script-archive/drylake/ratCreator.js index 60ccf1a1a3..6f6b322f84 100644 --- a/script-archive/drylake/ratCreator.js +++ b/script-archive/drylake/ratCreator.js @@ -340,7 +340,7 @@ function moveRats() { var metaRat = getMetaRatByRat(rat); if (metaRat !== undefined) { if (metaRat.injector !== undefined) { - if (metaRat.injector.isPlaying === true) { + if (metaRat.injector.playing === true) { metaRat.injector.options = { loop: true, position: ratPosition diff --git a/script-archive/entityScripts/movable.js b/script-archive/entityScripts/movable.js index b7ecfbbc8e..06b30ce15e 100644 --- a/script-archive/entityScripts/movable.js +++ b/script-archive/entityScripts/movable.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -(function(){ +(function(){ this.entityID = null; this.properties = null; @@ -30,13 +30,13 @@ "http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove2.wav", "http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove3.wav" ]; - + this.turnSoundURLS = [ "http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove1.wav", "http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove2.wav", "http://public.highfidelity.io/sounds/MovingFurniture/FurnitureMove3.wav" - + // TODO: determine if these or other turn sounds work better than move sounds. //"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureTurn1.wav", //"http://public.highfidelity.io/sounds/MovingFurniture/FurnitureTurn2.wav", @@ -50,7 +50,7 @@ this.turnSound = null; this.moveInjector = null; this.turnInjector = null; - + var debug = false; var displayRotateTargets = true; // change to false if you don't want the rotate targets var rotateOverlayTargetSize = 10000; // really big target @@ -61,12 +61,12 @@ var yawZero; var rotationNormal; var yawNormal; - var stopSoundDelay = 100; // number of msecs of not moving to have sound stop - + var stopSoundDelay = 100; // number of msecs of not moving to have sound stop + this.getRandomInt = function(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; - } - + } + this.downloadSounds = function() { for (var i = 0; i < this.moveSoundURLS.length; i++) { this.moveSounds[i] = SoundCache.getSound(this.moveSoundURLS[i]); @@ -95,7 +95,7 @@ if (debug) { print("playMoveSound() --- calling this.moveInjector = Audio.playSound(this.moveSound...)"); } - + if (!this.moveInjector) { this.moveInjector = Audio.playSound(this.moveSound, { position: this.properties.position, loop: true, volume: 0.1 }); } else { @@ -148,7 +148,7 @@ var upVector = { x: 0, y: 1, z: 0 }; var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction, this.properties.position, upVector); - + var newPosition = Vec3.sum(intersection, this.graboffset); Entities.editEntity(this.entityID, { position: newPosition }); }; @@ -158,7 +158,7 @@ var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y) var upVector = { x: 0, y: 1, z: 0 }; var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction, - this.properties.position, upVector); + this.properties.position, upVector); this.graboffset = Vec3.subtract(this.properties.position, intersection); }; @@ -183,18 +183,18 @@ this.lastMovedPosition.y = mouseEvent.y; } } - + this.move = function(mouseEvent) { this.updatePosition(mouseEvent); - if (this.moveInjector === null || !this.moveInjector.isPlaying) { + if (this.moveInjector === null || !this.moveInjector.playing) { this.playMoveSound(); } }; - + this.release = function(mouseEvent) { this.updatePosition(mouseEvent); }; - + this.rotate = function(mouseEvent) { var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y) var result = Overlays.findRayIntersection(pickRay); @@ -205,7 +205,7 @@ var centerToZero = Vec3.subtract(center, zero); var centerToIntersect = Vec3.subtract(center, result.intersection); var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal); - + var distanceFromCenter = Vec3.distance(center, result.intersection); var snapToInner = false; // var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; @@ -213,10 +213,10 @@ angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle; snapToInner = true; } - + var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); Entities.editEntity(this.entityID, { rotation: Quat.multiply(yawChange, this.originalRotation) }); - + // update the rotation display accordingly... var startAtCurrent = 360-angleFromZero; @@ -245,7 +245,7 @@ } } - if (this.turnInjector === null || !this.turnInjector.isPlaying) { + if (this.turnInjector === null || !this.turnInjector.playing) { this.playTurnSound(); } }; @@ -267,7 +267,7 @@ this.rotateOverlayOuter = null; this.rotateOverlayCurrent = null; } - + this.displayRotateOverlay = function(mouseEvent) { var yawOverlayAngles = { x: 90, y: 0, z: 0 }; var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles); @@ -356,14 +356,14 @@ var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y) var result = Overlays.findRayIntersection(pickRay); yawZero = result.intersection; - + }; - + this.preload = function(entityID) { this.updateProperties(entityID); // All callbacks start by updating the properties this.downloadSounds(); }; - + this.clickDownOnEntity = function(entityID, mouseEvent) { this.updateProperties(entityID); // All callbacks start by updating the properties this.grab(mouseEvent); @@ -372,13 +372,13 @@ var nowMSecs = nowDate.getTime(); this.clickedAt = nowMSecs; this.firstHolding = true; - + this.clicked.x = mouseEvent.x; this.clicked.y = mouseEvent.y; this.lastMovedPosition.x = mouseEvent.x; this.lastMovedPosition.y = mouseEvent.y; this.lastMovedMSecs = nowMSecs; - + this.pickRandomSounds(); }; @@ -391,7 +391,7 @@ if (this.clicked.x == mouseEvent.x && this.clicked.y == mouseEvent.y) { var d = new Date(); var now = d.getTime(); - + if (now - this.clickedAt > 500) { this.displayRotateOverlay(mouseEvent); this.firstHolding = false; @@ -402,13 +402,13 @@ this.firstHolding = false; } } - + if (this.rotateMode) { this.rotate(mouseEvent); } else { this.move(mouseEvent); } - + this.stopSoundIfNotMoving(mouseEvent); }; this.clickReleaseOnEntity = function(entityID, mouseEvent) { @@ -418,7 +418,7 @@ } else { this.release(mouseEvent); } - + if (this.rotateOverlayTarget != null) { this.cleanupRotateOverlay(); this.rotateMode = false; diff --git a/script-archive/example/audio/birdSongs.js b/script-archive/example/audio/birdSongs.js index 557fc81f5b..9e949a19ed 100644 --- a/script-archive/example/audio/birdSongs.js +++ b/script-archive/example/audio/birdSongs.js @@ -22,7 +22,7 @@ var BIRD_VELOCITY = 2.0; var LIGHT_RADIUS = 10.0; var BIRD_MASTER_VOLUME = 0.5; -var useLights = true; +var useLights = true; function randomVector(scale) { return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 }; @@ -33,11 +33,11 @@ function maybePlaySound(deltaTime) { // Set the location and other info for the sound to play var whichBird = Math.floor(Math.random() * birds.length); //print("playing sound # " + whichBird); - var position = { - x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), - y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), - z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) - }; + var position = { + x: lowerCorner.x + Math.random() * (upperCorner.x - lowerCorner.x), + y: lowerCorner.y + Math.random() * (upperCorner.y - lowerCorner.y), + z: lowerCorner.z + Math.random() * (upperCorner.z - lowerCorner.z) + }; var options = { position: position, volume: BIRD_MASTER_VOLUME @@ -63,31 +63,31 @@ function maybePlaySound(deltaTime) { constantAttenuation: 0, linearAttenuation: 4.0, - quadraticAttenuation: 2.0, + quadraticAttenuation: 2.0, lifetime: 10 }); } - + playing.push({ audioId: Audio.playSound(birds[whichBird].sound, options), entityId: entityId, lightId: lightId, color: birds[whichBird].color }); } if (playing.length != numPlaying) { numPlaying = playing.length; //print("number playing = " + numPlaying); - } + } for (var i = 0; i < playing.length; i++) { - if (!playing[i].audioId.isPlaying) { + if (!playing[i].audioId.playing) { Entities.deleteEntity(playing[i].entityId); if (useLights) { Entities.deleteEntity(playing[i].lightId); - } + } playing.splice(i, 1); } else { var loudness = playing[i].audioId.loudness; var newColor = { red: playing[i].color.red, green: playing[i].color.green, blue: playing[i].color.blue }; if (loudness > 0.05) { - newColor.red *= (1.0 - loudness); - newColor.green *= (1.0 - loudness); - newColor.blue *= (1.0 - loudness); + newColor.red *= (1.0 - loudness); + newColor.green *= (1.0 - loudness); + newColor.blue *= (1.0 - loudness); } var properties = Entities.getEntityProperties(playing[i].entityId); var newPosition = Vec3.sum(properties.position, randomVector(BIRD_VELOCITY * deltaTime)); @@ -120,7 +120,7 @@ Script.scriptEnding.connect(function() { }); function loadBirds() { - var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw", "mexicanWhipoorwill.raw", + var sound_filenames = ["bushtit_1.raw", "bushtit_2.raw", "bushtit_3.raw", "mexicanWhipoorwill.raw", "rosyfacedlovebird.raw", "saysphoebe.raw", "westernscreechowl.raw", "bandtailedpigeon.wav", "bridledtitmouse.wav", "browncrestedflycatcher.wav", "commonnighthawk.wav", "commonpoorwill.wav", "doublecrestedcormorant.wav", "gambelsquail.wav", "goldcrownedkinglet.wav", "greaterroadrunner.wav","groovebilledani.wav","hairywoodpecker.wav", @@ -155,13 +155,13 @@ function loadBirds() { { red: 216, green: 153, blue: 99 }, { red: 242, green: 226, blue: 64 } ]; - + var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/"; - + for (var i = 0; i < sound_filenames.length; i++) { birds.push({ - sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]), - color: colors[i] + sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]), + color: colors[i] }); } -} \ No newline at end of file +} diff --git a/script-archive/lobby.js b/script-archive/lobby.js index 3095740c93..6fa4a42cb6 100644 --- a/script-archive/lobby.js +++ b/script-archive/lobby.js @@ -88,19 +88,19 @@ var DRONE_VOLUME = 0.3; function drawLobby() { if (!panelWall) { print("Adding overlays for the lobby panel wall and orb shell."); - + var cameraEuler = Quat.safeEulerAngles(Camera.orientation); var towardsMe = Quat.angleAxis(cameraEuler.y + 180, { x: 0, y: 1, z: 0}); - + var orbPosition = Vec3.sum(Camera.position, Vec3.multiplyQbyV(towardsMe, ORB_SHIFT)); - + var panelWallProps = { url: LOBBY_PANEL_WALL_URL, position: Vec3.sum(orbPosition, Vec3.multiplyQbyV(towardsMe, panelsCenterShift)), rotation: towardsMe, dimensions: panelsDimensions }; - + var orbShellProps = { url: LOBBY_SHELL_URL, position: orbPosition, @@ -128,13 +128,13 @@ function drawLobby() { visible: false, isFacingAvatar: true }; - + avatarStickPosition = MyAvatar.position; - panelWall = Overlays.addOverlay("model", panelWallProps); + panelWall = Overlays.addOverlay("model", panelWallProps); orbShell = Overlays.addOverlay("model", orbShellProps); descriptionText = Overlays.addOverlay("text3d", descriptionTextProps); - + if (droneSound.downloaded) { // start the drone sound if (!currentDrone) { @@ -143,7 +143,7 @@ function drawLobby() { currentDrone.restart(); } } - + // start one of our muzak sounds playRandomMuzak(); } @@ -157,31 +157,31 @@ function changeLobbyTextures() { req.send(); places = JSON.parse(req.responseText).data.places; - + var NUM_PANELS = places.length; - var textureProp = { + var textureProp = { textures: {} }; - + for (var j = 0; j < NUM_PANELS; j++) { var panelIndex = placeIndexToPanelIndex(j); textureProp["textures"]["file" + panelIndex] = places[j].previews.lobby; }; - + Overlays.editOverlay(panelWall, textureProp); } var MUZAK_VOLUME = 0.1; -function playCurrentSound(secondOffset) { +function playCurrentSound(secondOffset) { if (currentSound == latinSound) { if (!latinInjector) { latinInjector = Audio.playSound(latinSound, { localOnly: true, secondOffset: secondOffset, volume: MUZAK_VOLUME }); } else { latinInjector.restart(); } - + currentMuzakInjector = latinInjector; } else if (currentSound == elevatorSound) { if (!elevatorInjector) { @@ -189,7 +189,7 @@ function playCurrentSound(secondOffset) { } else { elevatorInjector.restart(); } - + currentMuzakInjector = elevatorInjector; } } @@ -205,14 +205,14 @@ function playNextMuzak() { currentSound = latinSound; } } - + playCurrentSound(0); } } function playRandomMuzak() { currentSound = null; - + if (latinSound.downloaded && elevatorSound.downloaded) { currentSound = Math.random() < 0.5 ? latinSound : elevatorSound; } else if (latinSound.downloaded) { @@ -220,11 +220,11 @@ function playRandomMuzak() { } else if (elevatorSound.downloaded) { currentSound = elevatorSound; } - + if (currentSound) { // pick a random number of seconds from 0-10 to offset the muzak var secondOffset = Math.random() * 10; - + playCurrentSound(secondOffset); } else { currentMuzakInjector = null; @@ -233,36 +233,36 @@ function playRandomMuzak() { function cleanupLobby() { toggleEnvironmentRendering(true); - + // for each of the 21 placeholder textures, set them back to default so the cached model doesn't have changed textures var panelTexturesReset = {}; panelTexturesReset["textures"] = {}; - - for (var j = 0; j < MAX_NUM_PANELS; j++) { + + for (var j = 0; j < MAX_NUM_PANELS; j++) { panelTexturesReset["textures"]["file" + (j + 1)] = LOBBY_BLANK_PANEL_TEXTURE_URL; }; - + Overlays.editOverlay(panelWall, panelTexturesReset); - + Overlays.deleteOverlay(panelWall); Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(descriptionText); - + panelWall = false; orbShell = false; - + if (currentDrone) { currentDrone.stop(); currentDrone = null } - + if (currentMuzakInjector) { currentMuzakInjector.stop(); currentMuzakInjector = null; } - + places = {}; - + } function actionStartEvent(event) { @@ -271,19 +271,19 @@ function actionStartEvent(event) { // check if we hit a panel and if we should jump there var result = Overlays.findRayIntersection(event.actionRay); if (result.intersects && result.overlayID == panelWall) { - + var panelName = result.extraInfo; - + var panelStringIndex = panelName.indexOf("Panel"); if (panelStringIndex != -1) { var panelIndex = parseInt(panelName.slice(5)); var placeIndex = panelIndexToPlaceIndex(panelIndex); if (placeIndex < places.length) { var actionPlace = places[placeIndex]; - - print("Jumping to " + actionPlace.name + " at " + actionPlace.address + + print("Jumping to " + actionPlace.name + " at " + actionPlace.address + " after click on panel " + panelIndex + " with place index " + placeIndex); - + Window.location = actionPlace.address; maybeCleanupLobby(); } @@ -328,7 +328,7 @@ function handleLookAt(pickRay) { var placeIndex = panelIndexToPlaceIndex(panelIndex); if (placeIndex < places.length) { var actionPlace = places[placeIndex]; - + if (actionPlace.description == "") { Overlays.editOverlay(descriptionText, { text: actionPlace.name, visible: showText }); } else { @@ -378,7 +378,7 @@ function update(deltaTime) { Overlays.editOverlay(descriptionText, { position: textOverlayPosition() }); // if the reticle is up then we may need to play the next muzak - if (currentMuzakInjector && !currentMuzakInjector.isPlaying) { + if (currentMuzakInjector && !currentMuzakInjector.playing) { playNextMuzak(); } } diff --git a/script-archive/playTestSound.js b/script-archive/playTestSound.js index 318df6a257..573c8879c4 100644 --- a/script-archive/playTestSound.js +++ b/script-archive/playTestSound.js @@ -2,12 +2,12 @@ // playTestSound.js // examples // -// Created by Philip Rosedale +// Created by Philip Rosedale // Copyright 2014 High Fidelity, Inc. // -// Creates an object in front of you that changes color and plays a light -// at the start of a drum clip that loops. As you move away it will tell you in the -// log how many meters you are from the source. +// Creates an object in front of you that changes color and plays a light +// at the start of a drum clip that loops. As you move away it will tell you in the +// log how many meters you are from the source. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -17,7 +17,7 @@ var sound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Dru var position = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Quat.getFront(MyAvatar.orientation)); -var time; +var time; var soundPlaying = null; var baseColor = { red: 100, green: 100, blue: 100 }; @@ -38,8 +38,8 @@ var box = Entities.addEntity({ function checkSound(deltaTime) { var started = false; - if (!sound.downloaded) { - return; + if (!sound.downloaded) { + return; } if (soundPlaying == null) { soundPlaying = Audio.playSound(sound, { @@ -47,9 +47,9 @@ function checkSound(deltaTime) { volume: 1.0, loop: false } ); started = true; - } else if (!soundPlaying.isPlaying) { + } else if (!soundPlaying.playing) { soundPlaying.restart(); - started = true; + started = true; } if (started) { Entities.editEntity(box, { color: litColor }); @@ -67,19 +67,19 @@ function checkSound(deltaTime) { lifetime: lightTime / 1000 }); Script.setTimeout(resetColor, lightTime); - } + } var currentDistance = Vec3.distance(MyAvatar.position, position); if (Math.abs(currentDistance - distance) > 1.0) { print("Distance from source: " + currentDistance); distance = currentDistance; - } + } } function resetColor() { Entities.editEntity(box, { color: baseColor }); } - + function scriptEnding() { Entities.deleteEntity(box); if (soundPlaying) { @@ -93,4 +93,3 @@ function scriptEnding() { // Connect a call back that happens every frame Script.scriptEnding.connect(scriptEnding); Script.update.connect(checkSound); - From 8f3918b5baa01bf350253d5a0c4ccc6ced6edfaa Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 25 May 2016 11:21:05 -0700 Subject: [PATCH 54/59] Fix primitive shape collisions --- libraries/entities/src/ShapeEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 2527dedab2..c39a477a35 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -161,7 +161,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit // This value specifes how the shape should be treated by physics calculations. // For now, all polys will act as spheres ShapeType ShapeEntityItem::getShapeType() const { - return SHAPE_TYPE_ELLIPSOID; + return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_SPHERE; } void ShapeEntityItem::setColor(const rgbColor& value) { From 3137cd64e1c9cb499e85dd579fdbf120bdbddf46 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 May 2016 11:40:17 -0700 Subject: [PATCH 55/59] clear AddressManager previous lookup on 404 --- libraries/networking/src/AddressManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 619a1d7903..80989acd2c 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -383,8 +383,12 @@ void AddressManager::handleAPIError(QNetworkReply& errorReply) { qCDebug(networking) << "AddressManager API error -" << errorReply.error() << "-" << errorReply.errorString(); if (errorReply.error() == QNetworkReply::ContentNotFoundError) { + // if this is a lookup that has no result, don't keep re-trying it + _previousLookup.clear(); + emit lookupResultIsNotFound(); } + emit lookupResultsFinished(); } From b0ce65ec0197e2c7154ca7f21573337638235063 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 25 May 2016 11:42:06 -0700 Subject: [PATCH 56/59] trying to mimic previous behavior more closely --- assignment-client/src/Agent.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 12 ++++--- libraries/script-engine/src/ScriptEngine.h | 2 +- libraries/script-engine/src/ScriptEngines.cpp | 31 +++++++++++-------- libraries/script-engine/src/ScriptEngines.h | 1 + 6 files changed, 29 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 65e193dec6..327f6de695 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -476,7 +476,7 @@ void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending identity packets if (_scriptEngine) { - _scriptEngine->stop(); + _scriptEngine->stop(false); } // our entity tree is going to go away so tell that to the EntityScriptingInterface diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 56f6438e70..bc3c6b2441 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -114,7 +114,7 @@ void EntityTreeRenderer::clear() { // Unload and stop the engine here (instead of in its deleter) to // avoid marshalling unload signals back to this thread _entitiesScriptEngine->unloadAllEntityScripts(); - _entitiesScriptEngine->stop(); + _entitiesScriptEngine->stop(false); } if (_wantScripts && !_shuttingDown) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e7938ac5a0..61ab8c0c63 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -290,7 +290,7 @@ void ScriptEngine::waitTillDoneRunning() { assert(workerThread != QThread::currentThread()); // Engine should be stopped already, but be defensive - stop(); + stop(false); auto startedWaiting = usecTimestampNow(); while (workerThread->isRunning()) { @@ -941,13 +941,15 @@ void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) { } -void ScriptEngine::stop() { +void ScriptEngine::stop(bool marshal) { _isStopping = true; // this can be done on any thread // marshal us over to the correct thread - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "stop"); - return; + if (marshal) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "stop"); + return; + } } if (!_isFinished) { _isFinished = true; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index ef7e075021..4d39365626 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -84,7 +84,7 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts - Q_INVOKABLE void stop(); // this can be called from any thread + Q_INVOKABLE void stop(bool marshal); // this can be called from any thread // Stop any evaluating scripts and wait for the scripting thread to finish. void waitTillDoneRunning(); diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 5e5b8bfde9..6575a12c99 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -160,7 +160,7 @@ void ScriptEngines::shutdownScripting() { scriptEngine->disconnect(this); // Gracefully stop the engine's scripting thread - scriptEngine->stop(); + scriptEngine->stop(false); // We need to wait for the engine to be done running before we proceed, because we don't // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing @@ -359,7 +359,10 @@ QStringList ScriptEngines::getRunningScripts() { QList urls = _scriptEnginesHash.keys(); QStringList result; for (auto url : urls) { - result.append(url.toString()); + ScriptEngine* engine = getScriptEngineInternal(url); + if (engine) { + result.append(url.toString()); + } } return result; } @@ -388,7 +391,7 @@ void ScriptEngines::stopAllScripts(bool restart) { reloadScript(scriptName); }); } - it.value()->stop(); + it.value()->stop(true); qCDebug(scriptengine) << "stopping script..." << it.key(); } } @@ -411,7 +414,7 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { reloadScript(scriptName); }); } - scriptEngine->stop(); + scriptEngine->stop(false); stoppedScript = true; qCDebug(scriptengine) << "stopping script..." << scriptURL; } @@ -459,7 +462,7 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL } auto scriptEngine = getScriptEngine(scriptUrl); - if (scriptEngine) { + if (scriptEngine && !scriptEngine->isStopping()) { return scriptEngine; } @@ -484,19 +487,21 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL return scriptEngine; } -ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { +ScriptEngine* ScriptEngines::getScriptEngineInternal(const QUrl& rawScriptURL) { ScriptEngine* result = nullptr; - { - QReadLocker lock(&_scriptEnginesHashLock); - const QUrl scriptURL = normalizeScriptURL(rawScriptURL); - auto it = _scriptEnginesHash.find(scriptURL); - if (it != _scriptEnginesHash.end() && !it.value()->isStopping()) { - result = it.value(); - } + const QUrl scriptURL = normalizeScriptURL(rawScriptURL); + auto it = _scriptEnginesHash.find(scriptURL); + if (it != _scriptEnginesHash.end()) { + result = it.value(); } return result; } +ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { + QReadLocker lock(&_scriptEnginesHashLock); + return getScriptEngineInternal(rawScriptURL); +} + // FIXME - change to new version of ScriptCache loading notification void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { UserActivityLogger::getInstance().loadedScript(rawScriptURL); diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index a9c273b2a7..6d887ce95f 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -87,6 +87,7 @@ protected: void onScriptEngineLoaded(const QString& scriptFilename); void onScriptEngineError(const QString& scriptFilename); void launchScriptEngine(ScriptEngine* engine); + ScriptEngine* getScriptEngineInternal(const QUrl& rawScriptURL); QReadWriteLock _scriptEnginesHashLock; QHash _scriptEnginesHash; From 66bdbf910d2e6cd27aba1e23e5bb8ebf00a3177c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 May 2016 11:55:04 -0700 Subject: [PATCH 57/59] optionally include the metaverse session ID as an http header --- interface/src/DiscoverabilityManager.cpp | 4 ++++ libraries/networking/src/AccountManager.cpp | 13 +++++++++++-- libraries/networking/src/AccountManager.h | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 83f87f82ba..24256fdf39 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -127,6 +127,10 @@ void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply if (!dataObject.isEmpty()) { _sessionID = dataObject[SESSION_ID_KEY].toString(); + + // give that session ID to the account manager + auto accountManager = DependencyManager::get(); + accountManager->setSessionID(_sessionID); } } diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 9080e3cc53..46e72170e5 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AccountManager.h" + #include #include @@ -26,13 +28,13 @@ #include +#include "NetworkLogging.h" #include "NodeList.h" #include "udt/PacketHeaders.h" #include "RSAKeypairGenerator.h" #include "SharedUtil.h" +#include "UserActivityLogger.h" -#include "AccountManager.h" -#include "NetworkLogging.h" const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; @@ -216,6 +218,13 @@ void AccountManager::sendRequest(const QString& path, networkRequest.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter()); + // if we're allowed to send usage data, include whatever the current session ID is with this request + auto& activityLogger = UserActivityLogger::getInstance(); + if (activityLogger.isEnabled()) { + static const QString METAVERSE_SESSION_ID_HEADER = "HFM-SessionID"; + networkRequest.setRawHeader(METAVERSE_SESSION_ID_HEADER.toLocal8Bit(), _sessionID.toString().toLocal8Bit()); + } + QUrl requestURL = _authURL; if (path.startsWith("/")) { diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 89a2240bbb..4803d2625f 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -86,6 +86,8 @@ public: static QJsonObject dataObjectFromResponse(QNetworkReply& requestReply); + void setSessionID(const QUuid& sessionID) { _sessionID = sessionID; } + public slots: void requestAccessToken(const QString& login, const QString& password); @@ -136,6 +138,8 @@ private: bool _isWaitingForKeypairResponse { false }; QByteArray _pendingPrivateKey; + + QUuid _sessionID; }; #endif // hifi_AccountManager_h From 49769f7d2969626c515ff554ef9aa1ed716081e6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 25 May 2016 13:39:13 -0700 Subject: [PATCH 58/59] trying again -- frantic clicking on reload no longer appears to wedge things --- assignment-client/src/Agent.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 9 ++---- libraries/script-engine/src/ScriptEngine.h | 2 +- libraries/script-engine/src/ScriptEngines.cpp | 29 ++++++++----------- libraries/script-engine/src/ScriptEngines.h | 1 - 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 327f6de695..65e193dec6 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -476,7 +476,7 @@ void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending identity packets if (_scriptEngine) { - _scriptEngine->stop(false); + _scriptEngine->stop(); } // our entity tree is going to go away so tell that to the EntityScriptingInterface diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index bc3c6b2441..56f6438e70 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -114,7 +114,7 @@ void EntityTreeRenderer::clear() { // Unload and stop the engine here (instead of in its deleter) to // avoid marshalling unload signals back to this thread _entitiesScriptEngine->unloadAllEntityScripts(); - _entitiesScriptEngine->stop(false); + _entitiesScriptEngine->stop(); } if (_wantScripts && !_shuttingDown) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 61ab8c0c63..a5e3be8a43 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -290,7 +290,7 @@ void ScriptEngine::waitTillDoneRunning() { assert(workerThread != QThread::currentThread()); // Engine should be stopped already, but be defensive - stop(false); + stop(); auto startedWaiting = usecTimestampNow(); while (workerThread->isRunning()) { @@ -944,12 +944,9 @@ void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) { void ScriptEngine::stop(bool marshal) { _isStopping = true; // this can be done on any thread - // marshal us over to the correct thread if (marshal) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "stop"); - return; - } + QMetaObject::invokeMethod(this, "stop"); + return; } if (!_isFinished) { _isFinished = true; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 4d39365626..1077dce686 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -84,7 +84,7 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOTE - this is intended to be a public interface for Agent scripts, and local scripts, but not for EntityScripts - Q_INVOKABLE void stop(bool marshal); // this can be called from any thread + Q_INVOKABLE void stop(bool marshal = false); // Stop any evaluating scripts and wait for the scripting thread to finish. void waitTillDoneRunning(); diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 6575a12c99..29c223f4b3 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -160,7 +160,7 @@ void ScriptEngines::shutdownScripting() { scriptEngine->disconnect(this); // Gracefully stop the engine's scripting thread - scriptEngine->stop(false); + scriptEngine->stop(); // We need to wait for the engine to be done running before we proceed, because we don't // want any of the scripts final "scriptEnding()" or pending "update()" methods from accessing @@ -359,10 +359,7 @@ QStringList ScriptEngines::getRunningScripts() { QList urls = _scriptEnginesHash.keys(); QStringList result; for (auto url : urls) { - ScriptEngine* engine = getScriptEngineInternal(url); - if (engine) { - result.append(url.toString()); - } + result.append(url.toString()); } return result; } @@ -383,7 +380,7 @@ void ScriptEngines::stopAllScripts(bool restart) { // Stop and possibly restart all currently running scripts for (QHash::const_iterator it = _scriptEnginesHash.constBegin(); it != _scriptEnginesHash.constEnd(); it++) { - if (it.value()->isFinished()) { + if (it.value()->isFinished() || it.value()->isStopping()) { continue; } if (restart && it.value()->isUserLoaded()) { @@ -414,7 +411,7 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) { reloadScript(scriptName); }); } - scriptEngine->stop(false); + scriptEngine->stop(); stoppedScript = true; qCDebug(scriptengine) << "stopping script..." << scriptURL; } @@ -487,21 +484,19 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL return scriptEngine; } -ScriptEngine* ScriptEngines::getScriptEngineInternal(const QUrl& rawScriptURL) { +ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { ScriptEngine* result = nullptr; - const QUrl scriptURL = normalizeScriptURL(rawScriptURL); - auto it = _scriptEnginesHash.find(scriptURL); - if (it != _scriptEnginesHash.end()) { - result = it.value(); + { + QReadLocker lock(&_scriptEnginesHashLock); + const QUrl scriptURL = normalizeScriptURL(rawScriptURL); + auto it = _scriptEnginesHash.find(scriptURL); + if (it != _scriptEnginesHash.end()) { + result = it.value(); + } } return result; } -ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) { - QReadLocker lock(&_scriptEnginesHashLock); - return getScriptEngineInternal(rawScriptURL); -} - // FIXME - change to new version of ScriptCache loading notification void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) { UserActivityLogger::getInstance().loadedScript(rawScriptURL); diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 6d887ce95f..a9c273b2a7 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -87,7 +87,6 @@ protected: void onScriptEngineLoaded(const QString& scriptFilename); void onScriptEngineError(const QString& scriptFilename); void launchScriptEngine(ScriptEngine* engine); - ScriptEngine* getScriptEngineInternal(const QUrl& rawScriptURL); QReadWriteLock _scriptEnginesHashLock; QHash _scriptEnginesHash; From b16e701ea3d6a6287ba175240596d6cbbc5c50eb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 25 May 2016 13:53:28 -0700 Subject: [PATCH 59/59] Fix broken protocol for shapes --- libraries/entities/src/ShapeEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index c39a477a35..84208cc6f1 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -155,7 +155,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_SHAPE, entity::stringFromShape(getShape())); APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_COLOR, getAlpha()); + APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); } // This value specifes how the shape should be treated by physics calculations.