diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index acd9be0702..7a7210a0e8 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -116,8 +116,9 @@ public: void setLastOtherAvatarEncodeTime(const QUuid& otherAvatar, const uint64_t& time); QVector& getLastOtherAvatarSentJoints(QUuid otherAvatar) { - _lastOtherAvatarSentJoints[otherAvatar].resize(_avatar->getJointCount()); - return _lastOtherAvatarSentJoints[otherAvatar]; + auto& lastOtherAvatarSentJoints = _lastOtherAvatarSentJoints[otherAvatar]; + lastOtherAvatarSentJoints.resize(_avatar->getJointCount()); + return lastOtherAvatarSentJoints; } void queuePacket(QSharedPointer message, SharedNodePointer node); diff --git a/interface/resources/meshes/tablet-with-home-button.fbx b/interface/resources/meshes/tablet-with-home-button.fbx index 70b8008bad..37247022f6 100644 Binary files a/interface/resources/meshes/tablet-with-home-button.fbx and b/interface/resources/meshes/tablet-with-home-button.fbx differ diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 3f5cad655d..e08fdc53ff 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -50,7 +50,7 @@ Item { id: avatarImage visible: profileUrl !== "" && userName !== ""; // Size - height: isMyCard ? 70 : 42; + height: isMyCard ? 84 : 42; width: visible ? height : 0; anchors.top: parent.top; anchors.topMargin: isMyCard ? 0 : 8; @@ -520,7 +520,7 @@ Item { Slider { id: gainSlider // Size - width: thisNameCard.width; + width: isMyCard ? thisNameCard.width - 20 : thisNameCard.width; height: 14 // Anchors anchors.verticalCenter: nameCardVUMeter.verticalCenter; diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 64f61f0d69..02971cc984 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -28,7 +28,7 @@ Rectangle { // Properties property bool debug: false; property int myCardWidth: width - upperRightInfoContainer.width; - property int myCardHeight: 80; + property int myCardHeight: 100; property int rowHeight: 60; property int actionButtonWidth: 55; property int locationColumnWidth: 170; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 449b014c13..cc4e951235 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7398,11 +7398,13 @@ void Application::updateThreadPoolCount() const { } void Application::updateSystemTabletMode() { - qApp->setProperty(hifi::properties::HMD, isHMDMode()); - if (isHMDMode()) { - DependencyManager::get()->setToolbarMode(getHmdTabletBecomesToolbarSetting()); - } else { - DependencyManager::get()->setToolbarMode(getDesktopTabletBecomesToolbarSetting()); + if (_settingsLoaded) { + qApp->setProperty(hifi::properties::HMD, isHMDMode()); + if (isHMDMode()) { + DependencyManager::get()->setToolbarMode(getHmdTabletBecomesToolbarSetting()); + } else { + DependencyManager::get()->setToolbarMode(getDesktopTabletBecomesToolbarSetting()); + } } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f2053e29d7..94df5bf7f4 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -530,9 +530,13 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent destinationBuffer += numValidityBytes; // Move pointer past the validity bytes + // sentJointDataOut and lastSentJointData might be the same vector + // build sentJointDataOut locally and then swap it at the end. + QVector localSentJointDataOut; if (sentJointDataOut) { - sentJointDataOut->resize(_jointData.size()); // Make sure the destination is resized before using it + localSentJointDataOut.resize(numJoints); // Make sure the destination is resized before using it } + float minRotationDOT = !distanceAdjust ? AVATAR_MIN_ROTATION_DOT : getDistanceBasedMinRotationDOT(viewerPosition); for (int i = 0; i < _jointData.size(); i++) { @@ -552,8 +556,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation); if (sentJointDataOut) { - auto jointDataOut = *sentJointDataOut; - jointDataOut[i].rotation = data.rotation; + localSentJointDataOut[i].rotation = data.rotation; } } @@ -602,8 +605,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); if (sentJointDataOut) { - auto jointDataOut = *sentJointDataOut; - jointDataOut[i].translation = data.translation; + localSentJointDataOut[i].translation = data.translation; } } @@ -646,6 +648,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent if (outboundDataRateOut) { outboundDataRateOut->jointDataRate.increment(numBytes); } + + if (sentJointDataOut) { + // Push new sent joint data to sentJointDataOut + sentJointDataOut->swap(localSentJointDataOut); + } } int avatarDataSize = destinationBuffer - startPosition; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 3e6d19f430..46c1c9a4c7 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -267,9 +267,9 @@ void ModelEntityItem::updateFrameCount() { if (!getAnimationHold() && getAnimationIsPlaying()) { float deltaTime = (float)interval / (float)USECS_PER_SECOND; _currentFrame += (deltaTime * getAnimationFPS()); - if (_currentFrame > getAnimationLastFrame()) { - if (getAnimationLoop()) { - _currentFrame = getAnimationFirstFrame() + (int)(glm::floor(_currentFrame - getAnimationFirstFrame())) % (updatedFrameCount - 1); + if (_currentFrame > getAnimationLastFrame() + 1) { + if (getAnimationLoop() && getAnimationFirstFrame() != getAnimationLastFrame()) { + _currentFrame = getAnimationFirstFrame() + (int)(_currentFrame - getAnimationFirstFrame()) % updatedFrameCount; } else { _currentFrame = getAnimationLastFrame(); } diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 2f3d896509..7302e0e997 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -31,6 +31,32 @@ const QString INDEX_PATH = "/"; const QString GET_PLACE = "/api/v1/places/%1"; +/**jsdoc + * The location API provides facilities related to your current location in the metaverse. + * + * @namespace location + * @property {Uuid} domainId - A UUID uniquely identifying the domain you're visiting. Is {@link Uuid|Uuid.NULL} if you're not + * connected to the domain. + * Read-only. + * @property {string} hostname - The name of the domain for your current metaverse address (e.g., "AvatarIsland", + * localhost, or an IP address). + * Read-only. + * @property {string} href - Your current metaverse address (e.g., "hifi://avatarisland/15,-10,26/0,0,0,1") + * regardless of whether or not you're connected to the domain. + * Read-only. + * @property {boolean} isConnected - true if you're connected to the domain in your current href + * metaverse address, otherwise false. + * Read-only. + * @property {string} pathname - The location and orientation in your current href metaverse address + * (e.g., "/15,-10,26/0,0,0,1"). + * Read-only. + * @property {string} placename - The place name in your current href metaverse address + * (e.g., "AvatarIsland"). Is blank if your hostname is an IP address. + * Read-only. + * @property {string} protocol - The protocol of your current href metaverse address (e.g., "hifi"). + * Read-only. + */ + class AddressManager : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -42,10 +68,77 @@ class AddressManager : public QObject, public Dependency { Q_PROPERTY(QString placename READ getPlaceName) Q_PROPERTY(QString domainId READ getDomainId) public: + + /**jsdoc + * Get Interface's protocol version. + * @function location.protocolVersion + * @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using. + */ Q_INVOKABLE QString protocolVersion(); + using PositionGetter = std::function; using OrientationGetter = std::function; + /**jsdoc + *

The reasons for an address lookup via the metaverse API are defined by numeric values:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NameValueDescription
UserInput0User-typed input.
Back1Address from a {@link location.goBack|goBack} call.
Forward2Address from a {@link location.goForward|goForward} call.
StartupFromSettings3Initial location at Interface start-up from settings.
DomainPathResponse4A named path in the domain.
Internal5An internal attempt to resolve an alternative path.
AttemptedRefresh6A refresh after connecting to a domain.
Suggestions7Address from the Goto dialog.
VisitUserFromPAL8User from the People dialog.
+ * @typedef location.LookupTrigger + */ enum LookupTrigger { UserInput, Back, @@ -83,43 +176,240 @@ public: const QStack& getForwardStack() const { return _forwardStack; } public slots: + /**jsdoc + * Go to a specified metaverse address. + * @function location.handleLookupString + * @param {string} address - The address to go to: a "hifi:/" address, an IP address (e.g., + * "127.0.0.1" or "localhost"), a domain name, a named path on a domain (starts with + * "/"), a position or position and orientation, or a user (starts with "@"). + * @param {boolean} fromSuggestions=false - Set to true if the address is obtained from the "Goto" dialog. + * Helps ensure that user's location history is correctly maintained. + */ void handleLookupString(const QString& lookupString, bool fromSuggestions = false); - + + /**jsdoc + * Go to a position and orientation resulting from a lookup for a named path in the domain (set in the domain server's + * settings). + * @function location.goToViewpointForPath + * @param {string} path - The position and orientation corresponding to the named path. + * @param {string} namedPath - The named path that was looked up on the server. + * @deprecated This function is deprecated and will be removed. + */ + // This function is marked as deprecated in anticipation that it will not be included in the JavaScript API if and when the + // functions and signals that should be exposed are moved to a scripting interface class. + // // we currently expect this to be called from NodeList once handleLookupString has been called with a path bool goToViewpointForPath(const QString& viewpointString, const QString& pathString) { return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString); } + /**jsdoc + * Go back to the previous location in your navigation history, if there is one. + * @function location.goBack + */ void goBack(); + + /**jsdoc + * Go forward to the next location in your navigation history, if there is one. + * @function location.goForward + */ void goForward(); + + /**jsdoc + * Go to the local Sandbox server that's running on the same PC as Interface. + * @function location.goToLocalSandbox + * @param {string} path="" - The position and orientation to go to (e.g., "/0,0,0"). + * @param {location.LookupTrigger} trigger=StartupFromSettings - The reason for the function call. Helps ensure that user's + * location history is correctly maintained. + */ void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger); } + + /**jsdoc + * Go to the default "welcome" metaverse address. + * @function location.goToEntry + * @param {location.LookupTrigger} trigger=StartupFromSettings - The reason for the function call. Helps ensure that user's + * location history is correctly maintained. + */ void goToEntry(LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(DEFAULT_HIFI_ADDRESS, trigger); } + /**jsdoc + * Go to the specified user's location. + * @function location.goToUser + * @param {string} username - The user's username. + * @param {boolean} matchOrientation=true - If true then go to a location just in front of the user and turn to face + * them, otherwise go to the user's exact location and orientation. + */ void goToUser(const QString& username, bool shouldMatchOrientation = true); + /**jsdoc + * Refresh the current address, e.g., after connecting to a domain in order to position the user to the desired location. + * @function location.refreshPreviousLookup + * @deprecated This function is deprecated and will be removed. + */ + // This function is marked as deprecated in anticipation that it will not be included in the JavaScript API if and when the + // functions and signals that should be exposed are moved to a scripting interface class. void refreshPreviousLookup(); + /**jsdoc + * Update your current metaverse location in Interface's {@link Settings} file as your last-known address. This can be used + * to ensure that you start up at that address if you exit Interface without a later address automatically being saved. + * @function location.storeCurrentAddress + */ void storeCurrentAddress(); + /**jsdoc + * Copy your current metaverse address (i.e., location.href property value) to the OS clipboard. + * @function location.copyAddress + */ void copyAddress(); + + /**jsdoc + * Copy your current metaverse location and orientation (i.e., location.pathname property value) to the OS + * clipboard. + * @function location.copyPath + */ void copyPath(); + /**jsdoc + * Retrieve and remember the place name for the given domain ID if the place name is not already known. + * @function location.lookupShareableNameForDomainID + * @param {Uuid} domainID - The UUID of the domain. + * @deprecated This function is deprecated and will be removed. + */ + // This function is marked as deprecated in anticipation that it will not be included in the JavaScript API if and when the + // functions and signals that should be exposed are moved to a scripting interface class. void lookupShareableNameForDomainID(const QUuid& domainID); signals: + /**jsdoc + * Triggered when looking up the details of a metaverse user or location to go to has completed (successfully or + * unsuccessfully). + * @function location.lookupResultsFinished + * @returns {Signal} + */ void lookupResultsFinished(); + + /**jsdoc + * Triggered when looking up the details of a metaverse user or location to go to has completed and the domain or user is + * offline. + * @function location.lookupResultIsOffline + * @returns {Signal} + */ void lookupResultIsOffline(); + + /**jsdoc + * Triggered when looking up the details of a metaverse user or location to go to has completed and the domain or user could + * not be found. + * @function location.lookupResultIsNotFound + * @returns {Signal} + */ void lookupResultIsNotFound(); + /**jsdoc + * Triggered when a request is made to go to an IP address. + * @function location.possibleDomainChangeRequired + * @param {string} hostName - The name of the domain to go do. + * @param {number} port - The integer number of the network port to connect to. + * @param {Uuid} domainID - The UUID of the domain to go to. + * @returns {Signal} + */ + // No example because this function isn't typically used in scripts. void possibleDomainChangeRequired(const QString& newHostname, quint16 newPort, const QUuid& domainID); + + /**jsdoc + * Triggered when a request is made to go to a named domain or user. + * @function location.possibleDomainChangeRequiredViaICEForID + * @param {string} iceServerHostName - IP address of the ICE server. + * @param {Uuid} domainID - The UUID of the domain to go to. + * @returns {Signal} + */ + // No example because this function isn't typically used in scripts. void possibleDomainChangeRequiredViaICEForID(const QString& iceServerHostname, const QUuid& domainID); + /**jsdoc + * Triggered when an attempt is made to send your avatar to a specified position on the current domain. For example, when + * you change domains or enter a position to go to in the "Goto" dialog. + * @function location.locationChangeRequired + * @param {Vec3} position - The position to go to. + * @param {boolean} hasOrientationChange - If true then a new orientation has been requested. + * @param {Quat} orientation - The orientation to change to. Is {@link Quat(0)|Quat.IDENTITY} if + * hasOrientationChange is false. + * @param {boolean} shouldFaceLocation - If true then the request is to go to a position near that specified + * and orient your avatar to face it. For example when you visit someone from the "People" dialog. + * @returns {Signal} + * @example Report location change requests. + * function onLocationChangeRequired(newPosition, hasOrientationChange, newOrientation, shouldFaceLocation) { + * print("Location change required:"); + * print("- New position = " + JSON.stringify(newPosition)); + * print("- Has orientation change = " + hasOrientationChange); + * print("- New orientation = " + JSON.stringify(newOrientation)); + * print("- Should face location = " + shouldFaceLocation); + * } + * + * location.locationChangeRequired.connect(onLocationChangeRequired); + */ void locationChangeRequired(const glm::vec3& newPosition, bool hasOrientationChange, const glm::quat& newOrientation, bool shouldFaceLocation); + + /**jsdoc + * Triggered when an attempt is made to send your avatar to a new named path on the domain (set in the domain server's + * settings). For example, when you enter a "/" followed by the path's name in the "GOTO" dialog. + * @function location.pathChangeRequired + * @param {string} path - The name of the path to go to. + * @returns {Signal} + * @example Report path change requests. + * function onPathChangeRequired(newPath) { + * print("onPathChangeRequired: newPath = " + newPath); + * } + * + * location.pathChangeRequired.connect(onPathChangeRequired); + */ void pathChangeRequired(const QString& newPath); + + /**jsdoc + * Triggered when you navigate to a new domain. + * @function location.hostChanged + * @param {string} hostname - The new domain's host name. + * @returns {Signal} + * @example Report when you navigate to a new domain. + * function onHostChanged(host) { + * print("Host changed to: " + host); + * } + * + * location.hostChanged.connect(onHostChanged); + */ void hostChanged(const QString& newHost); + /**jsdoc + * Triggered when there's a change in whether or not there's a previous location that can be navigated to using + * {@link location.goBack|goBack}. (Reflects changes in the state of the "Goto" dialog's back arrow.) + * @function location.goBackPossible + * @param {boolean} isPossible - true if there's a previous location to navigate to, otherwise + * false. + * @returns {Signal} + * @example Report when ability to navigate back changes. + * function onGoBackPossible(isPossible) { + * print("Go back possible: " + isPossible); + * } + * + * location.goBackPossible.connect(onGoBackPossible); + */ void goBackPossible(bool isPossible); + + /**jsdoc + * Triggered when there's a change in whether or not there's a forward location that can be navigated to using + * {@link location.goForward|goForward}. (Reflects changes in the state of the "Goto" dialog's forward arrow.) + * @function location.goForwardPossible + * @param {boolean} isPossible - true if there's a forward location to navigate to, otherwise + * false. + * @returns {Signal} + * @example Report when ability to navigate forward changes. + * function onGoForwardPossible(isPossible) { + * print("Go forward possible: " + isPossible); + * } + * + * location.goForwardPossible.connect(onGoForwardPossible); + */ void goForwardPossible(bool isPossible); protected: diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 5a72006a8c..1c18125433 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -437,7 +437,7 @@ void NodeList::sendPendingDSPathQuery() { QString pendingPath = _domainHandler.getPendingPath(); if (!pendingPath.isEmpty()) { - qCDebug(networking) << "Attemping to send pending query to DS for path" << pendingPath; + qCDebug(networking) << "Attempting to send pending query to DS for path" << pendingPath; // this is a slot triggered if we just established a network link with a DS and want to send a path query sendDSPathQuery(_domainHandler.getPendingPath()); diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 7f2cbe0aee..16f1d086b7 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -148,8 +148,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.setIgnorePointerItems = function() { if (HMD.tabletID !== this.tabletID) { this.tabletID = HMD.tabletID; - Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist.concat([HMD.tabletID])); - Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist.concat([HMD.tabletID])); + Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist); + Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist); } }; @@ -378,8 +378,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.setBlacklist = function() { - RayPick.setIgnoreItems(_this.leftControllerRayPick, this.blacklist.concat([HMD.tabletID])); - RayPick.setIgnoreItems(_this.rightControllerRayPick, this.blacklist.concat([HMD.tabletID])); + RayPick.setIgnoreItems(_this.leftControllerRayPick, this.blacklist); + RayPick.setIgnoreItems(_this.rightControllerRayPick, this.blacklist); }; var MAPPING_NAME = "com.highfidelity.controllerDispatcher"; diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index a6e2751a83..bc83cc582c 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -400,7 +400,7 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) }); // update webOverlay - var RAYPICK_OFFSET = 0.0001; // Sufficient for raypick to reliably intersect tablet screen before tablet model. + var RAYPICK_OFFSET = 0.0007; // Sufficient for raypick to reliably intersect tablet screen before tablet model. var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2.0) * sensorScaleOffsetOverride + RAYPICK_OFFSET; var WEB_ENTITY_Y_OFFSET = 0.004 * sensorScaleFactor * sensorScaleOffsetOverride; var screenWidth = 0.82 * tabletWidth;