diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index d874100ca2..46ca51219d 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -157,11 +157,6 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis ++simpleReceivedIt; } - if (bytesWritten > 0 && sendingAvatar->isCertifyFailed()) { - // Resend identity packet if certification failed: - sendingAvatar->setNeedsIdentityUpdate(); - } - // enumerate the received instanced trait versions auto instancedReceivedIt = lastReceivedVersions.instancedCBegin(); while (instancedReceivedIt != lastReceivedVersions.instancedCEnd()) { diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 071ea4a079..c0c92d65d7 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -4250,6 +4250,19 @@ }, "id": "LANDRUN", "type": "clip" + }, + { + "children": [ + ], + "data": { + "endFrame": 105, + "loopFlag": false, + "startFrame": 100, + "timeScale": 1, + "url": "qrc:///avatar/animations/idle.fbx" + }, + "id": "seatedToIdle", + "type": "clip" } ], "data": { @@ -4267,60 +4280,8 @@ "interpType": "evaluateBoth", "transitions": [ { - "state": "idle", - "var": "isNotMoving" - }, - { - "state": "WALKFWD", - "var": "isMovingForward" - }, - { - "state": "WALKBWD", - "var": "isMovingBackward" - }, - { - "state": "STRAFERIGHT", - "var": "isMovingRight" - }, - { - "state": "STRAFELEFT", - "var": "isMovingLeft" - }, - { - "state": "turnRight", - "var": "isTurningRight" - }, - { - "state": "turnLeft", - "var": "isTurningLeft" - }, - { - "state": "fly", - "var": "isFlying" - }, - { - "state": "takeoffStand", - "var": "isTakeoffStand" - }, - { - "state": "TAKEOFFRUN", - "var": "isTakeoffRun" - }, - { - "state": "inAirStand", - "var": "isInAirStand" - }, - { - "state": "INAIRRUN", - "var": "isInAirRun" - }, - { - "state": "strafeRightHmd", - "var": "isMovingRightHmd" - }, - { - "state": "strafeLeftHmd", - "var": "isMovingLeftHmd" + "state": "seatedToIdle", + "var": "isNotSeated" } ] }, @@ -5210,6 +5171,18 @@ "var": "landRunOnDone" } ] + }, + { + "id": "seatedToIdle", + "interpDuration": 10, + "interpTarget": 1, + "interpType": "snapshotPrev", + "transitions": [ + { + "state": "idle", + "var": "seatedToIdleOnDone" + } + ] } ] }, diff --git a/interface/resources/qml/hifi/simplifiedUI/helpApp/HelpApp.qml b/interface/resources/qml/hifi/simplifiedUI/helpApp/HelpApp.qml index d8238d35cf..0ebbe49963 100644 --- a/interface/resources/qml/hifi/simplifiedUI/helpApp/HelpApp.qml +++ b/interface/resources/qml/hifi/simplifiedUI/helpApp/HelpApp.qml @@ -16,6 +16,7 @@ import stylesUit 1.0 as HifiStylesUit import "./controls" as HelpControls import "./faq" as HelpFAQ import "./about" as HelpAbout +import "./support" as HelpSupport Rectangle { property string activeTabView: "controlsTabView" @@ -59,6 +60,10 @@ Rectangle { tabTitle: "Controls" tabViewName: "controlsTabView" } + ListElement { + tabTitle: "Support" + tabViewName: "supportTabView" + } ListElement { tabTitle: "FAQ" tabViewName: "faqTabView" @@ -139,6 +144,12 @@ Rectangle { anchors.fill: parent } + HelpSupport.HelpSupport { + id: supportTabViewContainer + visible: activeTabView === "supportTabView" + anchors.fill: parent + } + HelpFAQ.HelpFAQ { id: faqTabViewContainer visible: activeTabView === "faqTabView" @@ -159,6 +170,8 @@ Rectangle { parent: { if (activeTabView === "controlsTabView") { controlsTabViewContainer + } else if (activeTabView === "supportTabView") { + supportTabViewContainer } else if (activeTabView === "faqTabView") { faqTabViewContainer } else if (activeTabView === "aboutTabView") { diff --git a/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/HelpControls.qml b/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/HelpControls.qml index 01c5187aa5..b4f7bd76c0 100644 --- a/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/HelpControls.qml +++ b/interface/resources/qml/hifi/simplifiedUI/helpApp/controls/HelpControls.qml @@ -88,7 +88,7 @@ Flickable { temporaryText: "Viewing!" onClicked: { - Qt.openUrlExternally("http://docs.highfidelity.com/explore/get-started/desktop.html"); + Qt.openUrlExternally("https://www.highfidelity.com/knowledge/get-around"); } } } diff --git a/interface/resources/qml/hifi/simplifiedUI/helpApp/support/HelpSupport.qml b/interface/resources/qml/hifi/simplifiedUI/helpApp/support/HelpSupport.qml new file mode 100644 index 0000000000..31b9593f09 --- /dev/null +++ b/interface/resources/qml/hifi/simplifiedUI/helpApp/support/HelpSupport.qml @@ -0,0 +1,85 @@ +// +// HelpSupport.qml +// +// Created by Zach Fox on 2019-08-20 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import "../../simplifiedConstants" as SimplifiedConstants +import "../../simplifiedControls" as SimplifiedControls +import stylesUit 1.0 as HifiStylesUit +import QtQuick.Layouts 1.3 + +Item { + id: root + width: parent.width + height: parent.height + + + SimplifiedConstants.SimplifiedConstants { + id: simplifiedUI + } + + + Image { + id: accent + source: "../images/accent2.svg" + anchors.left: parent.left + anchors.top: parent.top + width: 83 + height: 156 + transform: Scale { + xScale: -1 + origin.x: accent.width / 2 + origin.y: accent.height / 2 + } + } + + + ColumnLayout { + anchors.left: parent.left + anchors.leftMargin: 26 + anchors.right: parent.right + anchors.rightMargin: 26 + anchors.top: parent.top + spacing: 0 + + HifiStylesUit.GraphikSemiBold { + text: "Support" + Layout.preferredWidth: parent.width + Layout.preferredHeight: paintedHeight + Layout.topMargin: 16 + size: 22 + color: simplifiedUI.colors.text.white + } + + HifiStylesUit.GraphikRegular { + text: "You can quickly get the support that you need by clicking the button below." + Layout.preferredWidth: parent.width + Layout.preferredHeight: paintedHeight + Layout.topMargin: 8 + size: 18 + wrapMode: Text.Wrap + color: simplifiedUI.colors.text.white + } + + SimplifiedControls.Button { + Layout.topMargin: 8 + width: 200 + height: 32 + text: "CONTACT SUPPORT" + temporaryText: "Opening browser..." + + onClicked: { + Qt.openUrlExternally("https://www.highfidelity.com/knowledge/kb-tickets/new"); + } + } + } + + signal sendToScript(var message); +} diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/SettingsApp.qml b/interface/resources/qml/hifi/simplifiedUI/settingsApp/SettingsApp.qml index ecc8bac2a7..c9857afcec 100644 --- a/interface/resources/qml/hifi/simplifiedUI/settingsApp/SettingsApp.qml +++ b/interface/resources/qml/hifi/simplifiedUI/settingsApp/SettingsApp.qml @@ -17,8 +17,6 @@ import "./audio" as AudioSettings import "./general" as GeneralSettings import "./vr" as VrSettings import "./dev" as DevSettings -import "./about" as AboutSettings - Rectangle { property string activeTabView: "generalTabView" id: root @@ -86,10 +84,6 @@ Rectangle { tabTitle: "VR" tabViewName: "vrTabView" } - ListElement { - tabTitle: "About" - tabViewName: "aboutTabView" - } ListElement { tabTitle: "Dev" tabViewName: "devTabView" @@ -190,12 +184,6 @@ Rectangle { anchors.fill: parent } - AboutSettings.About { - id: aboutTabViewContainer - visible: activeTabView === "aboutTabView" - anchors.fill: parent - } - SimplifiedControls.VerticalScrollBar { parent: { if (activeTabView === "generalTabView") { @@ -206,8 +194,6 @@ Rectangle { vrTabViewContainer } else if (activeTabView === "devTabView") { devTabViewContainer - } else if (activeTabView === "aboutTabView") { - aboutTabViewContainer } } } diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml b/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml deleted file mode 100644 index 89cccb8ecd..0000000000 --- a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/About.qml +++ /dev/null @@ -1,332 +0,0 @@ -// -// About.qml -// -// Created by Zach Fox on 2019-06-18 -// Copyright 2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.10 -import QtQuick.Controls 2.3 -import "../../simplifiedConstants" as SimplifiedConstants -import "../../simplifiedControls" as SimplifiedControls -import stylesUit 1.0 as HifiStylesUit -import QtQuick.Layouts 1.3 - -Flickable { - id: root - contentWidth: parent.width - contentHeight: aboutColumnLayout.height - clip: true - - onVisibleChanged: { - if (visible) { - root.contentX = 0; - root.contentY = 0; - - // When the user clicks the About tab, refresh the audio I/O model so that - // the delegate Component.onCompleted handlers fire, which will update - // the text that appears in the About screen. - audioOutputDevices.model = undefined; - audioOutputDevices.model = AudioScriptingInterface.devices.output; - audioInputDevices.model = undefined; - audioInputDevices.model = AudioScriptingInterface.devices.input; - } - } - - - SimplifiedConstants.SimplifiedConstants { - id: simplifiedUI - } - - - ColumnLayout { - id: aboutColumnLayout - anchors.left: parent.left - anchors.leftMargin: 26 - anchors.right: parent.right - anchors.rightMargin: 26 - anchors.top: parent.top - spacing: 0 - - Image { - source: "images/logo.png" - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 16 - Layout.preferredWidth: 160 - Layout.preferredHeight: 120 - fillMode: Image.PreserveAspectFit - mipmap: true - } - - ColumnLayout { - id: platformInfoContainer - Layout.preferredWidth: parent.width - Layout.bottomMargin: 24 - spacing: 0 - - HifiStylesUit.GraphikSemiBold { - text: "Version " + Window.checkVersion() - Layout.alignment: Qt.AlignHCenter - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikSemiBold { - text: "Platform Info" - Layout.preferredWidth: parent.width - Layout.topMargin: 8 - Layout.bottomMargin: 8 - height: paintedHeight - size: 22 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikRegular { - text: "Computer Vendor/Model:" - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - - Component.onCompleted: { - var computer = JSON.parse(PlatformInfo.getComputer()); - var computerVendor = computer.vendor; - if (computerVendor.length === 0) { - computerVendor = "Unknown"; - } - var computerModel = computer.model; - if (computerModel.length === 0) { - computerModel = "Unknown"; - } - - text = "Computer Vendor/Model: " + computerVendor + "/" + computerModel; - } - } - - HifiStylesUit.GraphikRegular { - text: "Profiled Platform Tier: " + PlatformInfo.getTierProfiled() - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikRegular { - text: "OS Type: " + PlatformInfo.getOperatingSystemType() - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikRegular { - text: "CPU:" - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - - Component.onCompleted: { - var cpu = JSON.parse(PlatformInfo.getCPU(0)); - var cpuModel = cpu.model; - if (cpuModel.length === 0) { - cpuModel = "Unknown"; - } - - text = "CPU: " + cpuModel; - } - } - - HifiStylesUit.GraphikRegular { - text: "# CPUs: " + PlatformInfo.getNumCPUs() - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikRegular { - text: "# CPU Cores: " + PlatformInfo.getNumLogicalCores() - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikRegular { - text: "RAM: " + PlatformInfo.getTotalSystemMemoryMB() + " MB" - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - HifiStylesUit.GraphikRegular { - text: "GPU: " - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - - Component.onCompleted: { - var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU())); - var gpuModel = gpu.model; - if (gpuModel.length === 0) { - gpuModel = "Unknown"; - } - - text = "GPU: " + gpuModel; - } - } - - HifiStylesUit.GraphikRegular { - text: "VR Hand Controllers: " + (PlatformInfo.hasRiftControllers() ? "Rift" : (PlatformInfo.hasViveControllers() ? "Vive" : "None")) - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - // This is a bit of a hack to get the name of the currently-selected audio input device - // in the current mode (Desktop or VR). The reason this is necessary is because it seems to me like - // the only way one can get a human-readable list of the audio I/O devices is by using a ListView - // and grabbing the names from the AudioScriptingInterface; you can't do it using a ListModel. - // See `AudioDevices.h`, specifically the comment above the declaration of `QVariant data()`. - ListView { - id: audioInputDevices - visible: false - property string selectedInputDeviceName - Layout.preferredWidth: parent.width - Layout.preferredHeight: contentItem.height - interactive: false - delegate: Item { - Component.onCompleted: { - if (HMD.active && selectedHMD) { - audioInputDevices.selectedInputDeviceName = model.devicename - } else if (!HMD.active && selectedDesktop) { - audioInputDevices.selectedInputDeviceName = model.devicename - } - } - } - } - - HifiStylesUit.GraphikRegular { - text: "Audio Input: " + audioInputDevices.selectedInputDeviceName - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - - // This is a bit of a hack to get the name of the currently-selected audio output device - // in the current mode (Desktop or VR). The reason this is necessary is because it seems to me like - // the only way one can get a human-readable list of the audio I/O devices is by using a ListView - // and grabbing the names from the AudioScriptingInterface; you can't do it using a ListModel. - // See `AudioDevices.h`, specifically the comment above the declaration of `QVariant data()`. - ListView { - id: audioOutputDevices - visible: false - property string selectedOutputDeviceName - Layout.preferredWidth: parent.width - Layout.preferredHeight: contentItem.height - interactive: false - delegate: Item { - Component.onCompleted: { - if (HMD.active && selectedHMD) { - audioOutputDevices.selectedOutputDeviceName = model.devicename - } else if (!HMD.active && selectedDesktop) { - audioOutputDevices.selectedOutputDeviceName = model.devicename - } - } - } - } - - HifiStylesUit.GraphikRegular { - text: "Audio Output: " + audioOutputDevices.selectedOutputDeviceName - Layout.preferredWidth: parent.width - height: paintedHeight - size: 16 - color: simplifiedUI.colors.text.white - wrapMode: Text.Wrap - } - - SimplifiedControls.Button { - Layout.topMargin: 8 - width: 200 - height: 32 - text: "Copy to Clipboard" - temporaryText: "Copied!" - - onClicked: { - Window.copyToClipboard(root.buildPlatformInfoTextToCopy()); - showTemporaryText(); - } - } - } - } - - function buildPlatformInfoTextToCopy() { - var textToCopy = "**About Interface**\n"; - textToCopy += "Interface Version: " + Window.checkVersion() + "\n"; - textToCopy += "\n**Platform Info**\n"; - - var computer = JSON.parse(PlatformInfo.getComputer()); - var computerVendor = computer.vendor; - if (computerVendor.length === 0) { - computerVendor = "Unknown"; - } - var computerModel = computer.model; - if (computerModel.length === 0) { - computerModel = "Unknown"; - } - - textToCopy += "Computer Vendor/Model: " + computerVendor + "/" + computerModel + "\n"; - textToCopy += "Profiled Platform Tier: " + PlatformInfo.getTierProfiled() + "\n"; - textToCopy += "OS Type: " + PlatformInfo.getOperatingSystemType() + "\n"; - - var cpu = JSON.parse(PlatformInfo.getCPU(0)); - var cpuModel = cpu.model; - if (cpuModel.length === 0) { - cpuModel = "Unknown"; - } - - textToCopy += "CPU: " + cpuModel + "\n"; - textToCopy += "# CPUs: " + PlatformInfo.getNumCPUs() + "\n"; - textToCopy += "# CPU Cores: " + PlatformInfo.getNumLogicalCores() + "\n"; - textToCopy += "RAM: " + PlatformInfo.getTotalSystemMemoryMB() + " MB\n"; - - var gpu = JSON.parse(PlatformInfo.getGPU(PlatformInfo.getMasterGPU())); - var gpuModel = gpu.model; - if (gpuModel.length === 0) { - gpuModel = "Unknown"; - } - - textToCopy += "GPU: " + gpuModel + "\n"; - textToCopy += "VR Hand Controllers: " + (PlatformInfo.hasRiftControllers() ? "Rift" : (PlatformInfo.hasViveControllers() ? "Vive" : "None")) + "\n"; - textToCopy += "Audio Input: " + audioInputDevices.selectedInputDeviceName + "\n"; - textToCopy += "Audio Output: " + audioOutputDevices.selectedOutputDeviceName + "\n"; - - textToCopy += "\n**All Platform Info**\n"; - textToCopy += JSON.stringify(JSON.parse(PlatformInfo.getPlatform()), null, 4); - - return textToCopy; - } -} diff --git a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/images/logo.png b/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/images/logo.png deleted file mode 100644 index d480da86dd..0000000000 Binary files a/interface/resources/qml/hifi/simplifiedUI/settingsApp/about/images/logo.png and /dev/null differ diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 1342e55b5d..fdb05c8a35 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -225,10 +225,6 @@ StackView { verticalCenter: addressLineContainer.verticalCenter; } - onFocusChanged: { - addressBarDialog.raised = focus; - } - onTextChanged: { updateLocationText(text.length > 0); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1803b5e19f..2a310df7f5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4235,12 +4235,43 @@ bool Application::event(QEvent* event) { } bool Application::eventFilter(QObject* object, QEvent* event) { + auto eventType = event->type(); - if (_aboutToQuit && event->type() != QEvent::DeferredDelete && event->type() != QEvent::Destroy) { + if (_aboutToQuit && eventType != QEvent::DeferredDelete && eventType != QEvent::Destroy) { return true; } - auto eventType = event->type(); +#if defined(Q_OS_MAC) + // On Mac OS, Cmd+LeftClick is treated as a RightClick (more specifically, it seems to + // be Cmd+RightClick without the modifier being dropped). Starting in Qt 5.12, only + // on Mac, the MouseButtonRelease event for these mouse presses is sent to the top + // level QWidgetWindow, but are not propagated further. This means that the Application + // will see a MouseButtonPress, but no MouseButtonRelease, causing the client to get + // stuck in "mouse-look." The cause of the problem is in the way QWidgetWindow processes + // events where QMouseEvent::button() is not equal to QMouseEvent::buttons(). In this case + // QMouseEvent::button() is Qt::RightButton, while QMouseEvent::buttons() is (correctly?) + // Qt::LeftButton. + // + // The change here gets around this problem by capturing these + // pseudo-RightClicks, and re-emitting them as "pure" RightClicks, where + // QMouseEvent::button() == QMouseEvent::buttons() == Qt::RightButton. + // + if (eventType == QEvent::MouseButtonPress) { + auto mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::RightButton + && mouseEvent->buttons() == Qt::LeftButton + && mouseEvent->modifiers() == Qt::MetaModifier) { + + QMouseEvent* newEvent = new QMouseEvent( + QEvent::MouseButtonPress, mouseEvent->localPos(), mouseEvent->windowPos(), + mouseEvent->screenPos(), Qt::RightButton, Qt::MouseButtons(Qt::RightButton), + mouseEvent->modifiers()); + QApplication::postEvent(object, newEvent); + return true; + } + } +#endif + if (eventType == QEvent::KeyPress || eventType == QEvent::KeyRelease || eventType == QEvent::MouseMove) { getRefreshRateManager().resetInactiveTimer(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 28f6644d7f..0ff2e055b7 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -6245,31 +6245,43 @@ void MyAvatar::setSitDriveKeysStatus(bool enabled) { } void MyAvatar::beginSit(const glm::vec3& position, const glm::quat& rotation) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "beginSit", Q_ARG(glm::vec3, position), Q_ARG(glm::quat, rotation)); + return; + } + _characterController.setSeated(true); - setCollisionsEnabled(false); + setCollisionsEnabled(false); setHMDLeanRecenterEnabled(false); // Disable movement setSitDriveKeysStatus(false); centerBody(); int hipIndex = getJointIndex("Hips"); clearPinOnJoint(hipIndex); - goToLocation(position, true, rotation, false, false); pinJoint(hipIndex, position, rotation); } void MyAvatar::endSit(const glm::vec3& position, const glm::quat& rotation) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "endSit", Q_ARG(glm::vec3, position), Q_ARG(glm::quat, rotation)); + return; + } + if (_characterController.getSeated()) { clearPinOnJoint(getJointIndex("Hips")); _characterController.setSeated(false); setCollisionsEnabled(true); setHMDLeanRecenterEnabled(true); centerBody(); - goToLocation(position, true, rotation, false, false); + slamPosition(position); + setWorldOrientation(rotation); + + // the jump key is used to exit the chair. We add a delay here to prevent + // the avatar from jumping right as they exit the chair. float TIME_BEFORE_DRIVE_ENABLED_MS = 150.0f; QTimer::singleShot(TIME_BEFORE_DRIVE_ENABLED_MS, [this]() { // Enable movement again setSitDriveKeysStatus(true); }); } - -} \ No newline at end of file +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ad45df892b..bb6f036533 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1866,6 +1866,9 @@ public: // also clears internal reaction triggers void updateRigControllerParameters(Rig::ControllerParameters& params); + // Don't substitute verify-fail: + virtual const QUrl& getSkeletonModelURL() const override { return _skeletonModelURL; } + public slots: /**jsdoc diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 5af7a357b0..c449874117 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -830,9 +830,14 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack } void Wallet::sendChallengeOwnershipResponses() { - if (_pendingChallenges.size() == 0 || getSalt().length() == 0) { + if (_pendingChallenges.size() == 0) { return; } + if (getSalt().length() == 0) { + qCDebug(commerce) << "Not responding to ownership challenge due to missing Wallet salt"; + return; + } + auto nodeList = DependencyManager::get(); EC_KEY* ec = readKeys(keyFilePath()); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index d0204219ac..211c54def8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1144,6 +1144,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER; } + // Skip hysterisis timer for sit transitions. + if (_desiredState == RigRole::Seated || _state == RigRole::Seated) { + _desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER; + } + if ((_desiredStateAge >= STATE_CHANGE_HYSTERESIS_TIMER) && _desiredState != _state) { _state = _desiredState; _desiredStateAge = 0.0f; @@ -1223,6 +1228,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isInAirRun", false); _animVars.set("isNotInAir", true); _animVars.set("isSeated", false); + _animVars.set("isNotSeated", true); } else if (_state == RigRole::Turn) { if (turningSpeed > 0.0f) { @@ -1252,6 +1258,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isInAirRun", false); _animVars.set("isNotInAir", true); _animVars.set("isSeated", false); + _animVars.set("isNotSeated", true); } else if (_state == RigRole::Idle) { // default anim vars to notMoving and notTurning @@ -1274,6 +1281,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isInAirRun", false); _animVars.set("isNotInAir", true); _animVars.set("isSeated", false); + _animVars.set("isNotSeated", true); } else if (_state == RigRole::Hover) { // flying. @@ -1296,6 +1304,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isInAirRun", false); _animVars.set("isNotInAir", true); _animVars.set("isSeated", false); + _animVars.set("isNotSeated", true); } else if (_state == RigRole::Takeoff) { // jumping in-air @@ -1326,6 +1335,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isInAirRun", false); _animVars.set("isNotInAir", false); _animVars.set("isSeated", false); + _animVars.set("isNotSeated", true); } else if (_state == RigRole::InAir) { // jumping in-air @@ -1345,6 +1355,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isTakeoffRun", false); _animVars.set("isNotTakeoff", true); _animVars.set("isSeated", false); + _animVars.set("isNotSeated", true); bool inAirRun = forwardSpeed > 0.1f; if (inAirRun) { @@ -1386,6 +1397,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos _animVars.set("isInAirRun", false); _animVars.set("isNotInAir", true); _animVars.set("isSeated", true); + _animVars.set("isNotSeated", false); } t += deltaTime; @@ -1821,8 +1833,10 @@ void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabl int hipsIndex = indexOfJoint("Hips"); const float KNEE_POLE_VECTOR_BLEND_FACTOR = 0.85f; - if (headEnabled) { - // always do IK if head is enabled + bool isSeated = _state == RigRole::Seated; + + if (headEnabled && !isSeated) { + // enable leg IK if head is enabled and we arent sitting down. _animVars.set("leftFootIKEnabled", true); _animVars.set("rightFootIKEnabled", true); } else { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index a7e4a0ae9f..7f363dd36f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -131,7 +131,7 @@ AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& av } else { _lastPosition = avatarPosition; _status = Status::ABORT_TRANSIT; - } + } } _lastPosition = avatarPosition; _status = updatePosition(deltaTime); @@ -143,11 +143,18 @@ AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& av return _status; } +void AvatarTransit::slamPosition(const glm::vec3& avatarPosition) { + // used to instantly teleport between two points without triggering a change in status. + _lastPosition = avatarPosition; + _endPosition = avatarPosition; +} + void AvatarTransit::reset() { _lastPosition = _endPosition; _currentPosition = _endPosition; _isActive = false; } + void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) { _startPosition = startPosition; _endPosition = endPosition; @@ -192,8 +199,8 @@ AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) { status = Status::PRE_TRANSIT; if (_currentTime == 0) { status = Status::STARTED; - } - } else if (nextTime < _totalTime - _postTransitTime){ + } + } else if (nextTime < _totalTime - _postTransitTime) { status = Status::TRANSITING; if (_currentTime <= _preTransitTime) { status = Status::START_TRANSIT; @@ -519,10 +526,10 @@ void Avatar::relayJointDataToChildren() { * * "avatar" or ""The rate at which the avatar is updated even if not in view. * "avatarInView"The rate at which the avatar is updated if in view. - * "skeletonModel"The rate at which the skeleton model is being updated, even if there are no + * "skeletonModel"The rate at which the skeleton model is being updated, even if there are no * joint data available. * "jointData"The rate at which joint data are being updated. - * ""When no rate name is specified, the "avatar" update rate is + * ""When no rate name is specified, the "avatar" update rate is * provided. * * @@ -557,6 +564,7 @@ void Avatar::slamPosition(const glm::vec3& newPosition) { _positionDeltaAccumulator = glm::vec3(0.0f); setWorldVelocity(glm::vec3(0.0f)); _lastVelocity = glm::vec3(0.0f); + _transit.slamPosition(newPosition); } void Avatar::updateAttitude(const glm::quat& orientation) { @@ -1511,7 +1519,7 @@ void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { } indicateLoadingStatus(LoadingStatus::LoadModel); - _skeletonModel->setURL(_skeletonModelURL); + _skeletonModel->setURL(getSkeletonModelURL()); } void Avatar::setModelURLFinished(bool success) { @@ -1533,7 +1541,7 @@ void Avatar::setModelURLFinished(bool success) { QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); } else { - qCWarning(avatars_renderer) << "Avatar model failed to load... attempts:" + qCWarning(avatars_renderer) << "Avatar model failed to load... attempts:" << _skeletonModel->getResourceDownloadAttempts() << "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS; } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index ee0fb6f433..7bb15ecbf7 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -93,6 +93,7 @@ public: AvatarTransit() {}; Status update(float deltaTime, const glm::vec3& avatarPosition, const TransitConfig& config); + void slamPosition(const glm::vec3& avatarPosition); Status getStatus() { return _status; } bool isActive() { return _isActive; } glm::vec3 getCurrentPosition() { return _currentPosition; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7d5f38db40..c03f9430be 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1988,7 +1988,11 @@ void AvatarData::processAvatarIdentity(QDataStream& packetStream, bool& identity if (flagValue != _verificationFailed) { _verificationFailed = flagValue; identityChanged = true; - } + setSkeletonModelURL(_skeletonModelURL); + if (_verificationFailed) { + qCDebug(avatars) << "Avatar" << getSessionDisplayName() << "marked as VERIFY-FAILED"; + } + }; if (identity.attachmentData != _attachmentData) { setAttachmentData(identity.attachmentData); @@ -2016,6 +2020,18 @@ QUrl AvatarData::getWireSafeSkeletonModelURL() const { return QUrl(); } } + +static const QString VERIFY_FAIL_MODEL { "/meshes/verifyFailed.fst" }; + +const QUrl& AvatarData::getSkeletonModelURL() const { + if (_verificationFailed) { + static QUrl VERIFY_FAIL_MODEL_URL = PathUtils::resourcesUrl(VERIFY_FAIL_MODEL); + return VERIFY_FAIL_MODEL_URL; + } else { + return _skeletonModelURL; + } +} + QByteArray AvatarData::packSkeletonData() const { // Send an avatar trait packet with the skeleton data before the mesh is loaded int avatarDataSize = 0; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 20c5b1900d..59a2e2a53e 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1205,7 +1205,7 @@ public: QByteArray identityByteArray(bool setIsReplicated = false) const; QUrl getWireSafeSkeletonModelURL() const; - const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } + virtual const QUrl& getSkeletonModelURL() const; const QString& getDisplayName() const { return _displayName; } const QString& getSessionDisplayName() const { return _sessionDisplayName; } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 0c7054424f..d0b315b524 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -330,10 +330,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer bool displayNameChanged = false; // In this case, the "sendingNode" is the Avatar Mixer. avatar->processAvatarIdentity(avatarIdentityStream, identityChanged, displayNameChanged); - if (avatar->isCertifyFailed() && identityUUID != EMPTY) { - qCDebug(avatars) << "Avatar" << avatar->getSessionDisplayName() << "marked as VERIFY-FAILED"; - avatar->setSkeletonModelURL(PathUtils::resourcesUrl(VERIFY_FAIL_MODEL)); - } _replicas.processAvatarIdentity(identityUUID, message->getMessage(), identityChanged, displayNameChanged); } } diff --git a/tools/jsdoc/hifi-jsdoc-template/tmpl/container.tmpl b/tools/jsdoc/hifi-jsdoc-template/tmpl/container.tmpl index 3796bab632..451ed4d01a 100644 --- a/tools/jsdoc/hifi-jsdoc-template/tmpl/container.tmpl +++ b/tools/jsdoc/hifi-jsdoc-template/tmpl/container.tmpl @@ -239,7 +239,7 @@ - + + } ?> + +
Type: + @@ -63,7 +66,7 @@ var self = this; - +
Type: