From e4ef3ae8697f8431c8f4191a43eda3b3b2f0d289 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Feb 2016 15:06:53 -0800 Subject: [PATCH 01/37] automatically save adjustments to offset of equipped items --- examples/attachedEntitiesManager.js | 37 ++++++++++++---------- examples/controllers/handControllerGrab.js | 10 +++--- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/examples/attachedEntitiesManager.js b/examples/attachedEntitiesManager.js index f44564d6dc..01f8f861c9 100644 --- a/examples/attachedEntitiesManager.js +++ b/examples/attachedEntitiesManager.js @@ -116,6 +116,7 @@ function AttachedEntitiesManager() { manager.checkIfWearable(parsedMessage.grabbedEntity, parsedMessage.joint) // manager.saveAttachedEntities(); } else if (parsedMessage.action === 'shared-release') { + manager.updateRelativeOffsets(parsedMessage.grabbedEntity); // manager.saveAttachedEntities(); } else if (parsedMessage.action === 'equip') { // manager.saveAttachedEntities(); @@ -173,11 +174,12 @@ function AttachedEntitiesManager() { parentJointIndex: bestJointIndex }; - if (!this.avatarIsInDressingRoom() && - bestJointOffset && bestJointOffset.constructor === Array && bestJointOffset.length > 1) { - // don't snap the entity to the preferred position if the avatar is in the dressing room. - wearProps.localPosition = bestJointOffset[0]; - wearProps.localRotation = bestJointOffset[1]; + if (bestJointOffset && bestJointOffset.constructor === Array && bestJointOffset.length > 1) { + if (!this.avatarIsInDressingRoom()) { + // don't snap the entity to the preferred position if the avatar is in the dressing room. + wearProps.localPosition = bestJointOffset[0]; + wearProps.localRotation = bestJointOffset[1]; + } } Entities.editEntity(grabbedEntity, wearProps); } else if (props.parentID != NULL_UUID) { @@ -189,12 +191,19 @@ function AttachedEntitiesManager() { } } - this.updateRelativeOffsets = function(entityID, props) { + this.updateRelativeOffsets = function(entityID) { // save the preferred (current) relative position and rotation into the user-data of the entity - var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA); - var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex]; - wearableData.joints[currentJointName] = [props.localPosition, props.localRotation]; - setEntityCustomData('wearable', entityID, wearableData); + var props = Entities.getEntityProperties(entityID); + if (props.parentID == MyAvatar.sessionUUID) { + grabData = getEntityCustomData('grabKey', entityID, {}); + grabbableData = getEntityCustomData('grabbableKey', entityID, {}); + var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA); + var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex]; + wearableData.joints[currentJointName] = [props.localPosition, props.localRotation]; + setEntityCustomData('wearable', entityID, wearableData); + return true; + } + return false; } this.saveAttachedEntities = function() { @@ -203,12 +212,8 @@ function AttachedEntitiesManager() { var nearbyEntities = Entities.findEntities(MyAvatar.position, ATTACHED_ENTITY_SEARCH_DISTANCE); for (i = 0; i < nearbyEntities.length; i++) { var entityID = nearbyEntities[i]; - var props = Entities.getEntityProperties(entityID); - if (props.parentID == MyAvatar.sessionUUID) { - grabData = getEntityCustomData('grabKey', entityID, {}); - grabbableData = getEntityCustomData('grabbableKey', entityID, {}); - this.updateRelativeOffsets(entityID, props); - props = Entities.getEntityProperties(entityID); // refresh, because updateRelativeOffsets changed them + if (this.updateRelativeOffsets(entityID)) { + var props = Entities.getEntityProperties(entityID); // refresh, because updateRelativeOffsets changed them this.scrubProperties(props); saveData.push(props); } diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 838134cfff..842c54b86d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1217,10 +1217,12 @@ function MyController(hand) { this.hasPresetOffsets = function() { var wearableData = getEntityCustomData('wearable', this.grabbedEntity, {joints: {}}); - var allowedJoints = wearableData.joints; - var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; - if (handJointName in allowedJoints) { - return true; + if ("joints" in wearableData) { + var allowedJoints = wearableData.joints; + var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; + if (handJointName in allowedJoints) { + return true; + } } } From 25fe8583c8c5ef6a6d26a9b0f27590537be9cf70 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 1 Feb 2016 16:48:15 -0800 Subject: [PATCH 02/37] decrease all volume --- .../DomainContent/CellScience/Scripts/playBackgroundAudio.js | 2 +- .../DomainContent/CellScience/Scripts/showButtonToPlaySound.js | 2 +- .../DomainContent/CellScience/Scripts/showIdentification.js | 2 +- unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js b/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js index 0cb348c3f4..4bde42fb38 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js @@ -20,7 +20,7 @@ stereo: true, loop: true, localOnly: true, - volume: 0.5 + volume: 0.2 }; this.sound = SoundCache.getSound(self.soundURL); diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js index e505a532e3..7e51dcd9d1 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js @@ -24,7 +24,7 @@ stereo: true, loop: false, localOnly: true, - volume: 0.5 + volume: 0.2 }; this.sound = SoundCache.getSound(this.soundURL); } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index c0b0cb54d4..bfc6c70292 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -22,7 +22,7 @@ stereo: true, loop: false, localOnly: true, - volume: 0.5, + volume: 0.2, position: this.position }; this.sound = SoundCache.getSound(this.soundURL); diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index d69f33e7c9..c644cbe4f9 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -25,7 +25,7 @@ loop: false, localOnly: false, position: this.position, - volume: 0.5 + volume: 0.2 }; this.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); //print('Script.clearTimeout PRELOADING A ZOOM ENTITY') From 822a64a08b7366923e01705369274f139c4b91f0 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 1 Feb 2016 17:16:27 -0800 Subject: [PATCH 03/37] decrease volume --- .../DomainContent/CellScience/Scripts/playBackgroundAudio.js | 2 +- .../DomainContent/CellScience/importCellScience.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js b/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js index 4bde42fb38..e709f6e06e 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js @@ -8,7 +8,7 @@ (function() { var self = this; var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; - var version = 8; + var version = 9; this.preload = function(entityId) { self.soundPlaying = false; self.entityId = entityId; diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index b456c4a1ce..58888584a9 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1003; +var version = 1004; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From 2501be16cbc3bf5760699b1d1e7f8562da82526b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Feb 2016 18:11:27 -0800 Subject: [PATCH 04/37] base palm position on finger joint rather than an offset from hand joint. double size of near-grab sphere --- examples/controllers/handControllerGrab.js | 42 ++++++++++++++++++++-- interface/src/avatar/Avatar.cpp | 12 +++++-- interface/src/avatar/SkeletonModel.cpp | 16 +++++++++ interface/src/avatar/SkeletonModel.h | 3 ++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 074b72c9f4..3695c6c3f8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -69,13 +69,14 @@ var PICK_MAX_DISTANCE = 500; // max length of pick-ray // near grabbing // -var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var GRAB_RADIUS = 0.06; // if the ray misses but an object is this close, it will still be selected var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed +var SHOW_GRAB_SPHERE = false; // draw a green sphere to show the grab search position and size // // equip @@ -256,6 +257,7 @@ function MyController(hand) { //for visualizations this.overlayLine = null; this.particleBeamObject = null; + this.grabSphere = null; //for lights this.spotlight = null; @@ -336,6 +338,7 @@ function MyController(hand) { } this.setState = function(newState) { + this.grabSphereOff(); if (WANT_DEBUG || WANT_DEBUG_STATE) { print("STATE (" + this.hand + "): " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); @@ -416,6 +419,37 @@ function MyController(hand) { } } + this.grabSphereOn = function() { + var color = {red: 0, green: 255, blue: 0}; + if (this.grabSphere === null) { + var sphereProperties = { + position: this.getHandPosition(), + size: GRAB_RADIUS*2, + color: color, + alpha: 0.1, + solid: true, + visible: true + } + this.grabSphere = Overlays.addOverlay("sphere", sphereProperties); + } else { + Overlays.editOverlay(this.grabSphere, { + position: this.getHandPosition(), + size: GRAB_RADIUS*2, + color: color, + alpha: 0.1, + solid: true, + visible: true + }); + } + } + + this.grabSphereOff = function() { + if (this.grabSphere !== null) { + Overlays.deleteOverlay(this.grabSphere); + this.grabSphere = null; + } + }; + this.overlayLineOn = function(closePoint, farPoint, color) { if (this.overlayLine === null) { var lineProperties = { @@ -644,7 +678,6 @@ function MyController(hand) { this.searchSphereDistance = DEFAULT_SEARCH_SPHERE_DISTANCE; this.intersectionDistance = 0.0; } - }; this.particleBeamOff = function() { @@ -749,6 +782,11 @@ function MyController(hand) { // the trigger is being pressed, so do a ray test to see what we are hitting var handPosition = this.getHandPosition(); + + if (SHOW_GRAB_SPHERE) { + this.grabSphereOn(); + } + var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation; var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation)); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a552b77f1f..786e409d92 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1132,8 +1132,12 @@ glm::quat Avatar::getRightPalmRotation() const { glm::vec3 Avatar::getUncachedLeftPalmPosition() const { assert(QThread::currentThread() == thread()); // main thread access only glm::quat leftPalmRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation); glm::vec3 leftPalmPosition; + if (_skeletonModel.getLeftGrabPosition(leftPalmPosition)) { + return leftPalmPosition; + } + // avatar didn't have a LeftHandMiddle1 joint, fall back on this: + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation); getSkeletonModel().getLeftHandPosition(leftPalmPosition); leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation); return leftPalmPosition; @@ -1149,8 +1153,12 @@ glm::quat Avatar::getUncachedLeftPalmRotation() const { glm::vec3 Avatar::getUncachedRightPalmPosition() const { assert(QThread::currentThread() == thread()); // main thread access only glm::quat rightPalmRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation); glm::vec3 rightPalmPosition; + if (_skeletonModel.getRightGrabPosition(rightPalmPosition)) { + return rightPalmPosition; + } + // avatar didn't have a RightHandMiddle1 joint, fall back on this: + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation); getSkeletonModel().getRightHandPosition(rightPalmPosition); rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation); return rightPalmPosition; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6198a1b0a0..7a871236c5 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -235,6 +235,22 @@ void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) { } } +bool SkeletonModel::getLeftGrabPosition(glm::vec3& position) const { + int index = _rig->indexOfJoint("LeftHandMiddle1"); + if (index >= 0) { + return getJointPositionInWorldFrame(index, position); + } + return false; +} + +bool SkeletonModel::getRightGrabPosition(glm::vec3& position) const { + int index = _rig->indexOfJoint("RightHandMiddle1"); + if (index >= 0) { + return getJointPositionInWorldFrame(index, position); + } + return false; +} + bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { return getJointPositionInWorldFrame(getLeftHandJointIndex(), position); } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 7541a002dc..b57d54020d 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -39,6 +39,9 @@ public: /// Returns the index of the right hand joint, or -1 if not found. int getRightHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().rightHandJointIndex : -1; } + bool getLeftGrabPosition(glm::vec3& position) const; + bool getRightGrabPosition(glm::vec3& position) const; + /// Retrieve the position of the left hand /// \return true whether or not the position was found bool getLeftHandPosition(glm::vec3& position) const; From 1e69c12e87c1eb20d38cf5cdb80200e252bfb889 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Feb 2016 18:47:26 -0800 Subject: [PATCH 05/37] move grab position to front of palm --- interface/src/avatar/SkeletonModel.cpp | 46 ++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 7a871236c5..1163b4dff0 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -236,17 +236,51 @@ void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) { } bool SkeletonModel::getLeftGrabPosition(glm::vec3& position) const { - int index = _rig->indexOfJoint("LeftHandMiddle1"); - if (index >= 0) { - return getJointPositionInWorldFrame(index, position); + int knuckleIndex = _rig->indexOfJoint("LeftHandMiddle1"); + int handIndex = _rig->indexOfJoint("LeftHand"); + if (knuckleIndex >= 0 && handIndex >= 0) { + glm::quat handRotation; + glm::vec3 knucklePosition; + glm::vec3 handPosition; + if (!getJointPositionInWorldFrame(knuckleIndex, knucklePosition)) { + return false; + } + if (!getJointPositionInWorldFrame(handIndex, handPosition)) { + return false; + } + if (!getJointRotationInWorldFrame(handIndex, handRotation)) { + return false; + } + float halfPalmLength = glm::distance(knucklePosition, handPosition) * 0.5f; + // z azis is standardized to be out of the palm. move from the knuckle-joint away from the palm + // by 1/2 the palm length. + position = knucklePosition + handRotation * (glm::vec3(0.0f, 0.0f, 1.0f) * halfPalmLength); + return true; } return false; } bool SkeletonModel::getRightGrabPosition(glm::vec3& position) const { - int index = _rig->indexOfJoint("RightHandMiddle1"); - if (index >= 0) { - return getJointPositionInWorldFrame(index, position); + int knuckleIndex = _rig->indexOfJoint("RightHandMiddle1"); + int handIndex = _rig->indexOfJoint("RightHand"); + if (knuckleIndex >= 0 && handIndex >= 0) { + glm::quat handRotation; + glm::vec3 knucklePosition; + glm::vec3 handPosition; + if (!getJointPositionInWorldFrame(knuckleIndex, knucklePosition)) { + return false; + } + if (!getJointPositionInWorldFrame(handIndex, handPosition)) { + return false; + } + if (!getJointRotationInWorldFrame(handIndex, handRotation)) { + return false; + } + float halfPalmLength = glm::distance(knucklePosition, handPosition) * 0.5f; + // z azis is standardized to be out of the palm. move from the knuckle-joint away from the palm + // by 1/2 the palm length. + position = knucklePosition + handRotation * (glm::vec3(0.0f, 0.0f, 1.0f) * halfPalmLength); + return true; } return false; } From eff02d3e3ac4bb480ca6beb1283b44cd5d8d2bd2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 10 Jan 2016 10:11:47 -0800 Subject: [PATCH 06/37] Fix Agents bidding on simulation ownership --- assignment-client/src/Agent.cpp | 2 +- assignment-client/src/AssignmentClient.cpp | 2 +- interface/src/Application.cpp | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 7 ++++--- libraries/entities/src/EntityScriptingInterface.h | 5 +++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 07d15c9e26..3ff7eafd6b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -469,7 +469,7 @@ void Agent::aboutToFinish() { } // our entity tree is going to go away so tell that to the EntityScriptingInterface - DependencyManager::get()->setEntityTree(NULL); + DependencyManager::get()->setEntityTree(nullptr); // cleanup the AssetClient thread QThread* assetThread = DependencyManager::get()->thread(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 3bd38c4ae7..85a2c95b4d 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -60,7 +60,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri auto nodeList = DependencyManager::set(NodeType::Unassigned, listenPort); auto animationCache = DependencyManager::set(); - auto entityScriptingInterface = DependencyManager::set(); + auto entityScriptingInterface = DependencyManager::set(false); DependencyManager::registerInheritance(); auto actionFactory = DependencyManager::set(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab5edec527..f7d2bd9ada 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -348,7 +348,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set(true); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8fd7be912e..6bfcc66f1e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -25,8 +25,9 @@ #include "ZoneEntityItem.h" -EntityScriptingInterface::EntityScriptingInterface() : - _entityTree(NULL) +EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) : + _entityTree(NULL), + _bidOnSimulationOwnership(bidOnSimulationOwnership) { auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::canAdjustLocksChanged, this, &EntityScriptingInterface::canAdjustLocksChanged); @@ -255,7 +256,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties.setType(entity->getType()); bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges(); bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges; - if (hasPhysicsChanges) { + if (_bidOnSimulationOwnership && hasPhysicsChanges) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 641da7518e..934a194360 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -58,7 +58,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra class EntityScriptingInterface : public OctreeScriptingInterface, public Dependency { Q_OBJECT public: - EntityScriptingInterface(); + EntityScriptingInterface(bool bidOnSimulationOwnership); EntityEditPacketSender* getEntityPacketSender() const { return (EntityEditPacketSender*)getPacketSender(); } virtual NodeType_t getServerNodeType() const { return NodeType::EntityServer; } @@ -204,7 +204,8 @@ private: bool precisionPicking, const QVector& entityIdsToInclude, const QVector& entityIdsToDiscard); EntityTreePointer _entityTree; - EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr; + EntitiesScriptEngineProvider* _entitiesScriptEngine { nullptr }; + bool _bidOnSimulationOwnership { false }; }; #endif // hifi_EntityScriptingInterface_h From e9fd439ffd0210b0720b084bcecf9a1b91c07eb3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 28 Jan 2016 18:27:49 -0800 Subject: [PATCH 07/37] Added inAir animations --- .../defaultAvatar_full/avatar-animation.json | 80 +++++++++++++++++-- interface/src/avatar/SkeletonModel.cpp | 9 ++- libraries/animation/src/Rig.cpp | 38 ++++++++- libraries/animation/src/Rig.h | 11 ++- libraries/physics/src/CharacterController.h | 1 + 5 files changed, 125 insertions(+), 14 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 42ff64abc6..46912120db 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -247,7 +247,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -263,7 +264,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -278,7 +280,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -293,7 +296,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -308,7 +312,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -323,7 +328,8 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -338,7 +344,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -353,7 +360,8 @@ { "var": "isMovingLeft", "state": "strafeLeft" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isAway", "state": "awayIntro" }, - { "var": "isFlying", "state": "fly" } + { "var": "isFlying", "state": "fly" }, + { "var": "isInAir", "state": "inAir" } ] }, { @@ -385,8 +393,18 @@ "interpTarget": 6, "interpDuration": 6, "transitions": [ + { "var": "isAway", "state": "awayIntro" }, { "var": "isNotFlying", "state": "idle" } ] + }, + { + "id": "inAir", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isAway", "state": "awayIntro" }, + { "var": "isNotInAir", "state": "idle" } + ] } ] }, @@ -685,6 +703,52 @@ "loopFlag": true }, "children": [] + }, + { + "id": "inAir", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirPreApex", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 0.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "inAirApex", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", + "startFrame": 6.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "inAirPostApex", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx", + "startFrame": 11.0, + "endFrame": 11.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] } ] } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6198a1b0a0..50cbbbbb00 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -133,7 +133,14 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateFromHandParameters(handParams, deltaTime); - _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), myAvatar->isHovering()); + Rig::CharacterControllerState ccState = Rig::CharacterControllerState::Ground; + if (myAvatar->getCharacterController()->isHovering()) { + ccState = Rig::CharacterControllerState::Hover; + } else if (myAvatar->getCharacterController()->isJumping()) { + ccState = Rig::CharacterControllerState::Jump; + } + + _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState); // evaluate AnimGraph animation and update jointStates. Model::updateRig(deltaTime, parentTransform); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 4d72bfbaea..94bc23cf06 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -504,7 +504,7 @@ static const std::vector FORWARD_SPEEDS = { 0.4f, 1.4f, 4.5f }; // m/s static const std::vector BACKWARD_SPEEDS = { 0.6f, 1.45f }; // m/s static const std::vector LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s -void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering) { +void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState) { glm::vec3 front = worldRotation * IDENTITY_FRONT; @@ -572,11 +572,16 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos const float TURN_ENTER_SPEED_THRESHOLD = 0.5f; // rad/sec const float TURN_EXIT_SPEED_THRESHOLD = 0.2f; // rad/sec - if (isHovering) { + if (ccState == CharacterControllerState::Hover) { if (_desiredState != RigRole::Hover) { _desiredStateAge = 0.0f; } _desiredState = RigRole::Hover; + } else if (ccState == CharacterControllerState::Jump) { + if (_desiredState != RigRole::Jump) { + _desiredStateAge = 0.0f; + } + _desiredState = RigRole::Jump; } else { float moveThresh; if (_state != RigRole::Move) { @@ -662,6 +667,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); } } else if (_state == RigRole::Turn) { if (turningSpeed > 0.0f) { @@ -682,6 +689,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotMoving", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); } else if (_state == RigRole::Idle ) { // default anim vars to notMoving and notTurning _animVars.set("isMovingForward", false); @@ -694,7 +703,9 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); - } else { + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Hover) { // flying. _animVars.set("isMovingForward", false); _animVars.set("isMovingBackward", false); @@ -706,6 +717,27 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", true); _animVars.set("isNotFlying", false); + _animVars.set("isInAir", false); + _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Jump) { + // jumping in-air + _animVars.set("isMovingForward", false); + _animVars.set("isMovingBackward", false); + _animVars.set("isMovingLeft", false); + _animVars.set("isMovingRight", false); + _animVars.set("isNotMoving", true); + _animVars.set("isTurningLeft", false); + _animVars.set("isTurningRight", false); + _animVars.set("isNotTurning", true); + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); + _animVars.set("isInAir", true); + _animVars.set("isNotInAir", false); + + // compute blend based on velocity + const float JUMP_SPEED = 3.5f; + float alpha = glm::clamp(-worldVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f; + _animVars.set("inAirAlpha", alpha); } t += deltaTime; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index cf96c6dc16..50d775d7f5 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -73,6 +73,12 @@ public: glm::quat rightOrientation = glm::quat(); // rig space (z forward) }; + enum class CharacterControllerState { + Ground = 0, + Jump, + Hover + }; + virtual ~Rig() {} void destroyAnimGraph(); @@ -141,7 +147,7 @@ public: glm::mat4 getJointTransform(int jointIndex) const; // Start or stop animations as needed. - void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering); + void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState); // Regardless of who started the animations or how many, update the joints. void updateAnimations(float deltaTime, glm::mat4 rootTransform); @@ -271,7 +277,8 @@ public: Idle = 0, Turn, Move, - Hover + Hover, + Jump }; RigRole _state { RigRole::Idle }; RigRole _desiredState { RigRole::Idle }; diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index c1c64a1a02..3c9fc476ca 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -75,6 +75,7 @@ public: glm::vec3 getLinearVelocity() const; + bool isJumping() const { return _isJumping; } bool isHovering() const { return _isHovering; } void setHovering(bool enabled); From 61c55ebf6c96857559280116a830dec7aa5c410a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 29 Jan 2016 11:57:14 -0800 Subject: [PATCH 08/37] Updated character controller with a state enumeration Also, adjusted checkForSupport logic such that very slanted walls are not considered support. --- interface/src/avatar/MyAvatar.cpp | 7 +-- interface/src/avatar/MyAvatar.h | 2 - .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 20 ++++--- libraries/animation/src/Rig.cpp | 8 +-- libraries/animation/src/Rig.h | 4 +- libraries/physics/src/CharacterController.cpp | 60 +++++++++---------- libraries/physics/src/CharacterController.h | 17 +++--- 8 files changed, 62 insertions(+), 58 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0c0b51bda2..0aadaed150 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1510,7 +1510,8 @@ void MyAvatar::updatePosition(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity; - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering()); + bool isHovering = _characterController.getState() == CharacterController::State::Hover; + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); // rotate back into world-frame @@ -1579,10 +1580,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float return false; } -bool MyAvatar::isHovering() const { - return _characterController.isHovering(); -} - void MyAvatar::increaseSize() { if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) { _targetScale *= (1.0f + SCALING_RATIO); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 760f390de9..ac77784077 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -239,8 +239,6 @@ public: glm::quat getCustomListenOrientation() { return _customListenOrientation; } void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; } - bool isHovering() const; - public slots: void increaseSize(); void decreaseSize(); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index c7f2945757..07156e9294 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -67,7 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() { _rigidBody->setAngularFactor(0.0f); _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()), glmToBullet(_avatar->getPosition()))); - if (_isHovering) { + if (_state == State::Hover) { _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); } else { _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 50cbbbbb00..c8f14578b4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -72,6 +72,18 @@ void SkeletonModel::initJointStates() { emit skeletonLoaded(); } +Rig::CharacterControllerState convertCharacterControllerState(CharacterController::State state) { + switch (state) { + default: + case CharacterController::State::Ground: + return Rig::CharacterControllerState::Ground; + case CharacterController::State::InAir: + return Rig::CharacterControllerState::InAir; + case CharacterController::State::Hover: + return Rig::CharacterControllerState::Hover; + }; +} + // Called within Model::simulate call, below. void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Head* head = _owningAvatar->getHead(); @@ -133,13 +145,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateFromHandParameters(handParams, deltaTime); - Rig::CharacterControllerState ccState = Rig::CharacterControllerState::Ground; - if (myAvatar->getCharacterController()->isHovering()) { - ccState = Rig::CharacterControllerState::Hover; - } else if (myAvatar->getCharacterController()->isJumping()) { - ccState = Rig::CharacterControllerState::Jump; - } - + Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState()); _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState); // evaluate AnimGraph animation and update jointStates. diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 94bc23cf06..33c8f33ac8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -577,11 +577,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _desiredStateAge = 0.0f; } _desiredState = RigRole::Hover; - } else if (ccState == CharacterControllerState::Jump) { - if (_desiredState != RigRole::Jump) { + } else if (ccState == CharacterControllerState::InAir) { + if (_desiredState != RigRole::InAir) { _desiredStateAge = 0.0f; } - _desiredState = RigRole::Jump; + _desiredState = RigRole::InAir; } else { float moveThresh; if (_state != RigRole::Move) { @@ -719,7 +719,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotFlying", false); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); - } else if (_state == RigRole::Jump) { + } else if (_state == RigRole::InAir) { // jumping in-air _animVars.set("isMovingForward", false); _animVars.set("isMovingBackward", false); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 50d775d7f5..dc07a32efd 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -75,7 +75,7 @@ public: enum class CharacterControllerState { Ground = 0, - Jump, + InAir, Hover }; @@ -278,7 +278,7 @@ public: Turn, Move, Hover, - Jump + InAir }; RigRole _state { RigRole::Idle }; RigRole _desiredState { RigRole::Idle }; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index a30feec150..055f846793 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -1,4 +1,4 @@ -// + // // CharacterControllerInterface.cpp // libraries/physcis/src // @@ -51,10 +51,7 @@ CharacterController::CharacterController() { _followDesiredBodyTransform.setIdentity(); _followTimeRemaining = 0.0f; _jumpSpeed = JUMP_SPEED; - _isOnGround = false; - _isJumping = false; - _isFalling = false; - _isHovering = true; + _state = State::Hover; _isPushingUp = false; _jumpToHoverStart = 0; _followTime = 0.0f; @@ -107,6 +104,8 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } } +static const float COS_PI_OVER_THREE = cosf(PI / 3.0f); + bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) const { int numManifolds = collisionWorld->getDispatcher()->getNumManifolds(); for (int i = 0; i < numManifolds; i++) { @@ -119,8 +118,10 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) cons btManifoldPoint& pt = contactManifold->getContactPoint(j); // check to see if contact point is touching the bottom sphere of the capsule. + // and the contact normal is not slanted too much. float contactPointY = (obA == _rigidBody) ? pt.m_localPointA.getY() : pt.m_localPointB.getY(); - if (contactPointY < -_halfHeight) { + btVector3 normal = (obA == _rigidBody) ? pt.m_normalWorldOnB : -pt.m_normalWorldOnB; + if (contactPointY < -_halfHeight && normal.dot(_currentUp) > COS_PI_OVER_THREE) { return true; } } @@ -165,7 +166,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { } const btScalar MIN_SPEED = 0.001f; - if (_isHovering) { + if (_state == State::Hover) { if (desiredSpeed < MIN_SPEED) { if (actualSpeed < MIN_SPEED) { _rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); @@ -255,9 +256,9 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { void CharacterController::jump() { // check for case where user is holding down "jump" key... - // we'll eventually tansition to "hover" - if (!_isJumping) { - if (!_isHovering) { + // we'll eventually transition to "hover" + if (_state != State::InAir) { + if (_state != State::Hover) { _jumpToHoverStart = usecTimestampNow(); _pendingFlags |= PENDING_FLAG_JUMP; } @@ -266,7 +267,7 @@ void CharacterController::jump() { const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { _isPushingUp = true; - setHovering(true); + setState(State::Hover); } } } @@ -276,19 +277,19 @@ bool CharacterController::onGround() const { return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport; } -void CharacterController::setHovering(bool hover) { - if (hover != _isHovering) { - _isHovering = hover; - _isJumping = false; - +void CharacterController::setState(State desiredState) { + if (desiredState == State::Hover && _state != State::Hover) { + // hover enter if (_rigidBody) { - if (hover) { - _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - } else { - _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); - } + _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + } + } else if (_state == State::Hover && desiredState != State::Hover) { + // hover exit + if (_rigidBody) { + _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); } } + _state = desiredState; } void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { @@ -335,9 +336,8 @@ void CharacterController::setEnabled(bool enabled) { _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; - _isOnGround = false; } - setHovering(true); + setState(State::Hover); _enabled = enabled; } } @@ -345,7 +345,7 @@ void CharacterController::setEnabled(bool enabled) { void CharacterController::updateUpAxis(const glm::quat& rotation) { btVector3 oldUp = _currentUp; _currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS); - if (!_isHovering) { + if (_state != State::Hover) { const btScalar MIN_UP_ERROR = 0.01f; if (oldUp.distance(_currentUp) > MIN_UP_ERROR) { _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); @@ -425,23 +425,23 @@ void CharacterController::preSimulation() { if (rayCallback.hasHit()) { _floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius; const btScalar MIN_HOVER_HEIGHT = 3.0f; - if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) { - setHovering(false); + if (_state == State::Hover && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) { + setState(State::InAir); } // TODO: use collision events rather than ray-trace test to disable jumping const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_floorDistance < JUMP_PROXIMITY_THRESHOLD) { - _isJumping = false; + if (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport) { + setState(State::Ground); } } else if (!_hasSupport) { _floorDistance = FLT_MAX; - setHovering(true); + setState(State::Hover); } if (_pendingFlags & PENDING_FLAG_JUMP) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (onGround()) { - _isJumping = true; + setState(State::InAir); btVector3 velocity = _rigidBody->getLinearVelocity(); velocity += _jumpSpeed * _currentUp; _rigidBody->setLinearVelocity(velocity); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 3c9fc476ca..c8b360237d 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -75,9 +75,13 @@ public: glm::vec3 getLinearVelocity() const; - bool isJumping() const { return _isJumping; } - bool isHovering() const { return _isHovering; } - void setHovering(bool enabled); + enum class State { + Ground = 0, + InAir, + Hover + }; + + State getState() const { return _state; } void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); @@ -87,6 +91,8 @@ public: bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); protected: + void setState(State state); + void updateUpAxis(const glm::quat& rotation); bool checkForSupport(btCollisionWorld* collisionWorld) const; @@ -117,10 +123,7 @@ protected: btQuaternion _followAngularDisplacement; bool _enabled; - bool _isOnGround; - bool _isJumping; - bool _isFalling; - bool _isHovering; + State _state; bool _isPushingUp; btDynamicsWorld* _dynamicsWorld { nullptr }; From 2936811484541b5b6133f8e1560393a70a3a8e56 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 29 Jan 2016 18:05:18 -0800 Subject: [PATCH 09/37] Added takeoff animation, WIP Character controller still has some jump/in-air bugs. --- .../defaultAvatar_full/avatar-animation.json | 39 ++++++++++++++++--- interface/src/avatar/SkeletonModel.cpp | 2 + libraries/animation/src/Rig.cpp | 35 +++++++++++++++++ libraries/animation/src/Rig.h | 2 + libraries/physics/src/CharacterController.cpp | 33 ++++++++++------ libraries/physics/src/CharacterController.h | 2 + 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 46912120db..37da0c37cc 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -248,6 +248,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -265,6 +266,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -281,6 +283,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -297,6 +300,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -313,6 +317,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -329,6 +334,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -345,6 +351,7 @@ { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -361,6 +368,7 @@ { "var": "isTurningRight", "state": "turnRight" }, { "var": "isAway", "state": "awayIntro" }, { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoff", "state": "takeoff" }, { "var": "isInAir", "state": "inAir" } ] }, @@ -397,10 +405,19 @@ { "var": "isNotFlying", "state": "idle" } ] }, + { + "id": "takeoff", + "interpTarget": 0, + "interpDuration": 6, + "transitions": [ + { "var": "isAway", "state": "awayIntro" }, + { "var": "isNotTakeoff", "state": "inAir" } + ] + }, { "id": "inAir", - "interpTarget": 3, - "interpDuration": 3, + "interpTarget": 0, + "interpDuration": 6, "transitions": [ { "var": "isAway", "state": "awayIntro" }, { "var": "isNotInAir", "state": "idle" } @@ -704,6 +721,18 @@ }, "children": [] }, + { + "id": "takeoff", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_takeoff.fbx", + "startFrame": 1.0, + "endFrame": 2.5, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, { "id": "inAir", "type": "blendLinear", @@ -720,7 +749,7 @@ "startFrame": 0.0, "endFrame": 0.0, "timeScale": 0.0, - "loopFlag": true + "loopFlag": false }, "children": [] }, @@ -732,7 +761,7 @@ "startFrame": 6.0, "endFrame": 6.0, "timeScale": 1.0, - "loopFlag": true + "loopFlag": false }, "children": [] }, @@ -744,7 +773,7 @@ "startFrame": 11.0, "endFrame": 11.0, "timeScale": 1.0, - "loopFlag": true + "loopFlag": false }, "children": [] } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index c8f14578b4..92bdef686d 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -77,6 +77,8 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle default: case CharacterController::State::Ground: return Rig::CharacterControllerState::Ground; + case CharacterController::State::Takeoff: + return Rig::CharacterControllerState::Takeoff; case CharacterController::State::InAir: return Rig::CharacterControllerState::InAir; case CharacterController::State::Hover: diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 33c8f33ac8..9e811fa358 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -582,6 +582,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _desiredStateAge = 0.0f; } _desiredState = RigRole::InAir; + } else if (ccState == CharacterControllerState::Takeoff) { + if (_desiredState != RigRole::Takeoff) { + _desiredStateAge = 0.0f; + } + _desiredState = RigRole::Takeoff; } else { float moveThresh; if (_state != RigRole::Move) { @@ -667,6 +672,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); } @@ -689,8 +696,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotMoving", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Idle ) { // default anim vars to notMoving and notTurning _animVars.set("isMovingForward", false); @@ -703,8 +713,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); + } else if (_state == RigRole::Hover) { // flying. _animVars.set("isMovingForward", false); @@ -717,8 +730,28 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", true); _animVars.set("isNotFlying", false); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", false); _animVars.set("isNotInAir", true); + + } else if (_state == RigRole::Takeoff) { + // jumping in-air + _animVars.set("isMovingForward", false); + _animVars.set("isMovingBackward", false); + _animVars.set("isMovingLeft", false); + _animVars.set("isMovingRight", false); + _animVars.set("isNotMoving", true); + _animVars.set("isTurningLeft", false); + _animVars.set("isTurningRight", false); + _animVars.set("isNotTurning", true); + _animVars.set("isFlying", false); + _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", true); + _animVars.set("isNotTakeoff", false); + _animVars.set("isInAir", true); + _animVars.set("isNotInAir", false); + } else if (_state == RigRole::InAir) { // jumping in-air _animVars.set("isMovingForward", false); @@ -731,6 +764,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isNotTurning", true); _animVars.set("isFlying", false); _animVars.set("isNotFlying", true); + _animVars.set("isTakeoff", false); + _animVars.set("isNotTakeoff", true); _animVars.set("isInAir", true); _animVars.set("isNotInAir", false); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index dc07a32efd..e12af16e41 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -75,6 +75,7 @@ public: enum class CharacterControllerState { Ground = 0, + Takeoff, InAir, Hover }; @@ -278,6 +279,7 @@ public: Turn, Move, Hover, + Takeoff, InAir }; RigRole _state { RigRole::Idle }; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 055f846793..93b924d9bc 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -54,6 +54,7 @@ CharacterController::CharacterController() { _state = State::Hover; _isPushingUp = false; _jumpToHoverStart = 0; + _takeoffToInAirStart = 0; _followTime = 0.0f; _followLinearDisplacement = btVector3(0, 0, 0); _followAngularDisplacement = btQuaternion::getIdentity(); @@ -257,18 +258,18 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { void CharacterController::jump() { // check for case where user is holding down "jump" key... // we'll eventually transition to "hover" - if (_state != State::InAir) { - if (_state != State::Hover) { - _jumpToHoverStart = usecTimestampNow(); - _pendingFlags |= PENDING_FLAG_JUMP; - } - } else { + if (_state == State::Hover) { quint64 now = usecTimestampNow(); const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { _isPushingUp = true; setState(State::Hover); } + } else { + if (_state != State::Takeoff) { + _jumpToHoverStart = usecTimestampNow(); + _pendingFlags |= PENDING_FLAG_JUMP; + } } } @@ -430,7 +431,7 @@ void CharacterController::preSimulation() { } // TODO: use collision events rather than ray-trace test to disable jumping const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport) { + if (_state != State::Takeoff && (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport)) { setState(State::Ground); } } else if (!_hasSupport) { @@ -438,15 +439,25 @@ void CharacterController::preSimulation() { setState(State::Hover); } + quint64 now = usecTimestampNow(); + if (_pendingFlags & PENDING_FLAG_JUMP) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (onGround()) { - setState(State::InAir); - btVector3 velocity = _rigidBody->getLinearVelocity(); - velocity += _jumpSpeed * _currentUp; - _rigidBody->setLinearVelocity(velocity); + setState(State::Takeoff); + _takeoffToInAirStart = now; } } + + const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; + if (_state == State::Takeoff && (now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { + setState(State::InAir); + + _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; + btVector3 velocity = _rigidBody->getLinearVelocity(); + velocity += _jumpSpeed * _currentUp; + _rigidBody->setLinearVelocity(velocity); + } } _followTime = 0.0f; diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index c8b360237d..5470104a1a 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -77,6 +77,7 @@ public: enum class State { Ground = 0, + Takeoff, InAir, Hover }; @@ -107,6 +108,7 @@ protected: glm::vec3 _boxScale; // used to compute capsule shape + quint64 _takeoffToInAirStart; quint64 _jumpToHoverStart; btScalar _halfHeight; From 47f3ce3786e97f744d7338bd5cc694511df05891 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 1 Feb 2016 14:18:30 -0800 Subject: [PATCH 10/37] CharacterController jump is more reliable. --- libraries/animation/src/Rig.cpp | 7 ++ libraries/physics/src/CharacterController.cpp | 80 +++++++++++++------ 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 9e811fa358..64935691c8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -624,6 +624,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos const float STATE_CHANGE_HYSTERESIS_TIMER = 0.1f; + // Skip hystersis timer for jump transitions. + if (_desiredState == RigRole::Takeoff) { + _desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER; + } else if (_state == RigRole::InAir && _desiredState != RigRole::InAir) { + _desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER; + } + if ((_desiredStateAge >= STATE_CHANGE_HYSTERESIS_TIMER) && _desiredState != _state) { _state = _desiredState; _desiredStateAge = 0.0f; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 93b924d9bc..ad6c9545d2 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -1,4 +1,4 @@ - // +// // CharacterControllerInterface.cpp // libraries/physcis/src // @@ -15,11 +15,14 @@ #include "PhysicsCollisionGroups.h" #include "ObjectMotionState.h" +#include "PhysicsLogging.h" const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; +#define DEBUG_STATE_CHANGE + // helper class for simple ray-traces from character class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { public: @@ -220,7 +223,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { // Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform. // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). - // These two computations must be kept in sync. + const float MINIMUM_TIME_REMAINING = 0.005f; const float MAX_DISPLACEMENT = 0.5f * _radius; _followTimeRemaining -= dt; @@ -258,18 +261,21 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { void CharacterController::jump() { // check for case where user is holding down "jump" key... // we'll eventually transition to "hover" - if (_state == State::Hover) { - quint64 now = usecTimestampNow(); - const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); - if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { - _isPushingUp = true; - setState(State::Hover); - } - } else { - if (_state != State::Takeoff) { - _jumpToHoverStart = usecTimestampNow(); + if (_state != State::Takeoff) { + if (_state == State::InAir) { + quint64 now = usecTimestampNow(); + if (!_isPushingUp) { + _isPushingUp = true; + _jumpToHoverStart = now; + } + const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; + if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { + setState(State::Hover); + } + } else { _pendingFlags |= PENDING_FLAG_JUMP; } + } } @@ -278,19 +284,41 @@ bool CharacterController::onGround() const { return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport; } -void CharacterController::setState(State desiredState) { - if (desiredState == State::Hover && _state != State::Hover) { - // hover enter - if (_rigidBody) { - _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); - } - } else if (_state == State::Hover && desiredState != State::Hover) { - // hover exit - if (_rigidBody) { - _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); - } +#ifdef DEBUG_STATE_CHANGE +static const char* stateToStr(CharacterController::State state) { + switch (state) { + case CharacterController::State::Ground: + return "Ground"; + case CharacterController::State::Takeoff: + return "Takeoff"; + case CharacterController::State::InAir: + return "InAir"; + case CharacterController::State::Hover: + return "Hover"; + default: + return "Unknown"; + } +} +#endif // #ifdef DEBUG_STATE_CHANGE + +void CharacterController::setState(State desiredState) { + if (desiredState != _state) { +#ifdef DEBUG_STATE_CHANGE + qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "<-" << stateToStr(_state); +#endif + if (desiredState == State::Hover && _state != State::Hover) { + // hover enter + if (_rigidBody) { + _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); + } + } else if (_state == State::Hover && desiredState != State::Hover) { + // hover exit + if (_rigidBody) { + _rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); + } + } + _state = desiredState; } - _state = desiredState; } void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { @@ -411,6 +439,7 @@ void CharacterController::preSimulation() { if (_enabled && _dynamicsWorld) { // slam body to where it is supposed to be _rigidBody->setWorldTransform(_characterBodyTransform); + btVector3 velocity = _rigidBody->getLinearVelocity(); // scan for distant floor // rayStart is at center of bottom sphere @@ -431,7 +460,7 @@ void CharacterController::preSimulation() { } // TODO: use collision events rather than ray-trace test to disable jumping const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_state != State::Takeoff && (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport)) { + if (_state != State::Takeoff && (velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { setState(State::Ground); } } else if (!_hasSupport) { @@ -454,7 +483,6 @@ void CharacterController::preSimulation() { setState(State::InAir); _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; - btVector3 velocity = _rigidBody->getLinearVelocity(); velocity += _jumpSpeed * _currentUp; _rigidBody->setLinearVelocity(velocity); } From 8b5cf3e49abbd8f4d6f32edb1f1f06cbd8989b4b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 1 Feb 2016 20:43:41 -0800 Subject: [PATCH 11/37] CharacterController: refined state machine. --- libraries/physics/src/CharacterController.cpp | 201 +++++++++--------- libraries/physics/src/CharacterController.h | 6 +- 2 files changed, 109 insertions(+), 98 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index ad6c9545d2..f241be8b35 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -56,7 +56,8 @@ CharacterController::CharacterController() { _jumpSpeed = JUMP_SPEED; _state = State::Hover; _isPushingUp = false; - _jumpToHoverStart = 0; + _jumpButtonDownStart = 0; + _jumpButtonDownCount = 0; _takeoffToInAirStart = 0; _followTime = 0.0f; _followLinearDisplacement = btVector3(0, 0, 0); @@ -158,68 +159,57 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) { } void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { - btVector3 actualVelocity = _rigidBody->getLinearVelocity(); - btScalar actualSpeed = actualVelocity.length(); - - btVector3 desiredVelocity = _walkVelocity; - btScalar desiredSpeed = desiredVelocity.length(); - - const btScalar MIN_UP_PUSH = 0.1f; - if (desiredVelocity.dot(_currentUp) < MIN_UP_PUSH) { - _isPushingUp = false; - } const btScalar MIN_SPEED = 0.001f; - if (_state == State::Hover) { - if (desiredSpeed < MIN_SPEED) { - if (actualSpeed < MIN_SPEED) { - _rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); - } else { - const btScalar HOVER_BRAKING_TIMESCALE = 0.1f; - btScalar tau = glm::max(dt / HOVER_BRAKING_TIMESCALE, 1.0f); - _rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity); - } - } else { - const btScalar HOVER_ACCELERATION_TIMESCALE = 0.1f; - btScalar tau = dt / HOVER_ACCELERATION_TIMESCALE; - _rigidBody->setLinearVelocity(actualVelocity - tau * (actualVelocity - desiredVelocity)); + + btVector3 actualVelocity = _rigidBody->getLinearVelocity(); + if (actualVelocity.length() < MIN_SPEED) { + actualVelocity = btVector3(0.0f, 0.0f, 0.0f); + } + + btVector3 desiredVelocity = _walkVelocity; + if (desiredVelocity.length() < MIN_SPEED) { + desiredVelocity = btVector3(0.0f, 0.0f, 0.0f); + } + + // decompose into horizontal and vertical components. + btVector3 actualVertVelocity = actualVelocity.dot(_currentUp) * _currentUp; + btVector3 actualHorizVelocity = actualVelocity - actualVertVelocity; + btVector3 desiredVertVelocity = desiredVelocity.dot(_currentUp) * _currentUp; + btVector3 desiredHorizVelocity = desiredVelocity - desiredVertVelocity; + + btVector3 finalVelocity; + + switch (_state) { + case State::Ground: + case State::Takeoff: + { + // horizontal ground control + const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f; + btScalar tau = dt / WALK_ACCELERATION_TIMESCALE; + finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity; } - } else { - if (onGround()) { - // walking on ground - if (desiredSpeed < MIN_SPEED) { - if (actualSpeed < MIN_SPEED) { - _rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); - } else { - const btScalar HOVER_BRAKING_TIMESCALE = 0.1f; - btScalar tau = dt / HOVER_BRAKING_TIMESCALE; - _rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity); - } - } else { - // TODO: modify desiredVelocity using floor normal - const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f; - btScalar tau = dt / WALK_ACCELERATION_TIMESCALE; - btVector3 velocityCorrection = tau * (desiredVelocity - actualVelocity); - // subtract vertical component - velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp; - _rigidBody->setLinearVelocity(actualVelocity + velocityCorrection); - } - } else { - // transitioning to flying - btVector3 velocityCorrection = desiredVelocity - actualVelocity; + break; + case State::InAir: + { + // horizontal air control + const btScalar IN_AIR_ACCELERATION_TIMESCALE = 2.0f; + btScalar tau = dt / IN_AIR_ACCELERATION_TIMESCALE; + finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity; + } + break; + case State::Hover: + { + // vertical and horizontal air control const btScalar FLY_ACCELERATION_TIMESCALE = 0.2f; btScalar tau = dt / FLY_ACCELERATION_TIMESCALE; - if (!_isPushingUp) { - // actually falling --> compute a different velocity attenuation factor - const btScalar FALL_ACCELERATION_TIMESCALE = 2.0f; - tau = dt / FALL_ACCELERATION_TIMESCALE; - // zero vertical component - velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp; - } - _rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection); + finalVelocity = tau * desiredVelocity + (1.0f - tau) * actualVelocity; } + break; } + _rigidBody->setLinearVelocity(finalVelocity); + // Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform. // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). @@ -259,24 +249,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) { } void CharacterController::jump() { - // check for case where user is holding down "jump" key... - // we'll eventually transition to "hover" - if (_state != State::Takeoff) { - if (_state == State::InAir) { - quint64 now = usecTimestampNow(); - if (!_isPushingUp) { - _isPushingUp = true; - _jumpToHoverStart = now; - } - const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; - if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { - setState(State::Hover); - } - } else { - _pendingFlags |= PENDING_FLAG_JUMP; - } - - } + _pendingFlags |= PENDING_FLAG_JUMP; } bool CharacterController::onGround() const { @@ -441,6 +414,9 @@ void CharacterController::preSimulation() { _rigidBody->setWorldTransform(_characterBodyTransform); btVector3 velocity = _rigidBody->getLinearVelocity(); + btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp; + btVector3 actualHorizVelocity = velocity - actualVertVelocity; + // scan for distant floor // rayStart is at center of bottom sphere btVector3 rayStart = _characterBodyTransform.getOrigin() - _halfHeight * _currentUp; @@ -454,41 +430,74 @@ void CharacterController::preSimulation() { _dynamicsWorld->rayTest(rayStart, rayEnd, rayCallback); if (rayCallback.hasHit()) { _floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius; - const btScalar MIN_HOVER_HEIGHT = 3.0f; - if (_state == State::Hover && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) { - setState(State::InAir); - } - // TODO: use collision events rather than ray-trace test to disable jumping - const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; - if (_state != State::Takeoff && (velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { - setState(State::Ground); - } - } else if (!_hasSupport) { + } else { _floorDistance = FLT_MAX; - setState(State::Hover); } + const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; + const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; + const btScalar MIN_HOVER_HEIGHT = 2.5f; + const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; + const btScalar UPWARD_VELOCITY_THRESHOLD = 0.05f; + const btScalar MAX_FLYING_SPEED = 30.0f; + quint64 now = usecTimestampNow(); - if (_pendingFlags & PENDING_FLAG_JUMP) { - _pendingFlags &= ~ PENDING_FLAG_JUMP; - if (onGround()) { - setState(State::Takeoff); - _takeoffToInAirStart = now; + // record a time stamp when the jump button was first pressed. + if ((_previousFlags & PENDING_FLAG_JUMP) != (_pendingFlags & PENDING_FLAG_JUMP)) { + if (_pendingFlags & PENDING_FLAG_JUMP) { + _jumpButtonDownStart = now; + _jumpButtonDownCount++; } } - const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; - if (_state == State::Takeoff && (now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { - setState(State::InAir); + bool jumpButtonHeld = _pendingFlags & PENDING_FLAG_JUMP; + bool wantsToGoUp = !jumpButtonHeld && _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD; + bool tooFast = actualHorizVelocity.length() > (MAX_FLYING_SPEED / 2.0f); - _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; - velocity += _jumpSpeed * _currentUp; - _rigidBody->setLinearVelocity(velocity); + switch (_state) { + case State::Ground: + if (!rayCallback.hasHit() && !_hasSupport) { + setState(State::Hover); + } else if (_pendingFlags & PENDING_FLAG_JUMP) { + _takeOffJumpButtonID = _jumpButtonDownCount; + setState(State::Takeoff); + } + break; + case State::Takeoff: + if (!rayCallback.hasHit() && !_hasSupport) { + setState(State::Hover); + } else if ((now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { + setState(State::InAir); + _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; + velocity += _jumpSpeed * _currentUp; + _rigidBody->setLinearVelocity(velocity); + } + break; + case State::InAir: { + if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { + setState(State::Ground); + } else if ((jumpButtonHeld && ((_takeOffJumpButtonID != _jumpButtonDownCount) || (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD)) || wantsToGoUp) { + setState(State::Hover); + } + break; + } + case State::Hover: + if (!jumpButtonHeld && !wantsToGoUp && _floorDistance < MIN_HOVER_HEIGHT && !tooFast) { + setState(State::InAir); + } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !tooFast) { + setState(State::Ground); + } + break; } } - _followTime = 0.0f; + /// _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD + + _previousFlags = _pendingFlags; + _pendingFlags &= ~PENDING_FLAG_JUMP; + + _followTime = 0.0f; _followLinearDisplacement = btVector3(0, 0, 0); _followAngularDisplacement = btQuaternion::getIdentity(); } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 5470104a1a..97bda5c5d5 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -109,7 +109,9 @@ protected: glm::vec3 _boxScale; // used to compute capsule shape quint64 _takeoffToInAirStart; - quint64 _jumpToHoverStart; + quint64 _jumpButtonDownStart; + quint32 _jumpButtonDownCount; + quint32 _takeOffJumpButtonID; btScalar _halfHeight; btScalar _radius; @@ -131,7 +133,7 @@ protected: btDynamicsWorld* _dynamicsWorld { nullptr }; btRigidBody* _rigidBody { nullptr }; uint32_t _pendingFlags { 0 }; - + uint32_t _previousFlags { 0 }; }; #endif // hifi_CharacterControllerInterface_h From c4e1509aa214948bbe2428714d71c9f5133f5186 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 2 Feb 2016 11:19:17 -0800 Subject: [PATCH 12/37] CharacterController: better debug support of internal state machine Head is no longer visible when flying fast, in first-person HMD mode. --- interface/src/avatar/MyAvatar.cpp | 12 +++-- libraries/physics/src/CharacterController.cpp | 46 +++++++++++-------- libraries/physics/src/CharacterController.h | 6 +++ 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0aadaed150..4253091533 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1311,21 +1311,23 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { _prevShouldDrawHead = shouldDrawHead; } -const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; +const float RENDER_HEAD_CUTOFF_DISTANCE = 0.5f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); + return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { - return ((renderArgs->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) || - (qApp->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) || - !cameraInsideHead()); + bool defaultMode = renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE; + bool firstPerson = qApp->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON; + bool insideHead = cameraInsideHead(); + return !defaultMode || !firstPerson || !insideHead; } void MyAvatar::updateOrientation(float deltaTime) { + // Smoothly rotate body with arrow keys float targetSpeed = _driveKeys[YAW] * _yawSpeed; if (targetSpeed != 0.0f) { diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f241be8b35..160b227127 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -21,7 +21,11 @@ const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float JUMP_SPEED = 3.5f; const float MAX_FALL_HEIGHT = 20.0f; -#define DEBUG_STATE_CHANGE +#ifdef DEBUG_STATE_CHANGE +#define SET_STATE(desiredState, reason) setState(desiredState, reason) +#else +#define SET_STATE(desiredState, reason) setState(desiredState) +#endif // helper class for simple ray-traces from character class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { @@ -65,7 +69,6 @@ CharacterController::CharacterController() { _hasSupport = false; _pendingFlags = PENDING_FLAG_UPDATE_SHAPE; - } bool CharacterController::needsRemoval() const { @@ -274,10 +277,14 @@ static const char* stateToStr(CharacterController::State state) { } #endif // #ifdef DEBUG_STATE_CHANGE +#ifdef DEBUG_STATE_CHANGE +void CharacterController::setState(State desiredState, const char* reason) { +#else void CharacterController::setState(State desiredState) { +#endif if (desiredState != _state) { #ifdef DEBUG_STATE_CHANGE - qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "<-" << stateToStr(_state); + qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason; #endif if (desiredState == State::Hover && _state != State::Hover) { // hover enter @@ -339,7 +346,7 @@ void CharacterController::setEnabled(bool enabled) { } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; } - setState(State::Hover); + SET_STATE(State::Hover, "setEnabled"); _enabled = enabled; } } @@ -438,8 +445,8 @@ void CharacterController::preSimulation() { const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; - const btScalar UPWARD_VELOCITY_THRESHOLD = 0.05f; - const btScalar MAX_FLYING_SPEED = 30.0f; + const btScalar UPWARD_VELOCITY_THRESHOLD = 0.1f; + const btScalar MAX_WALKING_SPEED = 2.5f; quint64 now = usecTimestampNow(); @@ -452,23 +459,22 @@ void CharacterController::preSimulation() { } bool jumpButtonHeld = _pendingFlags & PENDING_FLAG_JUMP; - bool wantsToGoUp = !jumpButtonHeld && _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD; - bool tooFast = actualHorizVelocity.length() > (MAX_FLYING_SPEED / 2.0f); + bool flyingFast = _state == State::Hover && actualHorizVelocity.length() > (MAX_WALKING_SPEED * 0.75f); switch (_state) { case State::Ground: if (!rayCallback.hasHit() && !_hasSupport) { - setState(State::Hover); + SET_STATE(State::Hover, "no ground"); } else if (_pendingFlags & PENDING_FLAG_JUMP) { _takeOffJumpButtonID = _jumpButtonDownCount; - setState(State::Takeoff); + SET_STATE(State::Takeoff, "jump pressed"); } break; case State::Takeoff: if (!rayCallback.hasHit() && !_hasSupport) { - setState(State::Hover); + SET_STATE(State::Hover, "no ground"); } else if ((now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) { - setState(State::InAir); + SET_STATE(State::InAir, "takeoff done"); _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; velocity += _jumpSpeed * _currentUp; _rigidBody->setLinearVelocity(velocity); @@ -476,17 +482,19 @@ void CharacterController::preSimulation() { break; case State::InAir: { if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) { - setState(State::Ground); - } else if ((jumpButtonHeld && ((_takeOffJumpButtonID != _jumpButtonDownCount) || (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD)) || wantsToGoUp) { - setState(State::Hover); + SET_STATE(State::Ground, "hit ground"); + } else if (jumpButtonHeld && (_takeOffJumpButtonID != _jumpButtonDownCount)) { + SET_STATE(State::Hover, "double jump button"); + } else if (jumpButtonHeld && (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD) { + SET_STATE(State::Hover, "jump button held"); } break; } case State::Hover: - if (!jumpButtonHeld && !wantsToGoUp && _floorDistance < MIN_HOVER_HEIGHT && !tooFast) { - setState(State::InAir); - } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !tooFast) { - setState(State::Ground); + if ((_floorDistance < MIN_HOVER_HEIGHT) && !jumpButtonHeld && !flyingFast) { + SET_STATE(State::InAir, "near ground"); + } else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !flyingFast) { + SET_STATE(State::Ground, "touching ground"); } break; } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 97bda5c5d5..bb4a135ca3 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -31,6 +31,8 @@ class btRigidBody; class btCollisionWorld; class btDynamicsWorld; +//#define DEBUG_STATE_CHANGE + class CharacterController : public btCharacterControllerInterface { public: CharacterController(); @@ -92,7 +94,11 @@ public: bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); protected: +#ifdef DEBUG_STATE_CHANGE + void setState(State state, const char* reason); +#else void setState(State state); +#endif void updateUpAxis(const glm::quat& rotation); bool checkForSupport(btCollisionWorld* collisionWorld) const; From 656608e2ffaff0f21effbe461b8f36437addd6d1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 2 Feb 2016 12:08:52 -0800 Subject: [PATCH 13/37] Fixes for away.js --- .../meshes/defaultAvatar_full/avatar-animation.json | 1 + libraries/animation/src/Rig.cpp | 11 +++++++---- libraries/animation/src/Rig.h | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 37da0c37cc..a4e39969b4 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -377,6 +377,7 @@ "interpTarget": 30, "interpDuration": 30, "transitions": [ + { "var": "isNotAway", "state": "awayOutro" }, { "var": "awayIntroOnDone", "state": "away"} ] }, diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 64935691c8..2ea9d782d5 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -784,11 +784,14 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos t += deltaTime; - if (_enableInverseKinematics) { - _animVars.set("ikOverlayAlpha", 1.0f); - } else { - _animVars.set("ikOverlayAlpha", 0.0f); + if (_enableInverseKinematics != _lastEnableInverseKinematics) { + if (_enableInverseKinematics) { + _animVars.set("ikOverlayAlpha", 1.0f); + } else { + _animVars.set("ikOverlayAlpha", 0.0f); + } } + _lastEnableInverseKinematics = _enableInverseKinematics; } _lastFront = front; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index e12af16e41..a360140b16 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -301,6 +301,7 @@ public: std::map _origRoleAnimations; std::vector _prefetchedAnimations; + bool _lastEnableInverseKinematics { false }; bool _enableInverseKinematics { true }; private: From 25632b63b70a4b25c55066a1781a972503fbd81e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 2 Feb 2016 13:00:35 -0800 Subject: [PATCH 14/37] Adjust Entities.addEntity to not bid on simulation from AC Script --- .../entities/src/EntityScriptingInterface.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6bfcc66f1e..5d793d7547 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -131,17 +131,20 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties _entityTree->withWriteLock([&] { EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); if (entity) { - // This Node is creating a new object. If it's in motion, set this Node as the simulator. - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); - propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); if (propertiesWithSimID.parentRelatedPropertyChanged()) { // due to parenting, the server may not know where something is in world-space, so include the bounding cube. propertiesWithSimID.setQueryAACube(entity->getQueryAACube()); } - // and make note of it now, so we can act on it right away. - entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); + if (_bidOnSimulationOwnership) { + // This Node is creating a new object. If it's in motion, set this Node as the simulator. + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + + // and make note of it now, so we can act on it right away. + propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); + entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); + } entity->setLastBroadcast(usecTimestampNow()); } else { From cfff7657310c6e1f7fd85be9cf9bf82b14abe9ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 14:21:34 -0800 Subject: [PATCH 15/37] allow for absolute path handling at entity-server --- assignment-client/src/octree/OctreeServer.cpp | 27 ++++++++++++------- assignment-client/src/octree/OctreeServer.h | 2 +- .../resources/describe-settings.json | 6 ++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 81e25cc7ba..95c869c874 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1030,13 +1030,12 @@ void OctreeServer::readConfiguration() { qDebug() << "wantPersist=" << _wantPersist; if (_wantPersist) { - QString persistFilename; - if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) { - persistFilename = getMyDefaultPersistFilename(); + if (!readOptionString("persistFilePath", settingsSectionObject, _persistFilePath) + && !readOptionString("persistFilename", settingsSectionObject, _persistFilePath)) { + _persistFilePath = getMyDefaultPersistFilename(); } - strcpy(_persistFilename, qPrintable(persistFilename)); - qDebug("persistFilename=%s", _persistFilename); + qDebug() << "persistFilePath=" << _persistFilePath; _persistAsFileType = "json.gz"; @@ -1145,8 +1144,16 @@ void OctreeServer::domainSettingsRequestComplete() { if (_wantPersist) { // If persist filename does not exist, let's see if there is one beside the application binary // If there is, let's copy it over to our target persist directory - auto persistPath = ServerPathUtils::getDataFilePath("entities/" + QString(_persistFilename)); - if (!QFile::exists(persistPath)) { + QDir persistPath { _persistFilePath }; + QString absoluteFilePath = persistPath.path(); + + if (persistPath.isRelative()) { + // if the domain settings passed us a relative path, make an absolute path that is relative to the + // default data directory + absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); + } + + if (!QFile::exists(absoluteFilePath)) { qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz"; @@ -1154,7 +1161,7 @@ void OctreeServer::domainSettingsRequestComplete() { // This is the old persist path, based on the current persist filename, which could // be a custom filename set by the user. - auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilename); + auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilePath); // This is the old default persist path. auto oldDefaultPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(OLD_DEFAULT_PERSIST_FILENAME); @@ -1181,14 +1188,14 @@ void OctreeServer::domainSettingsRequestComplete() { if (shouldCopy) { qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistPath; - QFile::copy(pathToCopyFrom, persistPath); + QFile::copy(pathToCopyFrom, absoluteFilePath); } else { qDebug() << "No existing persist file found"; } } // now set up PersistThread - _persistThread = new OctreePersistThread(_tree, persistPath, _persistInterval, + _persistThread = new OctreePersistThread(_tree, absoluteFilePath, _persistInterval, _wantBackup, _settings, _debugTimestampNow, _persistAsFileType); _persistThread->initialize(true); } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index f1aa9531e8..1430715571 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -169,7 +169,7 @@ protected: int _statusPort; QString _statusHost; - char _persistFilename[MAX_FILENAME_LENGTH]; + QString _persistFilePath; QString _persistAsFileType; int _packetsPerClientPerInterval; int _packetsTotalPerInterval; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index e38aa2a75a..f024ba5648 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -383,9 +383,9 @@ "assignment-types": [6], "settings": [ { - "name": "persistFilename", - "label": "Entities Filename", - "help": "the path to the file entities are stored in. Make sure the path exists.", + "name": "persistFilePath", + "label": "Entities File Path", + "help": "The path to the file entities are stored in. If path is relative it will be relative to the application data directory.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From cede14fdc6bfacbac590a504698342c250f19cd8 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 2 Feb 2016 14:01:44 -0800 Subject: [PATCH 16/37] Don't cut off title of windows without close icons --- interface/resources/qml/windows/DefaultFrame.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index a082db5a92..c58f9ca545 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -6,8 +6,10 @@ import "../controls" Frame { id: frame + property bool wideTopMargin: (window && (window.closable || window.title)); + Rectangle { - anchors { margins: -iconSize; topMargin: -iconSize * ((window && window.closable) ? 2 : 1); } + anchors { margins: -iconSize; topMargin: -iconSize * (wideTopMargin ? 2 : 1); } anchors.fill: parent; color: "#7f7f7f7f"; radius: 3; From 4d91b8b7d625271d44bf551b7a88f7a3bfb60585 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 14:38:17 -0800 Subject: [PATCH 17/37] fix check for existing persist file directory --- assignment-client/src/octree/OctreeServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 95c869c874..c35d3d1cf8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1179,14 +1179,14 @@ void OctreeServer::domainSettingsRequestComplete() { pathToCopyFrom = oldDefaultPersistPath; } - QDir persistFileDirectory = QDir(persistPath).filePath(".."); + QDir persistFileDirectory { QDir { absoluteFilePath }.dirName() }; if (!persistFileDirectory.exists()) { qDebug() << "Creating data directory " << persistFileDirectory.absolutePath(); persistFileDirectory.mkpath("."); } if (shouldCopy) { - qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistPath; + qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << absoluteFilePath; QFile::copy(pathToCopyFrom, absoluteFilePath); } else { From 13d58003bec98ce646c9676eaa5bdf040b391a35 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:02:12 -0800 Subject: [PATCH 18/37] migrate persistFilename to persistFilePath in DS settings --- .../resources/describe-settings.json | 2 +- .../src/DomainServerSettingsManager.cpp | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index f024ba5648..f34d7ec8fb 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1,5 +1,5 @@ { - "version": 1.0, + "version": 1.1, "settings": [ { "name": "metaverse", diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index e10007784f..a0e647ed89 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -124,6 +124,30 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList // reload the master and user config so that the merged config is right _configMap.loadMasterAndUserConfig(argumentList); } + } else if (oldVersion < 1.1) { + static const QString ENTITY_FILE_NAME_KEYPATH = "entity_server_settings.persistFilename"; + static const QString ENTITY_FILE_PATH_KEYPATH = "entity_server_settings.persistFilePath"; + + // this was prior to change of poorly named entitiesFileName to entitiesFilePath + QVariant* persistFileNameVariant = valueForKeyPath(_configMap.getMergedConfig(), ENTITY_FILE_NAME_KEYPATH); + if (persistFileNameVariant && persistFileNameVariant->canConvert(QMetaType::QString)) { + QString persistFileName = persistFileNameVariant->toString(); + + qDebug() << "Migrating persistFilename to persistFilePath for entity-server settings"; + + // grab the persistFilePath option, create it if it doesn't exist + QVariant* persistFilePath = valueForKeyPath(_configMap.getUserConfig(), ENTITY_FILE_PATH_KEYPATH, true); + + // write the migrated value + *persistFilePath = persistFileName; + + // write the new settings to the json file + persistToFile(); + + // reload the master and user config so that the merged config is right + _configMap.loadMasterAndUserConfig(argumentList); + } + } } From 6cc3b2b47f82022ea00925887fa6ffbb9029e200 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 2 Feb 2016 15:04:28 -0800 Subject: [PATCH 19/37] Fixed unused variable warnings on OSX and Linux --- interface/src/avatar/MyAvatar.cpp | 1 - libraries/physics/src/CharacterController.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4253091533..b99430cae3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1314,7 +1314,6 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { const float RENDER_HEAD_CUTOFF_DISTANCE = 0.5f; bool MyAvatar::cameraInsideHead() const { - const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 160b227127..941428f03a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -445,7 +445,6 @@ void CharacterController::preSimulation() { const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND; const btScalar MIN_HOVER_HEIGHT = 2.5f; const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND; - const btScalar UPWARD_VELOCITY_THRESHOLD = 0.1f; const btScalar MAX_WALKING_SPEED = 2.5f; quint64 now = usecTimestampNow(); From 9633e40c6e61a80f4fa9f6bba10c6208e6b9589e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:15:19 -0800 Subject: [PATCH 20/37] add code to remove old persistFilename setting --- .../src/DomainServerSettingsManager.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index a0e647ed89..98bb63241e 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -125,11 +125,13 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList _configMap.loadMasterAndUserConfig(argumentList); } } else if (oldVersion < 1.1) { - static const QString ENTITY_FILE_NAME_KEYPATH = "entity_server_settings.persistFilename"; - static const QString ENTITY_FILE_PATH_KEYPATH = "entity_server_settings.persistFilePath"; + static const QString ENTITY_SERVER_SETTINGS_KEY = "entity_server_settings"; + static const QString ENTITY_FILE_NAME_KEY = "persistFilename"; + static const QString ENTITY_FILE_PATH_KEYPATH = ENTITY_SERVER_SETTINGS_KEY + ".persistFilePath"; // this was prior to change of poorly named entitiesFileName to entitiesFilePath - QVariant* persistFileNameVariant = valueForKeyPath(_configMap.getMergedConfig(), ENTITY_FILE_NAME_KEYPATH); + QVariant* persistFileNameVariant = valueForKeyPath(_configMap.getMergedConfig(), + ENTITY_SERVER_SETTINGS_KEY + "." + ENTITY_FILE_NAME_KEY); if (persistFileNameVariant && persistFileNameVariant->canConvert(QMetaType::QString)) { QString persistFileName = persistFileNameVariant->toString(); @@ -141,6 +143,15 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList // write the migrated value *persistFilePath = persistFileName; + // remove the old setting + QVariant* entityServerVariant = valueForKeyPath(_configMap.getUserConfig(), ENTITY_SERVER_SETTINGS_KEY); + if (entityServerVariant && entityServerVariant->canConvert(QMetaType::QVariantMap)) { + QVariantMap entityServerMap = entityServerVariant->toMap(); + entityServerMap.remove(ENTITY_FILE_NAME_KEY); + + *entityServerVariant = entityServerMap; + } + // write the new settings to the json file persistToFile(); From ff239a7c6afe3e68748fc379ddedd12a48ca693b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:17:45 -0800 Subject: [PATCH 21/37] add helper text for extension to persistFilePath --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index f34d7ec8fb..65949e98a0 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -385,7 +385,7 @@ { "name": "persistFilePath", "label": "Entities File Path", - "help": "The path to the file entities are stored in. If path is relative it will be relative to the application data directory.", + "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The entities file extension should be .json.gz.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From f24f2749e14b41e7a8f942c52ebaa36c36d0af72 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 2 Feb 2016 15:19:12 -0800 Subject: [PATCH 22/37] Make users.js show QML window for edit friends --- examples/users.js | 17 ++++++++++- interface/src/Application.cpp | 16 ---------- interface/src/Application.h | 2 -- .../GlobalServicesScriptingInterface.cpp | 3 -- .../GlobalServicesScriptingInterface.h | 3 +- libraries/ui/src/OffscreenUi.cpp | 29 ++++++++++--------- libraries/ui/src/QmlWebWindowClass.cpp | 5 +++- 7 files changed, 36 insertions(+), 39 deletions(-) diff --git a/examples/users.js b/examples/users.js index f63184625d..0f9be42835 100644 --- a/examples/users.js +++ b/examples/users.js @@ -235,7 +235,12 @@ var usersWindow = (function () { FRIENDS_BUTTON_HEIGHT = FRIENDS_BUTTON_SVG_HEIGHT, FRIENDS_BUTTON_COLOR = { red: 225, green: 225, blue: 225 }, FRIENDS_BUTTON_ALPHA = 0.95, + FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends", + FRIENDS_WINDOW_WIDTH = 290, + FRIENDS_WINDOW_HEIGHT = 500, + FRIENDS_WINDOW_TITLE = "Add/Remove Friends", friendsButton, + friendsWindow, OPTION_BACKGROUND_COLOR = { red: 60, green: 60, blue: 60 }, OPTION_BACKGROUND_ALPHA = 0.1, @@ -643,7 +648,17 @@ var usersWindow = (function () { } if (clickedOverlay === friendsButton) { - GlobalServices.editFriends(); + if (!friendsWindow) { + friendsWindow = new OverlayWebWindow({ + title: FRIENDS_WINDOW_TITLE, + width: FRIENDS_WINDOW_WIDTH, + height: FRIENDS_WINDOW_HEIGHT, + visible: false + }); + } + friendsWindow.setURL(FRIENDS_WINDOW_URL); + friendsWindow.setVisible(true); + friendsWindow.raise(); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 883b082d0e..d05440b2e6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4615,22 +4615,6 @@ void Application::activeChanged(Qt::ApplicationState state) { break; } } -void Application::showFriendsWindow() { - const QString FRIENDS_WINDOW_OBJECT_NAME = "FriendsWindow"; - const QString FRIENDS_WINDOW_TITLE = "Add/Remove Friends"; - const QString FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends"; - const int FRIENDS_WINDOW_WIDTH = 290; - const int FRIENDS_WINDOW_HEIGHT = 500; - auto webWindowClass = _window->findChildren(FRIENDS_WINDOW_OBJECT_NAME); - if (webWindowClass.empty()) { - auto friendsWindow = new WebWindowClass(FRIENDS_WINDOW_TITLE, FRIENDS_WINDOW_URL, FRIENDS_WINDOW_WIDTH, - FRIENDS_WINDOW_HEIGHT); - friendsWindow->setParent(_window); - friendsWindow->setObjectName(FRIENDS_WINDOW_OBJECT_NAME); - connect(friendsWindow, &WebWindowClass::closed, &WebWindowClass::deleteLater); - friendsWindow->setVisible(true); - } -} void Application::postLambdaEvent(std::function f) { if (this->thread() == QThread::currentThread()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 4b32d8879b..ef8a5377fd 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -245,8 +245,6 @@ public slots: void handleLocalServerConnection(); void readArgumentsFromLocalSocket(); - void showFriendsWindow(); - void packageModel(); void openUrl(const QUrl& url); diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index e764473107..7dac0247bd 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -144,6 +144,3 @@ void GlobalServicesScriptingInterface::updateDownloadInfo() { emit downloadInfoChanged(getDownloadInfo()); } -void GlobalServicesScriptingInterface::editFriends() { - QMetaObject::invokeMethod(qApp, "showFriendsWindow"); -} diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index e38bfc0eb6..11d8735187 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -45,8 +45,7 @@ public: public slots: DownloadInfoResult getDownloadInfo(); void updateDownloadInfo(); - void editFriends(); - + private slots: void loggedOut(); void checkDownloadInfo(); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 8e52507243..1d471d5419 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -45,6 +45,20 @@ private: bool _navigationFocused { false }; }; +QString fixupHifiUrl(const QString& urlString) { + static const QString ACCESS_TOKEN_PARAMETER = "access_token"; + static const QString ALLOWED_HOST = "metaverse.highfidelity.com"; + QUrl url(urlString); + QUrlQuery query(url); + if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) { + AccountManager& accountManager = AccountManager::getInstance(); + query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager.getAccountInfo().getAccessToken().token); + url.setQuery(query.query()); + return url.toString(); + } + return urlString; +} + class UrlHandler : public QObject { Q_OBJECT public: @@ -60,20 +74,7 @@ public: // FIXME hack for authentication, remove when we migrate to Qt 5.6 Q_INVOKABLE QString fixupUrl(const QString& originalUrl) { - static const QString ACCESS_TOKEN_PARAMETER = "access_token"; - static const QString ALLOWED_HOST = "metaverse.highfidelity.com"; - QString result = originalUrl; - QUrl url(originalUrl); - QUrlQuery query(url); - if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) { - qDebug() << "Updating URL with auth token"; - AccountManager& accountManager = AccountManager::getInstance(); - query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager.getAccountInfo().getAccessToken().token); - url.setQuery(query.query()); - result = url.toString(); - } - - return result; + return fixupHifiUrl(originalUrl); } }; diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 96e99654c8..f12fb51b19 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -49,8 +49,11 @@ QString QmlWebWindowClass::getURL() const { return result.toString(); } +// HACK find a good place to declare and store this +extern QString fixupHifiUrl(const QString& urlString); + void QmlWebWindowClass::setURL(const QString& urlString) { DependencyManager::get()->executeOnUiThread([=] { - _qmlWindow->setProperty(URL_PROPERTY, urlString); + _qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString)); }); } From bc7fda0ae9c69f6153d1fc6b56a19009a01fe440 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 2 Feb 2016 15:19:47 -0800 Subject: [PATCH 23/37] Set desirable global settings for QML web views --- interface/resources/qml/hifi/Desktop.qml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 9d527c697a..5951101194 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -1,5 +1,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtWebEngine 1.1; import "../desktop" import ".." @@ -7,6 +8,13 @@ import ".." Desktop { id: desktop + Component.onCompleted: { + WebEngine.settings.javascriptCanOpenWindows = false; + WebEngine.settings.javascriptCanAccessClipboard = false; + WebEngine.settings.spatialNavigationEnabled = true; + WebEngine.settings.localContentCanAccessRemoteUrls = true; + } + // The tool window, one instance property alias toolWindow: toolWindow ToolWindow { id: toolWindow } From 90b78feb1ee27ecd3dd35ab31f453f4912362e5b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:37:34 -0800 Subject: [PATCH 24/37] force models file to end in .json.gz --- assignment-client/src/octree/OctreeServer.cpp | 8 +++++++- domain-server/resources/describe-settings.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c35d3d1cf8..9a5b6ec0fd 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1153,6 +1153,11 @@ void OctreeServer::domainSettingsRequestComplete() { absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); } + // force the persist file to end with .json.gz + if (!absoluteFilePath.endsWith(".json.gz", Qt::CaseInsensitive)) { + absoluteFilePath += ".json.gz"; + } + if (!QFile::exists(absoluteFilePath)) { qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; @@ -1179,7 +1184,8 @@ void OctreeServer::domainSettingsRequestComplete() { pathToCopyFrom = oldDefaultPersistPath; } - QDir persistFileDirectory { QDir { absoluteFilePath }.dirName() }; + QDir persistFileDirectory { QDir::cleanPath(absoluteFilePath + "/..") }; + if (!persistFileDirectory.exists()) { qDebug() << "Creating data directory " << persistFileDirectory.absolutePath(); persistFileDirectory.mkpath("."); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 65949e98a0..870573ef6c 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -385,7 +385,7 @@ { "name": "persistFilePath", "label": "Entities File Path", - "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The entities file extension should be .json.gz.", + "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The filename must end in .json.gz.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From 99d1fa08fdd2fc51cad7f20f9f1ac0df361305be Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:49:40 -0800 Subject: [PATCH 25/37] handle incorrect casing in persist file extension --- assignment-client/src/octree/OctreeServer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9a5b6ec0fd..2eb7d00af8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1154,8 +1154,11 @@ void OctreeServer::domainSettingsRequestComplete() { } // force the persist file to end with .json.gz - if (!absoluteFilePath.endsWith(".json.gz", Qt::CaseInsensitive)) { - absoluteFilePath += ".json.gz"; + if (!absoluteFilePath.endsWith(_persistAsFileType, Qt::CaseInsensitive)) { + absoluteFilePath += _persistAsFileType; + } else { + // make sure the casing of .json.gz is correct + absoluteFilePath.replace(_persistAsFileType, _persistAsFileType, Qt::CaseInsensitive); } if (!QFile::exists(absoluteFilePath)) { From 8ab15770b8c7840fe09612ab2b3351266be9681f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:52:12 -0800 Subject: [PATCH 26/37] use absolutePath for absolute persist path --- assignment-client/src/octree/OctreeServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 2eb7d00af8..558b59edf7 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1145,7 +1145,7 @@ void OctreeServer::domainSettingsRequestComplete() { // If persist filename does not exist, let's see if there is one beside the application binary // If there is, let's copy it over to our target persist directory QDir persistPath { _persistFilePath }; - QString absoluteFilePath = persistPath.path(); + QString absoluteFilePath = persistPath.absolutePath(); if (persistPath.isRelative()) { // if the domain settings passed us a relative path, make an absolute path that is relative to the From 2c1623ed427b326a844c276e663a4ed9d377ac1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 16:07:14 -0800 Subject: [PATCH 27/37] use extension with preceeding period --- assignment-client/src/octree/OctreeServer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 558b59edf7..69c54a17d5 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1153,12 +1153,14 @@ void OctreeServer::domainSettingsRequestComplete() { absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); } + static const QString ENTITY_PERSIST_EXTENSION = ".json.gz"; + // force the persist file to end with .json.gz - if (!absoluteFilePath.endsWith(_persistAsFileType, Qt::CaseInsensitive)) { - absoluteFilePath += _persistAsFileType; + if (!absoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) { + absoluteFilePath += ENTITY_PERSIST_EXTENSION; } else { // make sure the casing of .json.gz is correct - absoluteFilePath.replace(_persistAsFileType, _persistAsFileType, Qt::CaseInsensitive); + absoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive); } if (!QFile::exists(absoluteFilePath)) { From 30e97c2a76bcdafa30d2f2cef9866917de680fc6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Feb 2016 16:34:06 -0800 Subject: [PATCH 28/37] run attachedEntitiesManager.js by default, but without a UI --- examples/attachedEntitiesManager.js | 75 ++++++++++++++++------------- examples/defaultScripts.js | 1 + 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/examples/attachedEntitiesManager.js b/examples/attachedEntitiesManager.js index 01f8f861c9..c44ac66a44 100644 --- a/examples/attachedEntitiesManager.js +++ b/examples/attachedEntitiesManager.js @@ -22,41 +22,44 @@ var MINIMUM_DROP_DISTANCE_FROM_JOINT = 0.4; var ATTACHED_ENTITY_SEARCH_DISTANCE = 10.0; var ATTACHED_ENTITIES_SETTINGS_KEY = "ATTACHED_ENTITIES"; var DRESSING_ROOM_DISTANCE = 2.0; +var SHOW_TOOL_BAR = false; // tool bar -HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -var BUTTON_SIZE = 32; -var PADDING = 3; -Script.include(["libraries/toolBars.js"]); -var toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.attachedEntities.toolbar", function(screenSize) { - return { - x: (BUTTON_SIZE + PADDING), - y: (screenSize.y / 2 - BUTTON_SIZE * 2 + PADDING) - }; -}); -var saveButton = toolBar.addOverlay("image", { - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: "http://headache.hungry.com/~seth/hifi/save.png", - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1 -}); -var loadButton = toolBar.addOverlay("image", { - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: "http://headache.hungry.com/~seth/hifi/load.png", - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1 -}); +if (SHOW_TOOL_BAR) { + HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + var BUTTON_SIZE = 32; + var PADDING = 3; + Script.include(["libraries/toolBars.js"]); + var toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.attachedEntities.toolbar", function(screenSize) { + return { + x: (BUTTON_SIZE + PADDING), + y: (screenSize.y / 2 - BUTTON_SIZE * 2 + PADDING) + }; + }); + var saveButton = toolBar.addOverlay("image", { + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: "http://headache.hungry.com/~seth/hifi/save.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 + }); + var loadButton = toolBar.addOverlay("image", { + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: "http://headache.hungry.com/~seth/hifi/load.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 + }); +} function mousePressEvent(event) { @@ -73,10 +76,14 @@ function mousePressEvent(event) { } function scriptEnding() { - toolBar.cleanup(); + if (SHOW_TOOL_BAR) { + toolBar.cleanup(); + } } -Controller.mousePressEvent.connect(mousePressEvent); +if (SHOW_TOOL_BAR) { + Controller.mousePressEvent.connect(mousePressEvent); +} Script.scriptEnding.connect(scriptEnding); diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 5ca62470ee..35af5f4eae 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -21,3 +21,4 @@ Script.load("controllers/squeezeHands.js"); Script.load("grab.js"); Script.load("directory.js"); Script.load("dialTone.js"); +Script.load("attachedEntitiesManager.js"); From 61daed537617919b859e99622b32ccaeee550a88 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 2 Feb 2016 17:39:43 -0800 Subject: [PATCH 29/37] fix userdata for pistol --- unpublishedScripts/hiddenEntityReset.js | 48 ++++++++++++------------- unpublishedScripts/masterReset.js | 48 ++++++++++++------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 995ebdaad6..903388bb43 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -299,31 +299,31 @@ }, dynamic: true, userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.07079616189002991, + y: 0.20177987217903137, + z: 0.06374628841876984 + }, { + x: -0.5863648653030396, + y: -0.46007341146469116, + z: 0.46949487924575806, + w: -0.4733745753765106 + }], + LeftHand: [{ + x: 0.1802254319190979, + y: 0.13442856073379517, + z: 0.08504903316497803 + }, { + x: 0.2198076844215393, + y: -0.7377811074256897, + z: 0.2780133783817291, + w: 0.574519157409668 + }] + } + }, grabbableKey: { - wearable: { - joints: { - RightHand: [{ - x: 0.07079616189002991, - y: 0.20177987217903137, - z: 0.06374628841876984 - }, { - x: -0.5863648653030396, - y: -0.46007341146469116, - z: 0.46949487924575806, - w: -0.4733745753765106 - }], - LeftHand: [{ - x: 0.1802254319190979, - y: 0.13442856073379517, - z: 0.08504903316497803 - }, { - x: 0.2198076844215393, - y: -0.7377811074256897, - z: 0.2780133783817291, - w: 0.574519157409668 - }] - } - }, invertSolidWhileHeld: true }, resetMe: { diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 8777ad5269..306ae294fd 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -283,31 +283,31 @@ MasterReset = function() { damping: 0.5, collisionSoundURL: "http://hifi-content.s3.amazonaws.com/james/pistol/sounds/drop.wav", userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.07079616189002991, + y: 0.20177987217903137, + z: 0.06374628841876984 + }, { + x: -0.5863648653030396, + y: -0.46007341146469116, + z: 0.46949487924575806, + w: -0.4733745753765106 + }], + LeftHand: [{ + x: 0.1802254319190979, + y: 0.13442856073379517, + z: 0.08504903316497803 + }, { + x: 0.2198076844215393, + y: -0.7377811074256897, + z: 0.2780133783817291, + w: 0.574519157409668 + }] + } + }, grabbableKey: { - wearable: { - joints: { - RightHand: [{ - x: 0.07079616189002991, - y: 0.20177987217903137, - z: 0.06374628841876984 - }, { - x: -0.5863648653030396, - y: -0.46007341146469116, - z: 0.46949487924575806, - w: -0.4733745753765106 - }], - LeftHand: [{ - x: 0.1802254319190979, - y: 0.13442856073379517, - z: 0.08504903316497803 - }, { - x: 0.2198076844215393, - y: -0.7377811074256897, - z: 0.2780133783817291, - w: 0.574519157409668 - }] - } - }, invertSolidWhileHeld: true }, resetMe: { From 963c71a47698536a979479990f0e712ddfea401b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 3 Feb 2016 09:28:49 -0800 Subject: [PATCH 30/37] Fix ES rejecting unowned entity physics updates --- libraries/entities/src/EntityTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 34dd809510..1405121d2e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -194,7 +194,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI // the entire update is suspect --> ignore it return false; } - } else { + } else if (simulationBlocked) { simulationBlocked = senderID != entity->getSimulatorID(); } if (simulationBlocked) { From 51b335c9020d20686c25d8658068367e39f39edb Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 3 Feb 2016 09:53:14 -0800 Subject: [PATCH 31/37] reduce cellscience volume --- .../DomainContent/CellScience/Scripts/playBackgroundAudio.js | 4 +--- .../CellScience/Scripts/showButtonToPlaySound.js | 2 +- .../DomainContent/CellScience/Scripts/showIdentification.js | 2 +- unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js | 3 ++- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js b/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js index e709f6e06e..856b9f8f67 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/playBackgroundAudio.js @@ -20,7 +20,7 @@ stereo: true, loop: true, localOnly: true, - volume: 0.2 + volume: 0.035 }; this.sound = SoundCache.getSound(self.soundURL); @@ -36,7 +36,6 @@ } } - this.enterEntity = function(entityID) { print("entering audio zone"); if (self.sound.downloaded) { @@ -49,7 +48,6 @@ } - this.leaveEntity = function(entityID) { print("leaving audio area " + self.userData.name); if (self.soundPlaying !== false) { diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js index 7e51dcd9d1..65fddd7ad3 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js @@ -24,7 +24,7 @@ stereo: true, loop: false, localOnly: true, - volume: 0.2 + volume: 0.035 }; this.sound = SoundCache.getSound(this.soundURL); } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index bfc6c70292..2e37f3a51f 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -22,7 +22,7 @@ stereo: true, loop: false, localOnly: true, - volume: 0.2, + volume: 0.035, position: this.position }; this.sound = SoundCache.getSound(this.soundURL); diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index c644cbe4f9..101ce54a5e 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -25,8 +25,9 @@ loop: false, localOnly: false, position: this.position, - volume: 0.2 + volume: 0.035 }; + this.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); //print('Script.clearTimeout PRELOADING A ZOOM ENTITY') print(" portal destination is " + portalDestination); From fff603e4e2f5a48567f7fb390cebdcb0c07a019d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 3 Feb 2016 10:21:27 -0800 Subject: [PATCH 32/37] Removed comment --- libraries/physics/src/CharacterController.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 941428f03a..d16c406658 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -499,8 +499,6 @@ void CharacterController::preSimulation() { } } - /// _walkVelocity.dot(_currentUp) > UPWARD_VELOCITY_THRESHOLD - _previousFlags = _pendingFlags; _pendingFlags &= ~PENDING_FLAG_JUMP; From ad2a7bfc3c4048bae461a0de08244ab0108c92fc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 3 Feb 2016 10:54:08 -0800 Subject: [PATCH 33/37] code review --- examples/attachedEntitiesManager.js | 4 ++-- examples/controllers/handControllerGrab.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/attachedEntitiesManager.js b/examples/attachedEntitiesManager.js index c44ac66a44..1cdd61ad39 100644 --- a/examples/attachedEntitiesManager.js +++ b/examples/attachedEntitiesManager.js @@ -40,7 +40,7 @@ if (SHOW_TOOL_BAR) { var saveButton = toolBar.addOverlay("image", { width: BUTTON_SIZE, height: BUTTON_SIZE, - imageURL: "http://headache.hungry.com/~seth/hifi/save.png", + imageURL: ".../save.png", color: { red: 255, green: 255, @@ -51,7 +51,7 @@ if (SHOW_TOOL_BAR) { var loadButton = toolBar.addOverlay("image", { width: BUTTON_SIZE, height: BUTTON_SIZE, - imageURL: "http://headache.hungry.com/~seth/hifi/load.png", + imageURL: ".../load.png", color: { red: 255, green: 255, diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 842c54b86d..ee3184d78f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1224,6 +1224,7 @@ function MyController(hand) { return true; } } + return false; } this.getPresetPosition = function() { From 26abca92aeab150f198f5d21da12e62cf9881288 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 10:55:07 -0800 Subject: [PATCH 34/37] don't move the re-used mute environment packet --- assignment-client/src/audio/AudioMixer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 54032e993f..ca60528a71 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -553,15 +553,24 @@ void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer mes if (sendingNode->isAllowedEditor()) { qDebug() << "Received a mute environment packet of" << message->getSize() << "bytes"; - - auto newPacket = NLPacket::create(PacketType::MuteEnvironment, message->getSize()); - // Copy payload - newPacket->write(message->getRawMessage(), message->getSize()); + + glm::vec3 position; + float radius; + + auto newPacket = NLPacket::create(PacketType::MuteEnvironment, sizeof(position) + sizeof(radius)); + + // read the position and radius from the sent packet + message->readPrimitive(&position); + message->readPrimitive(&radius); + + // write them to our packet + newPacket->writePrimitive(position); + newPacket->writePrimitive(radius); nodeList->eachNode([&](const SharedNodePointer& node){ if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != sendingNode) { - nodeList->sendPacket(std::move(newPacket), *node); + nodeList->sendUnreliablePacket(*newPacket, *node); } }); } From 0e20392e663d887c4dbc21927493cdedadb85cba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 11:07:16 -0800 Subject: [PATCH 35/37] remove debug for mute environment packet --- assignment-client/src/audio/AudioMixer.cpp | 102 ++++++++++----------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ca60528a71..227ac843bb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -458,7 +458,7 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { if (otherNodeStream->getType() == PositionalAudioStream::Microphone) { streamUUID = otherNode->getUUID(); } - + // clear out the pre-mix samples before filling it up with this source memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -498,7 +498,7 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) { break; } } - + AudioMixerClientData* nodeData = static_cast(node->getLinkedData()); AvatarAudioStream* stream = nodeData->getAvatarAudioStream(); bool dataChanged = (stream->hasReverb() != hasReverb) || @@ -550,10 +550,8 @@ void AudioMixer::handleNodeAudioPacket(QSharedPointer message, void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { auto nodeList = DependencyManager::get(); - - if (sendingNode->isAllowedEditor()) { - qDebug() << "Received a mute environment packet of" << message->getSize() << "bytes"; + if (sendingNode->isAllowedEditor()) { glm::vec3 position; float radius; @@ -658,185 +656,185 @@ void AudioMixer::sendStatsPacket() { } void AudioMixer::run() { - + qDebug() << "Waiting for connection to domain to request settings from domain-server."; - + // wait until we have the domain-server settings, otherwise we bail DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::settingsReceived, this, &AudioMixer::domainSettingsRequestComplete); connect(&domainHandler, &DomainHandler::settingsReceiveFail, this, &AudioMixer::domainSettingsRequestFailed); - + ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); } void AudioMixer::domainSettingsRequestComplete() { auto nodeList = DependencyManager::get(); - + nodeList->addNodeTypeToInterestSet(NodeType::Agent); - + nodeList->linkedDataCreateCallback = [](Node* node) { node->setLinkedData(std::unique_ptr { new AudioMixerClientData }); }; - + DomainHandler& domainHandler = nodeList->getDomainHandler(); const QJsonObject& settingsObject = domainHandler.getSettingsObject(); - + // check the settings object to see if we have anything we can parse out parseSettingsObject(settingsObject); - + // queue up a connection to start broadcasting mixes now that we're ready to go QMetaObject::invokeMethod(this, "broadcastMixes", Qt::QueuedConnection); } void AudioMixer::broadcastMixes() { - auto nodeList = DependencyManager::get(); - + auto nodeList = DependencyManager::get(); + int64_t nextFrame = 0; QElapsedTimer timer; timer.start(); - + int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS; - + const int TRAILING_AVERAGE_FRAMES = 100; int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; - + while (!_isFinished) { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - + const float RATIO_BACK_OFF = 0.02f; - + const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES; const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO; - + if (usecToSleep < 0) { usecToSleep = 0; } - + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); - + float lastCutoffRatio = _performanceThrottlingRatio; bool hasRatioChanged = false; - + if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); - + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { // we've recovered and can back off the required loudness _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - + if (_performanceThrottlingRatio < 0) { _performanceThrottlingRatio = 0; } - + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; hasRatioChanged = true; } - + if (hasRatioChanged) { // set out min audability threshold from the new ratio _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; - + framesSinceCutoffEvent = 0; } } - + if (!hasRatioChanged) { ++framesSinceCutoffEvent; } - + quint64 now = usecTimestampNow(); if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { perSecondActions(); _lastPerSecondCallbackTime = now; } - + nodeList->eachNode([&](const SharedNodePointer& node) { - + if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); - + // this function will attempt to pop a frame from each audio stream. // a pointer to the popped data is stored as a member in InboundAudioStream. // That's how the popped audio data will be read for mixing (but only if the pop was successful) nodeData->checkBuffersBeforeFrameSend(); - + // if the stream should be muted, send mute packet if (nodeData->getAvatarAudioStream() && shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())) { auto mutePacket = NLPacket::create(PacketType::NoisyMute, 0); nodeList->sendPacket(std::move(mutePacket), *node); } - + if (node->getType() == NodeType::Agent && node->getActiveSocket() && nodeData->getAvatarAudioStream()) { - + int streamsMixed = prepareMixForListeningNode(node.data()); - + std::unique_ptr mixPacket; - + if (streamsMixed > 0) { int mixPacketBytes = sizeof(quint16) + AudioConstants::NETWORK_FRAME_BYTES_STEREO; mixPacket = NLPacket::create(PacketType::MixedAudio, mixPacketBytes); - + // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); mixPacket->writePrimitive(sequence); - + // pack mixed audio samples mixPacket->write(reinterpret_cast(_mixSamples), AudioConstants::NETWORK_FRAME_BYTES_STEREO); } else { int silentPacketBytes = sizeof(quint16) + sizeof(quint16); mixPacket = NLPacket::create(PacketType::SilentAudioFrame, silentPacketBytes); - + // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); mixPacket->writePrimitive(sequence); - + // pack number of silent audio samples quint16 numSilentSamples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; mixPacket->writePrimitive(numSilentSamples); } - + // Send audio environment sendAudioEnvironmentPacket(node); - + // send mixed audio packet nodeList->sendPacket(std::move(mixPacket), *node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); - + // send an audio stream stats packet if it's time if (_sendAudioStreamStats) { nodeData->sendAudioStreamStatsPackets(node); _sendAudioStreamStats = false; } - + ++_sumListeners; } } }); - + ++_numStatFrames; - + // since we're a while loop we need to help Qt's event processing QCoreApplication::processEvents(); - + if (_isFinished) { // at this point the audio-mixer is done // check if we have a deferred delete event to process (which we should once finished) QCoreApplication::sendPostedEvents(this, QEvent::DeferredDelete); break; } - + usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - (timer.nsecsElapsed() / 1000); if (usecToSleep > 0) { @@ -1114,5 +1112,3 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } - - From 93530fca72fa36ff5422cc5d8d97f4f25c034d6c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 1 Feb 2016 16:20:59 -0800 Subject: [PATCH 36/37] fix the last of the current override warnings for OS X --- interface/src/Application.h | 10 +++++----- interface/src/avatar/Avatar.h | 8 ++++---- interface/src/avatar/AvatarMotionState.h | 4 ++-- interface/src/ui/overlays/ImageOverlay.h | 2 +- interface/src/ui/overlays/TextOverlay.h | 2 +- libraries/animation/src/SwingTwistConstraint.h | 2 +- .../src/RenderableBoxEntityItem.h | 4 ++-- .../src/RenderableLightEntityItem.h | 6 +++--- .../src/RenderableLineEntityItem.h | 2 +- .../src/RenderableSphereEntityItem.h | 4 ++-- .../src/RenderableTextEntityItem.h | 2 +- .../src/RenderableWebEntityItem.h | 4 ++-- libraries/physics/src/EntityMotionState.h | 16 ++++++++-------- 13 files changed, 33 insertions(+), 33 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 4b32d8879b..3d2cb6f351 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -167,11 +167,11 @@ public: virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override; - virtual ViewFrustum* getCurrentViewFrustum() { return getDisplayViewFrustum(); } - virtual QThread* getMainThread() { return thread(); } - virtual PickRay computePickRay(float x, float y) const; - virtual glm::vec3 getAvatarPosition() const; - virtual qreal getDevicePixelRatio(); + virtual ViewFrustum* getCurrentViewFrustum() override { return getDisplayViewFrustum(); } + virtual QThread* getMainThread() override { return thread(); } + virtual PickRay computePickRay(float x, float y) const override; + virtual glm::vec3 getAvatarPosition() const override; + virtual qreal getDevicePixelRatio() override; void setActiveDisplayPlugin(const QString& pluginName); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index db247f3e85..b23b64b384 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -164,10 +164,10 @@ public: virtual void setOrientation(const glm::quat& orientation) override; // these call through to the SpatiallyNestable versions, but they are here to expose these to javascript. - Q_INVOKABLE virtual const QUuid getParentID() const { return SpatiallyNestable::getParentID(); } - Q_INVOKABLE virtual void setParentID(const QUuid& parentID); - Q_INVOKABLE virtual quint16 getParentJointIndex() const { return SpatiallyNestable::getParentJointIndex(); } - Q_INVOKABLE virtual void setParentJointIndex(quint16 parentJointIndex); + Q_INVOKABLE virtual const QUuid getParentID() const override { return SpatiallyNestable::getParentID(); } + Q_INVOKABLE virtual void setParentID(const QUuid& parentID) override; + Q_INVOKABLE virtual quint16 getParentJointIndex() const override { return SpatiallyNestable::getParentJointIndex(); } + Q_INVOKABLE virtual void setParentJointIndex(quint16 parentJointIndex) override; // NOT thread safe, must be called on main thread. glm::vec3 getUncachedLeftPalmPosition() const; diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 715c38186b..04aa5ea57c 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -61,7 +61,7 @@ public: void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; } - virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override; friend class AvatarManager; friend class Avatar; @@ -72,7 +72,7 @@ protected: ~AvatarMotionState(); virtual bool isReadyToComputeShape() const override { return true; } - virtual btCollisionShape* computeNewShape(); + virtual btCollisionShape* computeNewShape() override; // The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState // instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor. diff --git a/interface/src/ui/overlays/ImageOverlay.h b/interface/src/ui/overlays/ImageOverlay.h index 224cb42045..40da461822 100644 --- a/interface/src/ui/overlays/ImageOverlay.h +++ b/interface/src/ui/overlays/ImageOverlay.h @@ -20,7 +20,7 @@ class ImageOverlay : public QmlOverlay { public: static QString const TYPE; - virtual QString getType() const { return TYPE; } + virtual QString getType() const override { return TYPE; } static QUrl const URL; ImageOverlay(); diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 7c6e133ebd..53c1805345 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -30,7 +30,7 @@ public: void setText(const QString& text); - TextOverlay* createClone() const; + TextOverlay* createClone() const override; QSizeF textSize(const QString& text) const; // Pixels }; diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index f36dc851ea..f73bbfb233 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -51,7 +51,7 @@ public: virtual bool apply(glm::quat& rotation) const override; void setLowerSpine(bool lowerSpine) { _lowerSpine = lowerSpine; } - virtual bool isLowerSpine() const { return _lowerSpine; } + virtual bool isLowerSpine() const override { return _lowerSpine; } // SwingLimitFunction is an implementation of the constraint check described in the paper: // "The Parameterization of Joint Rotation with the Unit Quaternion" by Quang Liu and Edmond C. Prakash diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.h b/libraries/entities-renderer/src/RenderableBoxEntityItem.h index 9addfd813a..67f881dbd8 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.h @@ -22,8 +22,8 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableBoxEntityItem(const EntityItemID& entityItemID) : BoxEntityItem(entityItemID) { } - virtual void render(RenderArgs* args); - virtual void setUserData(const QString& value); + virtual void render(RenderArgs* args) override; + virtual void setUserData(const QString& value) override; SIMPLE_RENDERABLE() private: diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index aac1a4a998..2db913db0d 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -20,12 +20,12 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID) { } - virtual void render(RenderArgs* args); - virtual bool supportsDetailedRayIntersection() const { return true; } + virtual void render(RenderArgs* args) override; + virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - void** intersectedObject, bool precisionPicking) const; + void** intersectedObject, bool precisionPicking) const override; SIMPLE_RENDERABLE(); }; diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.h b/libraries/entities-renderer/src/RenderableLineEntityItem.h index 9af8c0c8ba..1227c6e63d 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.h @@ -24,7 +24,7 @@ public: _lineVerticesID(GeometryCache::UNKNOWN_ID) { } - virtual void render(RenderArgs* args); + virtual void render(RenderArgs* args) override; SIMPLE_RENDERABLE(); diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.h b/libraries/entities-renderer/src/RenderableSphereEntityItem.h index 737bee3134..5efe49854a 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.h +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.h @@ -22,8 +22,8 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableSphereEntityItem(const EntityItemID& entityItemID) : SphereEntityItem(entityItemID) { } - virtual void render(RenderArgs* args); - virtual void setUserData(const QString& value); + virtual void render(RenderArgs* args) override; + virtual void setUserData(const QString& value) override; SIMPLE_RENDERABLE(); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index 149df946f7..cbe2b11c27 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -25,7 +25,7 @@ public: RenderableTextEntityItem(const EntityItemID& entityItemID) : TextEntityItem(entityItemID) { } ~RenderableTextEntityItem() { delete _textRenderer; } - virtual void render(RenderArgs* args); + virtual void render(RenderArgs* args) override; SIMPLE_RENDERABLE(); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 799a414151..da1ddbf1a1 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -25,8 +25,8 @@ public: RenderableWebEntityItem(const EntityItemID& entityItemID); ~RenderableWebEntityItem(); - virtual void render(RenderArgs* args); - virtual void setSourceUrl(const QString& value); + virtual void render(RenderArgs* args) override; + virtual void setSourceUrl(const QString& value) override; void setProxyWindow(QWindow* proxyWindow); QObject* getEventHandler(); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 152ae7be23..2c999d0aca 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,13 +29,13 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); - virtual bool handleEasyChanges(uint32_t& flags); - virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); + virtual bool handleEasyChanges(uint32_t& flags) override; + virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; /// \return PhysicsMotionType based on params set in EntityItem - virtual PhysicsMotionType computePhysicsMotionType() const; + virtual PhysicsMotionType computePhysicsMotionType() const override; - virtual bool isMoving() const; + virtual bool isMoving() const override; // this relays incoming position/rotation to the RigidBody virtual void getWorldTransform(btTransform& worldTrans) const override; @@ -48,8 +48,8 @@ public: bool shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID); void sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step); - virtual uint32_t getIncomingDirtyFlags(); - virtual void clearIncomingDirtyFlags(); + virtual uint32_t getIncomingDirtyFlags() override; + virtual void clearIncomingDirtyFlags() override; void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } @@ -80,7 +80,7 @@ public: virtual QString getName() const override; - virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override; // eternal logic can suggest a simuator priority bid for the next outgoing update void setOutgoingPriority(quint8 priority); @@ -93,7 +93,7 @@ protected: #endif virtual bool isReadyToComputeShape() const override; - virtual btCollisionShape* computeNewShape(); + virtual btCollisionShape* computeNewShape() override; virtual void setMotionType(PhysicsMotionType motionType); // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be From ea9d84bdc47556b9e31dad5385b566840417723c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 13:18:29 -0800 Subject: [PATCH 37/37] handle downloading of absolute persist file contents --- assignment-client/src/octree/OctreeServer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 69c54a17d5..31cab68cdf 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -289,6 +289,8 @@ void OctreeServer::initHTTPManager(int port) { _httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this); } +const QString PERSIST_FILE_DOWNLOAD_PATH = "/models.json.gz"; + bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { #ifdef FORCE_CRASH @@ -310,7 +312,6 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url #endif bool showStats = false; - QString persistFile = "/" + getPersistFilename(); if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/") { @@ -320,7 +321,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url _tree->resetEditStats(); resetSendingStats(); showStats = true; - } else if ((url.path() == persistFile) || (url.path() == persistFile + "/")) { + } else if ((url.path() == PERSIST_FILE_DOWNLOAD_PATH) || (url.path() == PERSIST_FILE_DOWNLOAD_PATH + "/")) { if (_persistFileDownload) { QByteArray persistFileContents = getPersistFileContents(); if (persistFileContents.length() > 0) { @@ -374,9 +375,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url statsString += "\r\n"; if (_persistFileDownload) { - statsString += QString("Persist file: %1\r\n").arg(persistFile); + statsString += QString("Persist file: Click to Download\r\n").arg(PERSIST_FILE_DOWNLOAD_PATH); } else { - statsString += QString("Persist file: %1\r\n").arg(persistFile); + statsString += QString("Persist file: %1\r\n").arg(_persistFilePath); } } else {