From 18b0ed9e8fd2070fc01bbf70da8866964e85ac93 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 30 Jul 2016 14:16:08 +1200 Subject: [PATCH 01/23] Close file browser dialog immediately after selecting asset to upload --- interface/resources/qml/AssetServer.qml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 8d971e48d3..1ad2d1a1e4 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -314,6 +314,14 @@ ScrollingWindow { }); } + Timer { + id: doUploadTimer + property var url + property bool isConnected: false + interval: 5 + repeat: false + running: false + } property var uploadOpen: false; Timer { @@ -366,6 +374,10 @@ ScrollingWindow { }, dropping); } + function initiateUpload(url) { + doUpload(doUploadTimer.url, false); + } + if (fileUrl) { doUpload(fileUrl, true); } else { @@ -373,12 +385,21 @@ ScrollingWindow { selectDirectory: false, dir: currentDirectory }); + browser.canceled.connect(function() { uploadOpen = false; }); + browser.selectedFile.connect(function(url) { currentDirectory = browser.dir; - doUpload(url, false); + + // Initiate upload from a timer so that file browser dialog can close beforehand. + doUploadTimer.url = url; + if (!doUploadTimer.isConnected) { + doUploadTimer.triggered.connect(function() { initiateUpload(); }); + doUploadTimer.isConnected = true; + } + doUploadTimer.start(); }); } } From b953e6f0ff78c9e0fdf9cbd9a77f5d8ef19843fe Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Aug 2016 18:12:30 -0700 Subject: [PATCH 02/23] when an avatar URL fails, switch to the default --- interface/src/avatar/Avatar.cpp | 10 ++++++++++ interface/src/avatar/Avatar.h | 4 +++- .../src/model-networking/ModelCache.cpp | 1 + .../src/model-networking/ModelCache.h | 3 +++ libraries/render-utils/src/Model.cpp | 11 +++++++++++ libraries/render-utils/src/Model.h | 8 ++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4d9481f002..f09eb5bdec 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -98,6 +98,7 @@ Avatar::Avatar(RigPointer rig) : _headData = static_cast(new Head(this)); _skeletonModel = std::make_shared(this, nullptr, rig); + connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished); } Avatar::~Avatar() { @@ -916,6 +917,15 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { } } +void Avatar::setModelURLFinished(bool success) { + if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) { + qDebug() << "Using default after failing to load Avatar model: " << _skeletonModelURL; + QMetaObject::invokeMethod(this, "setSkeletonModelURL", + Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); + } +} + + // create new model, can return an instance of a SoftAttachmentModel rather then Model static std::shared_ptr allocateAttachmentModel(bool isSoft, RigPointer rigOverride) { if (isSoft) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b9f44613c7..f646fe57f4 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -115,7 +115,7 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } - virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; + Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; void setShowDisplayName(bool showDisplayName); @@ -184,6 +184,8 @@ public slots: glm::vec3 getRightPalmPosition() const; glm::quat getRightPalmRotation() const; + void setModelURLFinished(bool success); + protected: friend class AvatarManager; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 26798070a6..3b7092ce8d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -404,6 +404,7 @@ void GeometryResourceWatcher::resourceFinished(bool success) { if (success) { _geometryRef = std::make_shared(*_resource); } + emit finished(success); } void GeometryResourceWatcher::resourceRefreshed() { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 4a0a921a04..962a919d6c 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -111,6 +111,9 @@ public: QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } +signals: + void finished(bool success); + private: void startWatching(); void stopWatching(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b04a1d8023..de0d69930b 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -109,6 +109,9 @@ Model::Model(RigPointer rig, QObject* parent) : } setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); + + connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); + connect(&_collisionWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); } Model::~Model() { @@ -825,6 +828,10 @@ void Model::setURL(const QUrl& url) { onInvalidate(); } +void Model::loadURLFinished(bool success) { + emit setURLFinished(success); +} + void Model::setCollisionModelURL(const QUrl& url) { if (_collisionUrl == url && _collisionWatcher.getURL() == url) { return; @@ -833,6 +840,10 @@ void Model::setCollisionModelURL(const QUrl& url) { _collisionWatcher.setResource(DependencyManager::get()->getGeometryResource(url)); } +void Model::loadCollisionModelURLFinished(bool success) { + emit setCollisionModelURLFinished(success); +} + bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { return _rig->getJointPositionInWorldFrame(jointIndex, position, _translation, _rotation); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 98e50c66f4..076913a883 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -236,6 +236,14 @@ public: // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); +public slots: + void loadURLFinished(bool success); + void loadCollisionModelURLFinished(bool success); + +signals: + void setURLFinished(bool success); + void setCollisionModelURLFinished(bool success); + protected: void setPupilDilation(float dilation) { _pupilDilation = dilation; } From ed4b0b3589d700b532eb546cca007900826cd7a8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 09:57:17 -0700 Subject: [PATCH 03/23] call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that we don't redo this every time we receive an identity packet from the avatar with the bad url. --- interface/src/avatar/Avatar.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f09eb5bdec..001dfea10b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -920,7 +920,9 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { void Avatar::setModelURLFinished(bool success) { if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) { qDebug() << "Using default after failing to load Avatar model: " << _skeletonModelURL; - QMetaObject::invokeMethod(this, "setSkeletonModelURL", + // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that + // we don't redo this every time we receive an identity packet from the avatar with the bad url. + QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); } } From 229b8d3b5ebd795087729bd336a5cdaa4d25a778 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 10:46:11 -0700 Subject: [PATCH 04/23] testing a more explicit fix of the audio failure --- interface/src/avatar/Avatar.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 001dfea10b..ab9c4b2f79 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -299,7 +299,9 @@ void Avatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("head"); glm::vec3 headPosition = getPosition(); - _skeletonModel->getHeadPosition(headPosition); + if (!_skeletonModel->getHeadPosition(headPosition)) { + headPosition = getPosition(); + } Head* head = getHead(); head->setPosition(headPosition); head->setScale(getUniformScale()); @@ -922,8 +924,8 @@ void Avatar::setModelURLFinished(bool success) { qDebug() << "Using default after failing to load Avatar model: " << _skeletonModelURL; // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that // we don't redo this every time we receive an identity packet from the avatar with the bad url. - QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", - Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); + // QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", + // Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); } } From 56af36ae64f27eeddf390b1d642341e401228dca Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 11:29:43 -0700 Subject: [PATCH 05/23] set head position of other avatars even if they can't be drawn --- interface/src/avatar/Avatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ab9c4b2f79..45cdba9ace 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -309,6 +309,7 @@ void Avatar::simulate(float deltaTime) { } } else { // a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated. + getHead()->setPosition(getPosition()); _skeletonModel->simulate(deltaTime, false); } From 75f9626c2d046773c9e5ff527569db55749fe86f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 11:50:53 -0700 Subject: [PATCH 06/23] if MyAvatar simulation is cut short (due to no skeleton), still update the head position --- interface/src/avatar/MyAvatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index eef176338f..de5455fc14 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -430,6 +430,7 @@ void MyAvatar::simulate(float deltaTime) { if (!_skeletonModel->hasSkeleton()) { // All the simulation that can be done has been done + getHead()->setPosition(getPosition()); // so audio-position isn't 0,0,0 return; } From f91df4997d7a2f8179cc394c3e673ddb010b1304 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 11:55:11 -0700 Subject: [PATCH 07/23] re-enable falling-back to default avatar if an avatar's url is bad --- interface/src/avatar/Avatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 45cdba9ace..b1b30a1acd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -925,8 +925,8 @@ void Avatar::setModelURLFinished(bool success) { qDebug() << "Using default after failing to load Avatar model: " << _skeletonModelURL; // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that // we don't redo this every time we receive an identity packet from the avatar with the bad url. - // QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", - // Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); + QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", + Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); } } From 79121133dfc6e7528d8de0c91fe42ed20ccc4991 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 12:00:45 -0700 Subject: [PATCH 08/23] remove unneeded change --- interface/src/avatar/Avatar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f646fe57f4..910f2cc1e6 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -115,7 +115,7 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } - Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; void setShowDisplayName(bool showDisplayName); From 363915b836e3a327231ffed1ae859fa8a5fa6234 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Aug 2016 19:37:38 -0700 Subject: [PATCH 09/23] switch audio script to use a valid but invisible avatar url --- .../audioExamples/acAudioSearching/ACAudioSearchAndInject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js b/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js index 30567b4fc7..daef1d5db3 100644 --- a/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js +++ b/script-archive/audioExamples/acAudioSearching/ACAudioSearchAndInject.js @@ -40,7 +40,7 @@ var DEFAULT_SOUND_DATA = { Script.include("../../libraries/utils.js"); Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. -Avatar.skeletonModelURL = "http://invalid-url"; +Avatar.skeletonModelURL = "http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst"; function ignore() {} function debug() { // Display the arguments not just [Object object]. //print.apply(null, [].map.call(arguments, JSON.stringify)); From c743cf379ee23367924adaabf01f2e5c93b9965d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 3 Aug 2016 11:31:51 -0700 Subject: [PATCH 10/23] use loadCollisionModelURLFinished when collisions model is finished --- libraries/render-utils/src/Model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bedd158f2a..d755dc3aca 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -112,7 +112,7 @@ Model::Model(RigPointer rig, QObject* parent) : setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); - connect(&_collisionWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); + connect(&_collisionWatcher, &GeometryResourceWatcher::finished, this, &Model::loadCollisionModelURLFinished); } Model::~Model() { From f9b6db12e3f1ebc5211f607e7483d8ded75e2df0 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Wed, 3 Aug 2016 13:48:27 -0700 Subject: [PATCH 11/23] Fix parsing of embedded entity scripts Now correctly identifies when scripts are not urls as well as javascript: urls. --- libraries/script-engine/src/ScriptCache.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 2114289095..d80baf9a7b 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -110,11 +110,18 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable QUrl url = ResourceManager::normalizeURL(unnormalizedURL); // attempt to determine if this is a URL to a script, or if this is actually a script itself (which is valid in the entityScript use case) - if (url.scheme().isEmpty() && scriptOrURL.simplified().replace(" ", "").contains("(function(){")) { + if (unnormalizedURL.scheme().isEmpty() && scriptOrURL.simplified().replace(" ", "").contains("(function(){")) { contentAvailable(scriptOrURL, scriptOrURL, false, true); return; } + // give a similar treatment to javacript: urls + if (unnormalizedURL.scheme() == "javascript") { + QString contents{ scriptOrURL }; + contents.replace(QRegExp("^javascript:"), ""); + contentAvailable(scriptOrURL, contents, false, true); + } + Lock lock(_containerLock); if (_scriptCache.contains(url) && !forceDownload) { auto scriptContent = _scriptCache[url]; From 78e59106b40b63c833c7f533ff4fe7bb078d729e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 3 Aug 2016 15:21:49 -0700 Subject: [PATCH 12/23] adjust threshold for how far above the ground will cause the avatar to auto-fly --- libraries/physics/src/CharacterController.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 30fb3536ca..df166ceb59 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -540,7 +540,8 @@ void CharacterController::preSimulation() { btScalar rayLength = _radius + MAX_FALL_HEIGHT; btVector3 rayEnd = rayStart - rayLength * _currentUp; - const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; + const btScalar FLY_TO_GROUND_THRESHOLD = 0.1f * _radius; + const btScalar GROUND_TO_AUTOFLY_THRESHOLD = 0.5f * _radius; const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 250 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 1100 * MSECS_PER_SECOND; @@ -581,7 +582,7 @@ void CharacterController::preSimulation() { _takeoffJumpButtonID = _jumpButtonDownCount; _takeoffToInAirStartTime = now; SET_STATE(State::Takeoff, "jump pressed"); - } else if (rayHasHit && !_hasSupport && _floorDistance > JUMP_PROXIMITY_THRESHOLD) { + } else if (rayHasHit && !_hasSupport && _floorDistance > GROUND_TO_AUTOFLY_THRESHOLD) { SET_STATE(State::InAir, "falling"); } break; @@ -595,7 +596,7 @@ void CharacterController::preSimulation() { } break; case State::InAir: { - if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { + if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport)) { SET_STATE(State::Ground, "hit ground"); } else { btVector3 desiredVelocity = _targetVelocity; @@ -614,7 +615,7 @@ void CharacterController::preSimulation() { case State::Hover: if ((_floorDistance < MIN_HOVER_HEIGHT) && !jumpButtonHeld && !flyingFast) { SET_STATE(State::InAir, "near ground"); - } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !flyingFast) { + } else if (((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport) && !flyingFast) { SET_STATE(State::Ground, "touching ground"); } break; From a826f4eca1c689ec641b0f43393adab0fa73fe46 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Wed, 3 Aug 2016 15:55:51 -0700 Subject: [PATCH 13/23] Fix console errors for javascript: urls --- libraries/script-engine/src/ScriptCache.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index d80baf9a7b..40234e8134 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -109,17 +110,20 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable QUrl unnormalizedURL(scriptOrURL); QUrl url = ResourceManager::normalizeURL(unnormalizedURL); - // attempt to determine if this is a URL to a script, or if this is actually a script itself (which is valid in the entityScript use case) - if (unnormalizedURL.scheme().isEmpty() && scriptOrURL.simplified().replace(" ", "").contains("(function(){")) { + // attempt to determine if this is a URL to a script, or if this is actually a script itself (which is valid in the + // entityScript use case) + if (unnormalizedURL.scheme().isEmpty() && + scriptOrURL.simplified().replace(" ", "").contains(QRegularExpression(R"(\(function\([a-z]?[\w,]*\){)"))) { contentAvailable(scriptOrURL, scriptOrURL, false, true); return; } // give a similar treatment to javacript: urls if (unnormalizedURL.scheme() == "javascript") { - QString contents{ scriptOrURL }; - contents.replace(QRegExp("^javascript:"), ""); + QString contents { scriptOrURL }; + contents.replace(QRegularExpression("^javascript:"), ""); contentAvailable(scriptOrURL, contents, false, true); + return; } Lock lock(_containerLock); @@ -140,6 +144,7 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif auto request = ResourceManager::createResourceRequest(nullptr, url); + Q_ASSERT(request); request->setCacheEnabled(!forceDownload); connect(request, &ResourceRequest::finished, this, &ScriptCache::scriptContentAvailable); request->send(); From ba49fd2c6133ab6c649df51fc8181e39861d117f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 4 Aug 2016 09:19:01 -0700 Subject: [PATCH 14/23] don't heartbeat immediately unless metaverse domain --- domain-server/src/DomainServer.cpp | 85 ++++++++++++++++++++---------- domain-server/src/DomainServer.h | 8 +++ 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 23e37efaf1..d352cb375f 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -117,9 +117,18 @@ DomainServer::DomainServer(int argc, char* argv[]) : _settingsManager.apiRefreshGroupInformation(); setupNodeListAndAssignments(); + + if (_type == MetaverseDomain) { + // if we have a metaverse domain, we'll need an access token to heartbeat handle auto-networking + resetAccountManagerAccessToken(); + } + setupAutomaticNetworking(); - if (!getID().isNull()) { + + if (!getID().isNull() && _type != NonMetaverse) { + // setup periodic heartbeats to metaverse API setupHeartbeatToMetaverse(); + // send the first heartbeat immediately sendHeartbeatToMetaverse(); } @@ -301,16 +310,22 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { // store the new ID and auto networking setting on disk _settingsManager.persistToFile(); - // change our domain ID immediately - DependencyManager::get()->setSessionUUID(QUuid { id }); - // store the new token to the account info auto accountManager = DependencyManager::get(); accountManager->setTemporaryDomain(id, key); + // change our domain ID immediately + DependencyManager::get()->setSessionUUID(QUuid { id }); + + // change our type to reflect that we are a temporary domain now + _type = MetaverseTemporaryDomain; + // update our heartbeats to use the correct id setupICEHeartbeatForFullNetworking(); setupHeartbeatToMetaverse(); + + // if we have a current ICE server address, update it in the API for the new temporary domain + sendICEServerAddressToMetaverseAPI(); } else { qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again" << "via domain-server relaunch or from the domain-server settings."; @@ -394,6 +409,16 @@ void DomainServer::setupNodeListAndAssignments() { const QVariant* idValueVariant = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH); if (idValueVariant) { nodeList->setSessionUUID(idValueVariant->toString()); + + // if we have an ID, we'll assume we're a metaverse domain + // now see if we think we're a temp domain (we have an API key) or a full domain + const auto& temporaryDomainKey = DependencyManager::get()->getTemporaryDomainKey(getID()); + if (temporaryDomainKey.isEmpty()) { + _type = MetaverseDomain; + } else { + _type = MetaverseTemporaryDomain; + } + } else { nodeList->setSessionUUID(QUuid::createUuid()); // Use random UUID } @@ -477,42 +502,46 @@ bool DomainServer::resetAccountManagerAccessToken() { } void DomainServer::setupAutomaticNetworking() { - qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; - - resetAccountManagerAccessToken(); _automaticNetworkingSetting = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); - auto nodeList = DependencyManager::get(); - const QUuid& domainID = getID(); + qDebug() << "Configuring automatic networking in domain-server as" << _automaticNetworkingSetting; - if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { - setupICEHeartbeatForFullNetworking(); - } + if (_automaticNetworkingSetting != DISABLED_AUTOMATIC_NETWORKING_VALUE) { + const QUuid& domainID = getID(); - if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || - _automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { + if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { + setupICEHeartbeatForFullNetworking(); + } - if (!domainID.isNull()) { - qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID" - << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); + if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || + _automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { - if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { - // send any public socket changes to the data server so nodes can find us at our new IP - connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged, - this, &DomainServer::performIPAddressUpdate); + if (!domainID.isNull()) { + qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID" + << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); - // have the LNL enable public socket updating via STUN - nodeList->startSTUNPublicSocketUpdate(); + if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { + + auto nodeList = DependencyManager::get(); + + // send any public socket changes to the data server so nodes can find us at our new IP + connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged, + this, &DomainServer::performIPAddressUpdate); + + // have the LNL enable public socket updating via STUN + nodeList->startSTUNPublicSocketUpdate(); + } + } else { + qDebug() << "Cannot enable domain-server automatic networking without a domain ID." + << "Please add an ID to your config file or via the web interface."; + + return; } - } else { - qDebug() << "Cannot enable domain-server automatic networking without a domain ID." - << "Please add an ID to your config file or via the web interface."; - - return; } } + } void DomainServer::setupHeartbeatToMetaverse() { diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 4004333789..06b3ed2c0a 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -42,6 +42,12 @@ public: DomainServer(int argc, char* argv[]); ~DomainServer(); + enum DomainType { + NonMetaverse, + MetaverseDomain, + MetaverseTemporaryDomain + }; + static int const EXIT_CODE_REBOOT; bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); @@ -195,6 +201,8 @@ private: int _numHeartbeatDenials { 0 }; bool _connectedToICEServer { false }; + DomainType _type { DomainType::NonMetaverse }; + friend class DomainGatekeeper; friend class DomainMetadata; }; From f3e30221f0553fe33ed772d06c0a95e0274edf30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 4 Aug 2016 09:32:01 -0700 Subject: [PATCH 15/23] only force a new temp name if already a temp domain-server --- domain-server/src/DomainServer.cpp | 63 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d352cb375f..6c4b12d4c0 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1168,42 +1168,45 @@ void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) { return; } - // check if we need to force a new temporary domain name - switch (requestReply.error()) { - // if we have a temporary domain with a bad token, we get a 401 - case QNetworkReply::NetworkError::AuthenticationRequiredError: { - static const QString DATA_KEY = "data"; - static const QString TOKEN_KEY = "api_key"; + // only attempt to grab a new temporary name if we're already a temporary domain server + if (_type == MetaverseTemporaryDomain) { + // check if we need to force a new temporary domain name + switch (requestReply.error()) { + // if we have a temporary domain with a bad token, we get a 401 + case QNetworkReply::NetworkError::AuthenticationRequiredError: { + static const QString DATA_KEY = "data"; + static const QString TOKEN_KEY = "api_key"; - QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); - auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; - if (!tokenFailure.isNull()) { - qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; + if (!tokenFailure.isNull()) { + qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; + } + break; } - break; + // if the domain does not (or no longer) exists, we get a 404 + case QNetworkReply::NetworkError::ContentNotFoundError: + qWarning() << "Domain not found, getting a new temporary domain."; + break; + // otherwise, we erred on something else, and should not force a temporary domain + default: + return; } - // if the domain does not (or no longer) exists, we get a 404 - case QNetworkReply::NetworkError::ContentNotFoundError: - qWarning() << "Domain not found, getting a new temporary domain."; - break; - // otherwise, we erred on something else, and should not force a temporary domain - default: - return; - } - // halt heartbeats until we have a token - _metaverseHeartbeatTimer->deleteLater(); - _metaverseHeartbeatTimer = nullptr; + // halt heartbeats until we have a token + _metaverseHeartbeatTimer->deleteLater(); + _metaverseHeartbeatTimer = nullptr; - // give up eventually to avoid flooding traffic - static const int MAX_ATTEMPTS = 5; - static int attempt = 0; - if (++attempt < MAX_ATTEMPTS) { - // get a new temporary name and token - getTemporaryName(true); - } else { - qWarning() << "Already attempted too many temporary domain requests. Please set a domain ID manually or restart."; + // give up eventually to avoid flooding traffic + static const int MAX_ATTEMPTS = 5; + static int attempt = 0; + if (++attempt < MAX_ATTEMPTS) { + // get a new temporary name and token + getTemporaryName(true); + } else { + qWarning() << "Already attempted too many temporary domain requests. Please set a domain ID manually or restart."; + } } } From e1c7ced652720642ed032a966fa38400828245cb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 09:54:26 -0700 Subject: [PATCH 16/23] increase GROUND_TO_AUTOFLY_THRESHOLD --- libraries/physics/src/CharacterController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index df166ceb59..1c6836769b 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -541,7 +541,7 @@ void CharacterController::preSimulation() { btVector3 rayEnd = rayStart - rayLength * _currentUp; const btScalar FLY_TO_GROUND_THRESHOLD = 0.1f * _radius; - const btScalar GROUND_TO_AUTOFLY_THRESHOLD = 0.5f * _radius; + const btScalar GROUND_TO_AUTOFLY_THRESHOLD = 1.2f * _radius; const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 250 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 1100 * MSECS_PER_SECOND; From 4c258b95682e49ad15f9bca28f705e2c8a85e824 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 10:16:08 -0700 Subject: [PATCH 17/23] fix bug which caused getValue for a non-existent key to return the integer 2 --- libraries/shared/src/SettingManager.cpp | 7 +++---- libraries/shared/src/SettingManager.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/SettingManager.cpp b/libraries/shared/src/SettingManager.cpp index abb8525b03..2ccee513da 100644 --- a/libraries/shared/src/SettingManager.cpp +++ b/libraries/shared/src/SettingManager.cpp @@ -70,11 +70,10 @@ namespace Setting { QVariant handleValue = UNSET_VALUE; if (handle->isSet()) { handleValue = handle->getVariant(); + withWriteLock([&] { + _pendingChanges[key] = handleValue; + }); } - - withWriteLock([&] { - _pendingChanges[key] = handleValue; - }); } static const int SAVE_INTERVAL_MSEC = 5 * 1000; // 5 sec diff --git a/libraries/shared/src/SettingManager.h b/libraries/shared/src/SettingManager.h index 1f309c966f..ffdd4ba42a 100644 --- a/libraries/shared/src/SettingManager.h +++ b/libraries/shared/src/SettingManager.h @@ -46,7 +46,7 @@ namespace Setting { private: QHash _handles; QPointer _saveTimer = nullptr; - const QVariant UNSET_VALUE { QUuid::createUuid().variant() }; + const QVariant UNSET_VALUE { QUuid::createUuid() }; QHash _pendingChanges; friend class Interface; From 7629e34586702d3172d643f9cea8b01ff7562f55 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 4 Aug 2016 11:05:34 -0700 Subject: [PATCH 18/23] optimized distance-attnuation calculation --- assignment-client/src/audio/AudioMixer.cpp | 59 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8f752e70d0..eabb4955d9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -100,6 +100,63 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f; +const int IEEE754_MANT_BITS = 23; +const int IEEE754_EXPN_BIAS = 127; + +// +// for x > 0.0f, returns log2(x) +// for x <= 0.0f, returns large negative value +// +// abs |error| < 8e-3, smooth (exact for x=2^N) for NPOLY=3 +// abs |error| < 2e-4, smooth (exact for x=2^N) for NPOLY=5 +// rel |error| < 0.4 from precision loss very close to 1.0f +// +static inline float fastlog2(float x) { + + union { float f; int32_t i; } mant, bits = { x }; + + // split into mantissa and exponent + mant.i = (bits.i & ((1 << IEEE754_MANT_BITS) - 1)) | (IEEE754_EXPN_BIAS << IEEE754_MANT_BITS); + int32_t expn = (bits.i >> IEEE754_MANT_BITS) - IEEE754_EXPN_BIAS; + + mant.f -= 1.0f; + + // polynomial for log2(1+x) over x=[0,1] + //x = (-0.346555386f * mant.f + 1.346555386f) * mant.f; + x = (((-0.0821307180f * mant.f + 0.321188984f) * mant.f - 0.677784014f) * mant.f + 1.43872575f) * mant.f; + + return x + expn; +} + +// +// for -126 <= x < 128, returns exp2(x) +// +// rel |error| < 3e-3, smooth (exact for x=N) for NPOLY=3 +// rel |error| < 9e-6, smooth (exact for x=N) for NPOLY=5 +// +static inline float fastexp2(float x) { + + union { float f; int32_t i; } xi; + + // bias such that x > 0 + x += IEEE754_EXPN_BIAS; + //x = MAX(x, 1.0f); + //x = MIN(x, 254.9999f); + + // split into integer and fraction + xi.i = (int32_t)x; + x -= xi.i; + + // construct exp2(xi) as a float + xi.i <<= IEEE754_MANT_BITS; + + // polynomial for exp2(x) over x=[0,1] + //x = (0.339766028f * x + 0.660233972f) * x + 1.0f; + x = (((0.0135557472f * x + 0.0520323690f) * x + 0.241379763f) * x + 0.693032121f) * x + 1.0f; + + return x * xi.f; +} + float AudioMixer::gainForSource(const PositionalAudioStream& streamToAdd, const AvatarAudioStream& listeningNodeStream, const glm::vec3& relativePosition, bool isEcho) { float gain = 1.0f; @@ -148,7 +205,7 @@ float AudioMixer::gainForSource(const PositionalAudioStream& streamToAdd, g = (g > 1.0f) ? 1.0f : g; // calculate the distance coefficient using the distance to this node - float distanceCoefficient = exp2f(log2f(g) * log2f(distanceBetween/ATTENUATION_BEGINS_AT_DISTANCE)); + float distanceCoefficient = fastexp2(fastlog2(g) * fastlog2(distanceBetween/ATTENUATION_BEGINS_AT_DISTANCE)); // multiply the current attenuation coefficient by the distance coefficient gain *= distanceCoefficient; From aeadbda1e171cfe67f19af7dcf687c02812b5171 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 11:34:42 -0700 Subject: [PATCH 19/23] adjust ground-to-fly logic --- libraries/physics/src/CharacterController.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 1c6836769b..b5ef03be0f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -534,14 +534,14 @@ void CharacterController::preSimulation() { // scan for distant floor // rayStart is at center of bottom sphere - btVector3 rayStart = _characterBodyTransform.getOrigin() - _halfHeight * _currentUp; + btVector3 rayStart = _characterBodyTransform.getOrigin(); // rayEnd is straight down MAX_FALL_HEIGHT btScalar rayLength = _radius + MAX_FALL_HEIGHT; btVector3 rayEnd = rayStart - rayLength * _currentUp; const btScalar FLY_TO_GROUND_THRESHOLD = 0.1f * _radius; - const btScalar GROUND_TO_AUTOFLY_THRESHOLD = 1.2f * _radius; + const btScalar GROUND_TO_FLY_THRESHOLD = 0.8f * _radius + _halfHeight; const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 250 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 1100 * MSECS_PER_SECOND; @@ -554,7 +554,7 @@ void CharacterController::preSimulation() { bool rayHasHit = rayCallback.hasHit(); if (rayHasHit) { _rayHitStartTime = now; - _floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius; + _floorDistance = rayLength * rayCallback.m_closestHitFraction - (_radius + _halfHeight); } else if ((now - _rayHitStartTime) < RAY_HIT_START_PERIOD) { rayHasHit = true; } else { @@ -582,7 +582,7 @@ void CharacterController::preSimulation() { _takeoffJumpButtonID = _jumpButtonDownCount; _takeoffToInAirStartTime = now; SET_STATE(State::Takeoff, "jump pressed"); - } else if (rayHasHit && !_hasSupport && _floorDistance > GROUND_TO_AUTOFLY_THRESHOLD) { + } else if (rayHasHit && !_hasSupport && _floorDistance > GROUND_TO_FLY_THRESHOLD) { SET_STATE(State::InAir, "falling"); } break; From 45c21ca52391d7590737519b02abfc47a404b30a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 13:37:08 -0700 Subject: [PATCH 20/23] make UNSET_VALUE still work while still returning and empty string value for undefined keys --- libraries/shared/src/SettingHandle.cpp | 6 +++++- libraries/shared/src/SettingManager.cpp | 9 +++++---- libraries/shared/src/SettingManager.h | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index 13f9ea48ce..ae0f54104e 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -89,7 +89,11 @@ void Settings::setValue(const QString& name, const QVariant& value) { } QVariant Settings::value(const QString& name, const QVariant& defaultValue) const { - return _manager->value(name, defaultValue); + QVariant result = _manager->value(name, defaultValue); + if (result == _manager->unsetValue()) { + return QVariant(QString()); + } + return result; } diff --git a/libraries/shared/src/SettingManager.cpp b/libraries/shared/src/SettingManager.cpp index 2ccee513da..a42e62c1c8 100644 --- a/libraries/shared/src/SettingManager.cpp +++ b/libraries/shared/src/SettingManager.cpp @@ -53,7 +53,7 @@ namespace Setting { const auto& key = handle->getKey(); withWriteLock([&] { QVariant loadedValue; - if (_pendingChanges.contains(key)) { + if (_pendingChanges.contains(key) && _pendingChanges[key] != UNSET_VALUE) { loadedValue = _pendingChanges[key]; } else { loadedValue = value(key); @@ -70,10 +70,11 @@ namespace Setting { QVariant handleValue = UNSET_VALUE; if (handle->isSet()) { handleValue = handle->getVariant(); - withWriteLock([&] { - _pendingChanges[key] = handleValue; - }); } + + withWriteLock([&] { + _pendingChanges[key] = handleValue; + }); } static const int SAVE_INTERVAL_MSEC = 5 * 1000; // 5 sec diff --git a/libraries/shared/src/SettingManager.h b/libraries/shared/src/SettingManager.h index ffdd4ba42a..836c522342 100644 --- a/libraries/shared/src/SettingManager.h +++ b/libraries/shared/src/SettingManager.h @@ -28,6 +28,7 @@ namespace Setting { public: void customDeleter() override; + QVariant unsetValue() { return UNSET_VALUE; } protected: ~Manager(); From 981a8d76facb774a1264c0861ba5456b0acd3446 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 13:47:43 -0700 Subject: [PATCH 21/23] code review --- libraries/shared/src/SettingHandle.cpp | 2 +- libraries/shared/src/SettingManager.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index ae0f54104e..71427d1554 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -91,7 +91,7 @@ void Settings::setValue(const QString& name, const QVariant& value) { QVariant Settings::value(const QString& name, const QVariant& defaultValue) const { QVariant result = _manager->value(name, defaultValue); if (result == _manager->unsetValue()) { - return QVariant(QString()); + return defaultValue; } return result; } diff --git a/libraries/shared/src/SettingManager.h b/libraries/shared/src/SettingManager.h index 836c522342..e785c5f147 100644 --- a/libraries/shared/src/SettingManager.h +++ b/libraries/shared/src/SettingManager.h @@ -28,7 +28,7 @@ namespace Setting { public: void customDeleter() override; - QVariant unsetValue() { return UNSET_VALUE; } + const QVariant& unsetValue() { return UNSET_VALUE; } protected: ~Manager(); From a2441ca84c4b66bb66639c6ccf33599efe2890b3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 14:09:12 -0700 Subject: [PATCH 22/23] back out some uneeded chagnes --- libraries/shared/src/SettingHandle.cpp | 6 +----- libraries/shared/src/SettingManager.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index 71427d1554..13f9ea48ce 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -89,11 +89,7 @@ void Settings::setValue(const QString& name, const QVariant& value) { } QVariant Settings::value(const QString& name, const QVariant& defaultValue) const { - QVariant result = _manager->value(name, defaultValue); - if (result == _manager->unsetValue()) { - return defaultValue; - } - return result; + return _manager->value(name, defaultValue); } diff --git a/libraries/shared/src/SettingManager.h b/libraries/shared/src/SettingManager.h index e785c5f147..ffdd4ba42a 100644 --- a/libraries/shared/src/SettingManager.h +++ b/libraries/shared/src/SettingManager.h @@ -28,7 +28,6 @@ namespace Setting { public: void customDeleter() override; - const QVariant& unsetValue() { return UNSET_VALUE; } protected: ~Manager(); From 3ca1ee1d82ca9292ad2e26a5d907c3e576332887 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 4 Aug 2016 17:39:41 -0700 Subject: [PATCH 23/23] Fix some group-related code to handle CamelCase usernames --- domain-server/src/DomainGatekeeper.cpp | 2 +- domain-server/src/DomainServerSettingsManager.cpp | 12 ++++++------ domain-server/src/DomainServerSettingsManager.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 8f8c8e001c..c827e79223 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -182,7 +182,7 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin GroupRank rank = _server->_settingsManager.getGroupRank(groupID, rankID); #ifdef WANT_DEBUG - qDebug() << "| user-permissions: user is in group:" << groupID << " rank:" + qDebug() << "| user-permissions: user " << verifiedUsername << "is in group:" << groupID << " rank:" << rank.name << "so:" << userPerms; #endif } diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index dc49bc6126..47187fac5c 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -356,7 +356,7 @@ void DomainServerSettingsManager::initializeGroupPermissions(NodePermissionsMap& if (nameKey.first.toLower() != groupNameLower) { continue; } - QUuid groupID = _groupIDs[groupNameLower]; + QUuid groupID = _groupIDs[groupNameLower.toLower()]; QUuid rankID = nameKey.second; GroupRank rank = _groupRanks[groupID][rankID]; if (rank.order == 0) { @@ -1477,14 +1477,14 @@ void DomainServerSettingsManager::apiGetGroupRanksErrorCallback(QNetworkReply& r void DomainServerSettingsManager::recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID) { if (rankID != QUuid()) { - _groupMembership[name][groupID] = rankID; + _groupMembership[name.toLower()][groupID] = rankID; } else { - _groupMembership[name].remove(groupID); + _groupMembership[name.toLower()].remove(groupID); } } QUuid DomainServerSettingsManager::isGroupMember(const QString& name, const QUuid& groupID) { - const QHash& groupsForName = _groupMembership[name]; + const QHash& groupsForName = _groupMembership[name.toLower()]; if (groupsForName.contains(groupID)) { return groupsForName[groupID]; } @@ -1528,7 +1528,7 @@ void DomainServerSettingsManager::debugDumpGroupsState() { qDebug() << "_groupIDs:"; foreach (QString groupName, _groupIDs.keys()) { - qDebug() << "| " << groupName << "==>" << _groupIDs[groupName]; + qDebug() << "| " << groupName << "==>" << _groupIDs[groupName.toLower()]; } qDebug() << "_groupNames:"; @@ -1548,7 +1548,7 @@ void DomainServerSettingsManager::debugDumpGroupsState() { qDebug() << "_groupMembership"; foreach (QString userName, _groupMembership.keys()) { - QHash& groupsForUser = _groupMembership[userName]; + QHash& groupsForUser = _groupMembership[userName.toLower()]; QString line = ""; foreach (QUuid groupID, groupsForUser.keys()) { line += " g=" + groupID.toString() + ",r=" + groupsForUser[groupID].toString(); diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 144589326c..c067377ffc 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -84,7 +84,7 @@ public: QList getBlacklistGroupIDs(); // these are used to locally cache the result of calling "api/v1/groups/.../is_member/..." on metaverse's api - void clearGroupMemberships(const QString& name) { _groupMembership[name].clear(); } + void clearGroupMemberships(const QString& name) { _groupMembership[name.toLower()].clear(); } void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID); QUuid isGroupMember(const QString& name, const QUuid& groupID); // returns rank or -1 if not a member