From 117e302b2af7400b5694bb3fd7898ad2d08d1ab6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 12 Jan 2017 15:40:37 -0800 Subject: [PATCH 01/27] First pass --- interface/resources/qml/hifi/NameCard.qml | 72 ++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index c6daf53b9a..c1b93b92ca 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -55,12 +55,82 @@ Item { width: parent.width - /*avatarImage.width - parent.spacing - */parent.anchors.leftMargin - parent.anchors.rightMargin height: childrenRect.height anchors.verticalCenter: parent.verticalCenter - // DisplayName Text + + // DisplayName field for my card + Rectangle { + id: myDisplayName + visible: isMyCard + color: "#C5C5C5" + anchors.left: parent.left + anchors.leftMargin: -10 + width: parent.width + 70 + height: 35 + TextInput { + id: myDisplayNameText + // Properties + text: thisNameCard.displayName + autoScroll: false + maximumLength: 64 + width: parent.width + height: parent.height + wrapMode: TextInput.Wrap + // Anchors + anchors.fill: parent + anchors.leftMargin: 10 + // Text Positioning + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + // Style + color: hifi.colors.darkGray + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pointSize: thisNameCard.displayTextHeight + // Signals + onEditingFinished: { + console.log("New displayName: ", text) + } + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + hoverEnabled: true + propagateComposedEvents: true + onClicked: { + myDisplayNameText.selectAll(); + myDisplayNameText.focus = true; + } + onEntered: myDisplayName.color = hifi.colors.lightGrayText + onExited: myDisplayName.color = "#C5C5C5" + } + // Edit pencil glyph + HiFiGlyphs { + text: hifi.glyphs.edit + // Size + size: thisNameCard.displayTextHeight + // Anchors + anchors.right: parent.right + anchors.rightMargin: size/2 + anchors.verticalCenter: parent.verticalCenter + // Style + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: hifi.colors.baseGray + } + } + // Spacer for DisplayName for my card + Rectangle { + width: myDisplayName.width + height: 5 + visible: isMyCard + opacity: 0 + } + // DisplayName Text for others' cards FiraSansSemiBold { id: displayNameText // Properties text: thisNameCard.displayName elide: Text.ElideRight + visible: !isMyCard // Size width: parent.width // Anchors From 6e4a4da92ab2ec2920ac135493d935b73d62f5f3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 12 Jan 2017 16:40:47 -0800 Subject: [PATCH 02/27] Checkpoint --- interface/resources/qml/hifi/NameCard.qml | 18 ++++++++++-------- scripts/system/pal.js | 6 ++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index c1b93b92ca..906e81a08d 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -69,17 +69,15 @@ Item { id: myDisplayNameText // Properties text: thisNameCard.displayName - autoScroll: false maximumLength: 64 - width: parent.width - height: parent.height - wrapMode: TextInput.Wrap + clip: true // Anchors anchors.fill: parent anchors.leftMargin: 10 + anchors.rightMargin: editGlyph.implicitWidth + editGlyph.anchors.rightMargin // Text Positioning - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignLeft + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignLeft // Style color: hifi.colors.darkGray FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } @@ -87,15 +85,18 @@ Item { font.pointSize: thisNameCard.displayTextHeight // Signals onEditingFinished: { - console.log("New displayName: ", text) + pal.sendToScript({method: 'displayNameUpdate', params: text}) } } MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton hoverEnabled: true - propagateComposedEvents: true onClicked: { + myDisplayNameText.focus ? myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX, mouseY, TextInput.CursorOnCharacter) : myDisplayNameText.selectAll(); + myDisplayNameText.focus = true; + } + onDoubleClicked: { myDisplayNameText.selectAll(); myDisplayNameText.focus = true; } @@ -104,6 +105,7 @@ Item { } // Edit pencil glyph HiFiGlyphs { + id: editGlyph text: hifi.glyphs.edit // Size size: thisNameCard.displayTextHeight diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 6b3fd00c3b..c6ac1056de 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -237,6 +237,12 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like data = message.params; Users.setAvatarGain(data['sessionId'], data['gain']); break; + case 'displayNameUpdate': + if (MyAvatar.displayName != message.params) { + MyAvatar.displayName = message.params; + } + break; + default: default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } From 2f176f50fae4ff06d9ab2e92b92acdf81b63e38c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 13 Jan 2017 12:56:59 -0800 Subject: [PATCH 03/27] Another checkpoint --- interface/resources/fonts/hifi-glyphs.ttf | Bin 24580 -> 24772 bytes interface/resources/qml/hifi/NameCard.qml | 13 +++++++++---- interface/resources/qml/hifi/Pal.qml | 13 +++++++++++-- .../qml/styles-uit/HifiConstants.qml | 3 ++- libraries/avatars/src/AvatarData.cpp | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 09aefffdfef007aa94f3cbdfd02a61612c0ee9e7..c139a196d0f70536b980d7cbbad81c416d237e0b 100644 GIT binary patch delta 684 zcmX|;O-Phs5Xb-XywCf*>%Q(6$S&oZx@9eHv}!B62_*z(6xCL4;;xpy=;jLh1+Jh( z>Y;-|hw`~Z*sVi>V9P>>2uv~|=n@!tkdO}2rArZH1jc^Qz|8y(GsFC6?!BS)HJSwh zuwf1guJ-gqFHcTK2Z7;d0F3k9=X$UN0SwOrXo~cQqI-(GC(KMSZ&foL?DFh{Mi9}57s0fdst#H`8NXa}G=0L{sC ze(Jz(-5NkI0PLo+Bj%l^hur{Q2e6Yir*il}w*Wd-S}0?t6W_wG`heJPfQq^7MBZ}$ z>nbp?4DgR-aRiK-7nX+{r+-0bDB0$dt&K`%TN{gXhO)AYZjwzd(Oz({T%rJFH_9_W z%}~l@fRm*p4i;2~&Ft9ZI{QhP;!DLr@-6?&{QlySTIiisFo+nf&y? zVy4k%5F@MqxvQY7cFh^-AZZBA>D4M7hyAs@)MEA3Qw?Wa+-3QK`kR zDeVZ#SUkYmgK|DTDgVa3l$8ww+l*4hKLhU+yPg;w&!5O8G9%+DK&}ooP)2?ks@MPj HXlvsiT0xGP delta 494 zcmX|+Pe>GT6vsbrW_Gp4>>>-+5?hq(sSUw@UQl~C_V^eb z5-UJuYW%_I)Aqmn;9G#$Qab63obA}G1$Kd^bUK-Hj2p5CQUhE~yVJ9^&udmemVlq* z6T{BKQ0f90%fNTnna%Q520>c9hcb?v91A~s5B*Uulbx8F{?oob3GpK^J{IK!=6Zj0 zCeF7VU}|`^t*m@$YF7S*+?0&EB?D5W7UVF3Cs6EQF^^n9FH#Ug{GJ$D=U6E9HrGeVw}Msz}qtW z2(VRVKLP%$+x9h8i1$dNs<5w1qiVKi)Ehe_8MSHe7GB@~tgGD6C2`f_&_(mq(#oFz Dg()->killNodeWithUUID(getSessionUUID()); qCDebug(avatars) << "Changing display name for avatar to" << displayName; } From 32e330320e0e50d84d8d7bb1a03d0831732fcb17 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 11:26:57 -0800 Subject: [PATCH 04/27] Cleanup after rebase --- interface/resources/qml/hifi/NameCard.qml | 17 ++++++++++++----- interface/resources/qml/hifi/Pal.qml | 8 -------- libraries/avatars/src/AvatarData.cpp | 2 +- scripts/system/pal.js | 1 - 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 250dad7f7f..b389891255 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -60,11 +60,15 @@ Item { Rectangle { id: myDisplayName visible: isMyCard - color: "#C5C5C5" - anchors.left: parent.left - anchors.leftMargin: -10 + // Size width: parent.width + 70 height: 35 + // Anchors + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: -10 + // Style + color: "#C5C5C5" border.color: hifi.colors.blueHighlight border.width: 0 TextInput { @@ -126,7 +130,10 @@ Item { } // Spacer for DisplayName for my card Rectangle { + id: myDisplayNameSpacer width: myDisplayName.width + // Anchors + anchors.top: myDisplayName.bottom height: 5 visible: isMyCard opacity: 0 @@ -160,7 +167,7 @@ Item { // Size width: parent.width // Anchors - anchors.top: displayNameText.bottom + anchors.top: isMyCard ? myDisplayNameSpacer.bottom : displayNameText.bottom // Text Size size: thisNameCard.usernameTextHeight // Text Positioning @@ -182,7 +189,7 @@ Item { Rectangle { id: nameCardVUMeter // Size - width: ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width + width: isMyCard ? gainSlider.width : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width height: 8 // Anchors anchors.top: spacer.bottom diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 8fa8fe8514..68ad3f811c 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -346,11 +346,6 @@ Rectangle { visible: iAmAdmin color: hifi.colors.lightGrayText } - function letterbox(message) { - letterboxMessage.text = message; - letterboxMessage.visible = true - - } // This Rectangle refers to the [?] popup button next to "NAMES" Rectangle { color: hifi.colors.tableBackgroundLight @@ -411,9 +406,6 @@ Rectangle { onExited: adminHelpText.color = hifi.colors.redHighlight } } - LetterboxMessage { - id: letterboxMessage - } } function findSessionIndex(sessionId, optionalData) { // no findIndex in .qml diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0381363ef3..0350e73d2e 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1094,7 +1094,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; - DependencyManager::get()->killNodeWithUUID(getSessionUUID()); + DependencyManager::get()->getDomainHandler().softReset(); qCDebug(avatars) << "Changing display name for avatar to" << displayName; } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index c6ac1056de..6fd386b00f 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -242,7 +242,6 @@ pal.fromQml.connect(function (message) { // messages are {method, params}, like MyAvatar.displayName = message.params; } break; - default: default: print('Unrecognized message from Pal.qml:', JSON.stringify(message)); } From 3b56f46206a3267c8016c9959c90958f343f5fb3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 13:18:24 -0800 Subject: [PATCH 05/27] Style changes --- interface/resources/qml/hifi/NameCard.qml | 34 ++++++++++++++--------- libraries/avatars/src/AvatarData.cpp | 3 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b389891255..367ef3b25b 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -28,7 +28,7 @@ Item { property string uuid: "" property string displayName: "" property string userName: "" - property int displayTextHeight: 18 + property real displayNameTextPixelSize: 18 property int usernameTextHeight: 12 property real audioLevel: 0.0 property bool isMyCard: false @@ -68,7 +68,7 @@ Item { anchors.left: parent.left anchors.leftMargin: -10 // Style - color: "#C5C5C5" + color: hifi.colors.textFieldLightBackground border.color: hifi.colors.blueHighlight border.width: 0 TextInput { @@ -77,23 +77,30 @@ Item { text: thisNameCard.displayName maximumLength: 64 clip: true + // Size + width: parent.width + height: parent.height // Anchors - anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left anchors.leftMargin: 10 anchors.rightMargin: editGlyph.implicitWidth + editGlyph.anchors.rightMargin - // Text Positioning - verticalAlignment: TextInput.AlignVCenter - horizontalAlignment: TextInput.AlignLeft // Style color: hifi.colors.darkGray FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } font.family: firaSansSemiBold.name - font.pointSize: thisNameCard.displayTextHeight + font.pixelSize: displayNameTextPixelSize + selectionColor: hifi.colors.blueHighlight + selectedTextColor: "black" + // Text Positioning + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignLeft // Signals onEditingFinished: { pal.sendToScript({method: 'displayNameUpdate', params: text}) focus = false myDisplayName.border.width = 0 + color = hifi.colors.darkGray } } MouseArea { @@ -101,23 +108,24 @@ Item { acceptedButtons: Qt.LeftButton hoverEnabled: true onClicked: { - myDisplayName.border.width = 3 + myDisplayName.border.width = 1 myDisplayNameText.focus ? myDisplayNameText.cursorPosition = myDisplayNameText.positionAt(mouseX, mouseY, TextInput.CursorOnCharacter) : myDisplayNameText.selectAll(); myDisplayNameText.focus = true + myDisplayNameText.color = "black" } onDoubleClicked: { myDisplayNameText.selectAll(); myDisplayNameText.focus = true; } onEntered: myDisplayName.color = hifi.colors.lightGrayText - onExited: myDisplayName.color = "#C5C5C5" + onExited: myDisplayName.color = hifi.colors.textFieldLightBackground } // Edit pencil glyph HiFiGlyphs { id: editGlyph text: hifi.glyphs.editPencil - // Size - size: thisNameCard.displayTextHeight*1.5 + // Text Size + size: displayNameTextPixelSize*1.5 // Anchors anchors.right: parent.right anchors.rightMargin: 5 @@ -150,7 +158,7 @@ Item { // Anchors anchors.top: parent.top // Text Size - size: thisNameCard.displayTextHeight + size: displayNameTextPixelSize // Text Positioning verticalAlignment: Text.AlignVCenter // Style @@ -189,7 +197,7 @@ Item { Rectangle { id: nameCardVUMeter // Size - width: isMyCard ? gainSlider.width : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width + width: isMyCard ? myDisplayName.width - 20 : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * parent.width height: 8 // Anchors anchors.top: spacer.bottom diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0350e73d2e..3d09be0679 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1047,7 +1047,7 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) { } if (identity.displayName != _displayName) { - setDisplayName(identity.displayName); + _displayName = identity.displayName; hasIdentityChanged = true; } maybeUpdateSessionDisplayNameFromTransport(identity.sessionDisplayName); @@ -1094,6 +1094,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; + DependencyManager::get()->getDomainHandler().softReset(); qCDebug(avatars) << "Changing display name for avatar to" << displayName; From e98a40c30e287897fddef8be2fe20f256f7a8485 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 14:43:30 -0800 Subject: [PATCH 06/27] Does this work? --- assignment-client/src/avatars/AvatarMixer.cpp | 12 +++++++++--- .../src/avatars/AvatarMixerClientData.h | 6 +++--- libraries/avatars/src/AvatarData.cpp | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 11cbd73970..8ac2f3922b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -262,8 +262,13 @@ void AvatarMixer::broadcastAvatarData() { // setup a PacketList for the avatarPackets auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); - if (avatar.getSessionDisplayName().isEmpty() && // We haven't set it yet... - nodeData->getReceivedIdentity()) { // ... but we have processed identity (with possible displayName). + if (nodeData->getAvatarSessionDisplayNameMustChange()) { // ... but we have processed identity (with possible displayName). + const QString& existingBaseDisplayName = nodeData->getBaseDisplayName(); + // No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case. + if (--_sessionDisplayNames[existingBaseDisplayName].second <= 0) { + _sessionDisplayNames.remove(existingBaseDisplayName); + } + QString baseName = avatar.getDisplayName().trimmed(); const QRegularExpression curses{ "fuck|shit|damn|cock|cunt" }; // POC. We may eventually want something much more elaborate (subscription?). baseName = baseName.replace(curses, "*"); // Replace rather than remove, so that people have a clue that the person's a jerk. @@ -280,6 +285,7 @@ void AvatarMixer::broadcastAvatarData() { highWater++; soFar.second++; // refcount nodeData->flagIdentityChange(); + nodeData->setAvatarSessionDisplayNameMustChange(false); sendIdentityPacket(nodeData, node); // Tell new node about its sessionUUID. Others will find out below. } @@ -584,7 +590,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes if (avatar.processAvatarIdentity(identity)) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->flagIdentityChange(); - nodeData->setReceivedIdentity(); + nodeData->setAvatarSessionDisplayNameMustChange(); } } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index f18cfdde1b..38db2e74d2 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -53,8 +53,8 @@ public: HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; } void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); } - bool getReceivedIdentity() const { return _gotIdentity; } - void setReceivedIdentity() { _gotIdentity = true; } + bool getAvatarSessionDisplayNameMustChange() const { return _avatarSessionDisplayNameMustChange; } + void setAvatarSessionDisplayNameMustChange(bool set = true) { _avatarSessionDisplayNameMustChange = set; } void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; } float getFullRateDistance() const { return _fullRateDistance; } @@ -112,7 +112,7 @@ private: std::unordered_set _hasReceivedFirstPacketsFrom; HRCTime _identityChangeTimestamp; - bool _gotIdentity { false }; + bool _avatarSessionDisplayNameMustChange{ false }; float _fullRateDistance = FLT_MAX; float _maxAvatarDistance = FLT_MAX; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3d09be0679..1fb68fce14 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1094,8 +1094,9 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { void AvatarData::setDisplayName(const QString& displayName) { _displayName = displayName; + _sessionDisplayName = ""; - DependencyManager::get()->getDomainHandler().softReset(); + sendIdentityPacket(); qCDebug(avatars) << "Changing display name for avatar to" << displayName; } From e72c25736e804bbd625c5855b6d85e7b15086eff Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 15:21:18 -0800 Subject: [PATCH 07/27] Cleanup --- assignment-client/src/avatars/AvatarMixer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 8ac2f3922b..4127719b7b 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -262,9 +262,8 @@ void AvatarMixer::broadcastAvatarData() { // setup a PacketList for the avatarPackets auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); - if (nodeData->getAvatarSessionDisplayNameMustChange()) { // ... but we have processed identity (with possible displayName). + if (nodeData->getAvatarSessionDisplayNameMustChange()) { const QString& existingBaseDisplayName = nodeData->getBaseDisplayName(); - // No sense guarding against very rare case of a node with no entry, as this will work without the guard and do one less lookup in the common case. if (--_sessionDisplayNames[existingBaseDisplayName].second <= 0) { _sessionDisplayNames.remove(existingBaseDisplayName); } @@ -286,7 +285,7 @@ void AvatarMixer::broadcastAvatarData() { soFar.second++; // refcount nodeData->flagIdentityChange(); nodeData->setAvatarSessionDisplayNameMustChange(false); - sendIdentityPacket(nodeData, node); // Tell new node about its sessionUUID. Others will find out below. + sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name. Others will find out below. } // this is an AGENT we have received head data from @@ -590,7 +589,7 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes if (avatar.processAvatarIdentity(identity)) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->flagIdentityChange(); - nodeData->setAvatarSessionDisplayNameMustChange(); + nodeData->setAvatarSessionDisplayNameMustChange(true); } } } From 1e8effdcc42d85b6326b0c4d240088e23b36cee1 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 16 Jan 2017 15:28:53 -0800 Subject: [PATCH 08/27] Packet verison bump --- libraries/networking/src/udt/PacketHeaders.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c012ed8f67..9bbd139138 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -211,7 +211,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { HandControllerJoints, HasKillAvatarReason, SessionDisplayName, - Unignore + Unignore, + ImmediateSessionDisplayNameUpdates }; enum class DomainConnectRequestVersion : PacketVersion { From c9fd650e70939bfe62fea6323f16d986519d999c Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 16 Jan 2017 19:37:31 -0500 Subject: [PATCH 09/27] update to support click/far-click toggling and userData.disabled setting --- .../tutorials/entity_scripts/ambientSound.js | 330 +++++++++++++++--- 1 file changed, 282 insertions(+), 48 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 620b371400..64adcf379a 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -1,55 +1,70 @@ // ambientSound.js // // This entity script will allow you to create an ambient sound that loops when a person is within a given -// range of this entity. Great way to add one or more ambisonic soundfields to your environment. +// range of this entity. Great way to add one or more ambisonic soundfields to your environment. // -// In the userData section for the entity, add/edit three values: -// userData.soundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. +// In the userData section for the entity, add/edit three values: +// userData.soundURL should be a string giving the URL to the sound file. Defaults to 100 meters if not set. // userData.range should be an integer for the max distance away from the entity where the sound will be audible. -// userData.volume is the max volume at which the clip should play. Defaults to 1.0 full volume) +// userData.maxVolume is the max volume at which the clip should play. Defaults to 1.0 full volume. +// userData.disabled is an optionanl boolean flag which can be used to disable the ambient sound. Defaults to false. +// +// The rotation of the entity is copied to the ambisonic field, so by rotating the entity you will rotate the +// direction in-which a certain sound comes from. // -// The rotation of the entity is copied to the ambisonic field, so by rotating the entity you will rotate the -// direction in-which a certain sound comes from. -// // Remember that the entity has to be visible to the user for the sound to play at all, so make sure the entity is -// large enough to be loaded at the range you set, particularly for large ranges. -// +// large enough to be loaded at the range you set, particularly for large ranges. +// // Copyright 2016 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 // -(function(){ +(function(){ + var VERSION = "0.0.1"; // This sample clip and range will be used if you don't add userData to the entity (see above) var DEFAULT_RANGE = 100; var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; var soundURL = ""; + var soundName = ""; + var startTime; + var soundOptions = { + loop: true, + localOnly: true, + //ignorePenumbra: true, + }; var range = DEFAULT_RANGE; var maxVolume = DEFAULT_VOLUME; + var disabled = false; var UPDATE_INTERVAL_MSECS = 100; var rotation; var entity; var ambientSound; var center; - var soundPlaying = false; + var soundPlaying; var checkTimer = false; var _this; - var WANT_COLOR_CHANGE = false; var COLOR_OFF = { red: 128, green: 128, blue: 128 }; var COLOR_ON = { red: 255, green: 0, blue: 0 }; - var WANT_DEBUG = false; + var WANT_DEBUG = true; function debugPrint(string) { if (WANT_DEBUG) { - print(string); + print("ambientSound | " + string); } } + var WANT_DEBUG_BROADCASTS = "ambientSound.js"; + var WANT_DEBUG_OVERLAY = false; + var LINEHEIGHT = 0.1; + // Optionally enable debug overlays using a Settings value + WANT_DEBUG_OVERLAY = WANT_DEBUG_OVERLAY || /ambientSound/.test(Settings.getValue("WANT_DEBUG_OVERLAY")); + this.updateSettings = function() { // Check user data on the entity for any changes var oldSoundURL = soundURL; @@ -58,81 +73,300 @@ var data = JSON.parse(props.userData); if (data.soundURL && !(soundURL === data.soundURL)) { soundURL = data.soundURL; - debugPrint("Read ambient sound URL: " + soundURL); - } else if (!data.soundURL) { - soundURL = DEFAULT_URL; + soundName = (soundURL||"").split("/").pop(); // just filename part + debugPrint("Read ambient sound URL: " + soundURL); } if (data.range && !(range === data.range)) { range = data.range; debugPrint("Read ambient sound range: " + range); } - if (data.volume && !(maxVolume === data.volume)) { - maxVolume = data.volume; + // Check known aliases for the "volume" setting (which allows for inplace upgrade of existing marketplace entities) + data.maxVolume = data.maxVolume || data.soundVolume || data.volume; + if (data.maxVolume && !(maxVolume === data.maxVolume)) { + maxVolume = data.maxVolume; debugPrint("Read ambient sound volume: " + maxVolume); } + if ("disabled" in data && !(disabled === data.disabled)) { + disabled = data.disabled; + debugPrint("Read ambient disabled state: " + disabled); + if (disabled) { + this.cleanup(); + debugState("disabled"); + return; + } + } + /*if ("loop" in data && !(soundOptions.loop === data.loop)) { + soundOptions.loop = data.loop; + debugPrint("Read ambient loop state: " + soundOptions.loop); + }*/ } if (!(soundURL === oldSoundURL) || (soundURL === "")) { - debugPrint("Loading ambient sound into cache"); - ambientSound = SoundCache.getSound(soundURL); + if (soundURL) { + debugState("downloading", "Loading ambient sound into cache"); + // Use prefetch to detect URL loading errors + var resource = SoundCache.prefetch(soundURL); + function onStateChanged() { + if (resource.state === Resource.State.FINISHED) { + resource.stateChanged.disconnect(onStateChanged); + ambientSound = SoundCache.getSound(soundURL); + debugState("idle"); + } else if (resource.state === Resource.State.FAILED) { + resource.stateChanged.disconnect(onStateChanged); + debugPrint("Failed to download ambient sound: " + soundURL); + debugState("error"); + } + debugPrint("onStateChanged: " + JSON.stringify({ + sound: soundName, + state: resource.state, + stateName: Object.keys(Resource.State).filter(function(key) { + return Resource.State[key] === resource.state; + }) + })); + } + resource.stateChanged.connect(onStateChanged); + onStateChanged(resource.state); + } if (soundPlaying && soundPlaying.playing) { + debugPrint("URL changed, stopping current ambient sound"); soundPlaying.stop(); soundPlaying = false; - if (WANT_COLOR_CHANGE) { - Entities.editEntity(entity, { color: COLOR_OFF }); - } - debugPrint("Restarting ambient sound"); } - } + } } - this.preload = function(entityID) { + this.clickDownOnEntity = function(entityID, mouseEvent) { + print("click"); + if (mouseEvent.isPrimaryButton) { + this._toggle("primary click"); + } + }; + + this.startFarTrigger = function() { + this._toggle("far click"); + }; + + this._toggle = function(hint) { + // Toggle between ON/OFF state, but only if not in edit mode + if (Settings.getValue("io.highfidelity.isEditting")) { + return; + } + var props = Entities.getEntityProperties(entity, [ "userData", "age", "scriptTimestamp" ]); + var data = JSON.parse(props.userData); + data.disabled = !data.disabled; + + debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundName + ")"); + var oldState = _debugState; + + if (WANT_DEBUG_BROADCASTS) { + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); + } + + this.cleanup(); + + // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change + Entities.editEntity(entity, { + userData: JSON.stringify(data), + scriptTimestamp: Math.round(props.age * 1000) + }); + //this._updateColor(data.disabled); + }; + + this._updateColor = function(disabled) { + // Update Shape or Text Entity color based on ON/OFF status + var props = Entities.getEntityProperties(entity, [ "color", "textColor" ]); + var targetColor = disabled ? COLOR_OFF : COLOR_ON; + var currentColor = props.textColor || props.color; + var newProps = props.textColor ? { textColor: targetColor } : { color: targetColor }; + + if (currentColor.red !== targetColor.red || + currentColor.green !== targetColor.green || + currentColor.blue !== targetColor.blue) { + Entities.editEntity(entity, newProps); + } + }; + + this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. - debugPrint("Ambient sound preload"); + debugPrint("Ambient sound preload " + VERSION); entity = entityID; _this = this; - checkTimer = Script.setInterval(this.maybeUpdate, UPDATE_INTERVAL_MSECS); - }; + + if (WANT_DEBUG_OVERLAY) { + _createDebugOverlays(); + } + + var props = Entities.getEntityProperties(entity, [ "userData" ]); + if (props.userData) { + var data = JSON.parse(props.userData); + this._updateColor(data.disabled); + if (data.disabled) { + _this.maybeUpdate(); + return; + } + } + + checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + }; this.maybeUpdate = function() { // Every UPDATE_INTERVAL_MSECS, update the volume of the ambient sound based on distance from my avatar _this.updateSettings(); var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]); + if (!props.position) { + // FIXME: this mysterious state has been happening while testing + // and might indicate a bug where an Entity can become unreachable without `unload` having been called.. + print("FIXME: ambientSound.js -- expected Entity unavailable!") + if (WANT_DEBUG_BROADCASTS) { + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); + } + return _this.cleanup(); + } center = props.position; rotation = props.rotation; var distance = Vec3.length(Vec3.subtract(MyAvatar.position, center)); if (distance <= range) { var volume = (1.0 - distance / range) * maxVolume; - if (!soundPlaying && ambientSound.downloaded) { - soundPlaying = Audio.playSound(ambientSound, { loop: true, - localOnly: true, - orientation: rotation, - volume: volume }); - debugPrint("Starting ambient sound, volume: " + volume); - if (WANT_COLOR_CHANGE) { - Entities.editEntity(entity, { color: COLOR_ON }); - } - + soundOptions.orientation = Quat.rotation; + soundOptions.volume = volume; + if (!soundPlaying && ambientSound && ambientSound.downloaded) { + debugState("playing", "Starting ambient sound: " + soundName + " (duration: " + ambientSound.duration + ")"); + soundPlaying = Audio.playSound(ambientSound, soundOptions); } else if (soundPlaying && soundPlaying.playing) { - soundPlaying.setOptions( { volume: volume, orientation: rotation } ); + soundPlaying.setOptions(soundOptions); } - } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { soundPlaying.stop(); soundPlaying = false; - Entities.editEntity(entity, { color: { red: 128, green: 128, blue: 128 }}); - debugPrint("Out of range, stopping ambient sound"); + debugState("idle", "Out of range, stopping ambient sound: " + soundName); + } + if (WANT_DEBUG_OVERLAY) { + updateDebugOverlay(distance); } } - this.unload = function(entityID) { - debugPrint("Ambient sound unload"); + this.unload = function(entityID) { + debugPrint("Ambient sound unload "); + if (WANT_DEBUG_BROADCASTS) { + var offset = ambientSound && (new Date - startTime)/1000 % ambientSound.duration; + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); + } + if (WANT_DEBUG_OVERLAY) { + _removeDebugOverlays(); + } + this.cleanup(); + }; + + this.cleanup = function() { if (checkTimer) { Script.clearInterval(checkTimer); + checkTimer = false; } if (soundPlaying && soundPlaying.playing) { soundPlaying.stop(); + soundPlaying = false; } - }; + }; -}) + // Visual debugging overlay (to see set WANT_DEBUG_OVERLAY = true) + + var DEBUG_COLORS = { + //preload: { red: 0, green: 80, blue: 80 }, + disabled: { red: 0, green: 0, blue: 0, alpha: 0.0 }, + downloading: { red: 255, green: 255, blue: 0 }, + error: { red: 255, green: 0, blue: 0 }, + playing: { red: 0, green: 200, blue: 0 }, + idle: { red: 0, green: 100, blue: 0 } + }; + var _debugOverlay; + var _debugState = ""; + function debugState(state, message) { + if (state === "playing") { + startTime = new Date; + } + _debugState = state; + if (message) { + debugPrint(message); + } + updateDebugOverlay(); + if (WANT_DEBUG_BROADCASTS) { + // Broadcast state changes to an implicit entity channel, making multi-user scenarios easier to verify from a single console + Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); + } + } + + function updateDebugOverlay(distance) { + var props = Entities.getEntityProperties(entity, [ "name", "dimensions" ]); + if (!props.dimensions) { + return print("ambientSound.js: updateDebugOverlay -- entity no longer available " + entity); + } + var options = soundPlaying && soundPlaying.options; + if (options) { + var offset = soundPlaying.playing && ambientSound && (new Date - startTime)/1000 % ambientSound.duration; + var deg = Quat.safeEulerAngles(options.orientation); + var orientation = [ deg.x, deg.y, deg.z].map(Math.round).join(", "); + var volume = options.volume; + } + var info = { + //loudness: soundPlaying.loudness && soundPlaying.loudness.toFixed(4) || undefined, + offset: offset && ("00"+offset.toFixed(1)).substr(-4)+"s" || undefined, + orientation: orientation, + injector: soundPlaying && soundPlaying.playing && "playing", + resource: ambientSound && ambientSound.downloaded && "ready (" + ambientSound.duration.toFixed(1) + "s)", + name: props.name || undefined, + uuid: entity.split(/\W/)[1], // extracts just the first part of the UUID + sound: soundName, + volume: Math.max(0,volume||0).toFixed(2) + " / " + maxVolume.toFixed(2), + distance: (distance||0).toFixed(1) + "m / " + range.toFixed(1) + "m", + state: _debugState.toUpperCase(), + }; + + // Pretty print key/value pairs, excluding any undefined values + var outputText = Object.keys(info).filter(function(key) { + return info[key] !== undefined; + }).map(function(key) { + return key + ": " + info[key]; + }).join("\n"); + + // Calculate a local position for displaying info just above the Entity + var textSize = Overlays.textSize(_debugOverlay, outputText); + var size = { + x: textSize.width + LINEHEIGHT, + y: textSize.height + LINEHEIGHT + }; + var pos = { x: 0, y: props.dimensions.y + size.y/2, z: 0 }; + + var backgroundColor = DEBUG_COLORS[_debugState]; + var backgroundAlpha = backgroundColor ? backgroundColor.alpha : 0.6; + Overlays.editOverlay(_debugOverlay, { + visible: true, + backgroundColor: backgroundColor, + backgroundAlpha: backgroundAlpha, + text: outputText, + localPosition: pos, + size: size, + }); + } + + function _removeDebugOverlays() { + if (_debugOverlay) { + Overlays.deleteOverlay(_debugOverlay); + _debugOverlay = 0; + } + } + + function _createDebugOverlays() { + _debugOverlay = Overlays.addOverlay("text3d", { + visible: true, + lineHeight: LINEHEIGHT, + leftMargin: LINEHEIGHT/2, + topMargin: LINEHEIGHT/2, + localPosition: Vec3.ZERO, + parentID: entity, + ignoreRayIntersection: true, + isFacingAvatar: true, + textAlpha: 0.6, + //drawInFront: true, + }); + } +}) From 827aa68d3f609146a59fd7edf20c6d4a906e6e6f Mon Sep 17 00:00:00 2001 From: humbletim Date: Mon, 16 Jan 2017 19:50:25 -0500 Subject: [PATCH 10/27] cleanup pass --- .../tutorials/entity_scripts/ambientSound.js | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 64adcf379a..3b75ed6720 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -45,25 +45,25 @@ var entity; var ambientSound; var center; - var soundPlaying; + var soundPlaying = false; var checkTimer = false; var _this; var COLOR_OFF = { red: 128, green: 128, blue: 128 }; var COLOR_ON = { red: 255, green: 0, blue: 0 }; - var WANT_DEBUG = true; + var WANT_DEBUG = false; function debugPrint(string) { if (WANT_DEBUG) { print("ambientSound | " + string); } } - var WANT_DEBUG_BROADCASTS = "ambientSound.js"; var WANT_DEBUG_OVERLAY = false; var LINEHEIGHT = 0.1; // Optionally enable debug overlays using a Settings value WANT_DEBUG_OVERLAY = WANT_DEBUG_OVERLAY || /ambientSound/.test(Settings.getValue("WANT_DEBUG_OVERLAY")); + var WANT_DEBUG_BROADCASTS = WANT_DEBUG_OVERLAY && "ambientSound.js"; this.updateSettings = function() { // Check user data on the entity for any changes @@ -95,10 +95,6 @@ return; } } - /*if ("loop" in data && !(soundOptions.loop === data.loop)) { - soundOptions.loop = data.loop; - debugPrint("Read ambient loop state: " + soundOptions.loop); - }*/ } if (!(soundURL === oldSoundURL) || (soundURL === "")) { if (soundURL) { @@ -135,7 +131,6 @@ } this.clickDownOnEntity = function(entityID, mouseEvent) { - print("click"); if (mouseEvent.isPrimaryButton) { this._toggle("primary click"); } @@ -158,7 +153,7 @@ var oldState = _debugState; if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); } this.cleanup(); @@ -218,7 +213,7 @@ // and might indicate a bug where an Entity can become unreachable without `unload` having been called.. print("FIXME: ambientSound.js -- expected Entity unavailable!") if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); } return _this.cleanup(); } @@ -227,7 +222,7 @@ var distance = Vec3.length(Vec3.subtract(MyAvatar.position, center)); if (distance <= range) { var volume = (1.0 - distance / range) * maxVolume; - soundOptions.orientation = Quat.rotation; + soundOptions.orientation = rotation; soundOptions.volume = volume; if (!soundPlaying && ambientSound && ambientSound.downloaded) { debugState("playing", "Starting ambient sound: " + soundName + " (duration: " + ambientSound.duration + ")"); @@ -249,7 +244,7 @@ debugPrint("Ambient sound unload "); if (WANT_DEBUG_BROADCASTS) { var offset = ambientSound && (new Date - startTime)/1000 % ambientSound.duration; - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); } if (WANT_DEBUG_OVERLAY) { _removeDebugOverlays(); @@ -290,8 +285,8 @@ } updateDebugOverlay(); if (WANT_DEBUG_BROADCASTS) { - // Broadcast state changes to an implicit entity channel, making multi-user scenarios easier to verify from a single console - Messages.sendMessage(WANT_DEBUG_BROADCASTS /*entity*/, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); + // Broadcast state changes to make multi-user scenarios easier to verify from a single console + Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); } } From 6c701bb0f0124002fb8e57c6a1cec8cfec1394ab Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 16 Jan 2017 18:22:53 -0800 Subject: [PATCH 11/27] remove ignored avatars from PAL when they disconnect --- interface/resources/qml/hifi/Pal.qml | 4 ++++ interface/src/avatar/AvatarManager.cpp | 5 +++++ libraries/networking/src/NodeList.cpp | 12 ++++++++++++ libraries/networking/src/NodeList.h | 2 ++ .../script-engine/src/UsersScriptingInterface.h | 6 ++++++ scripts/system/pal.js | 8 +++++++- 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 3438baa217..a57e76f864 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -502,6 +502,10 @@ Rectangle { ignored = {}; gainSliderValueDB = {}; break; + case 'avatarDisconnected': + var sessionID = message.params[0]; + delete ignored[sessionID]; + break; default: console.log('Unrecognized message:', JSON.stringify(message)); } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 1f5726acba..848218a27e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -261,6 +261,11 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble || removalReason == YourAvatarEnteredTheirBubble) { DependencyManager::get()->radiusIgnoreNodeBySessionID(avatar->getSessionUUID(), true); } + if (removalReason == KillAvatarReason::AvatarDisconnected) { + // remove from node sets, if present + DependencyManager::get()->maintainIgnoreMuteSets(avatar->getSessionUUID()); + DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); + } _avatarFades.push_back(removedAvatar); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 98a563c4e5..0ad31b70fe 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -847,6 +847,18 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { } } +// removes this UUID from ignore and mute lists. +void NodeList::maintainIgnoreMuteSets(const QUuid& nodeID) { + // don't remove yourself, or nobody + if (!nodeID.isNull() && _sessionUUID != nodeID) { + QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; + QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; + _ignoredNodeIDs.unsafe_erase(nodeID); + _personalMutedNodeIDs.unsafe_erase(nodeID); + qCDebug(networking) << "removed" << nodeID.toString() << "from ignore/mute sets (if present)"; + } +} + bool NodeList::isIgnoringNode(const QUuid& nodeID) const { QReadLocker ignoredSetLocker{ &_ignoredSetLock }; return _ignoredNodeIDs.find(nodeID) != _ignoredNodeIDs.cend(); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 5c477303e2..4cbe3b1c3b 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -90,6 +90,8 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool isRequesting); + void maintainIgnoreMuteSets(const QUuid& nodeID); + public slots: void reset(); void sendDomainServerCheckIn(); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 0b6b7855b5..2dcff02c77 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -139,6 +139,12 @@ signals: */ void usernameFromIDReply(const QString& nodeID, const QString& username, const QString& machineFingerprint); + /**jsdoc + * Notifies scripts that a user has disconnected from the domain + * @function Users.avatar.avatarDisconnected + */ + void avatarDisconnected(const QUuid& nodeID); + private: bool getRequestsDomainListData(); void setRequestsDomainListData(bool requests); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 5c5b84e3e8..ad7d2bd7b5 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -580,7 +580,11 @@ function onClicked() { } pal.setVisible(!pal.visible); } - +function avatarDisconnected(nodeID) { + // remove from the pal list + print("got avatarDisconnected for " + nodeID); + pal.sendToQml({method: 'avatarDisconnected', params: [nodeID]}); +} // // Button state. // @@ -593,6 +597,8 @@ button.clicked.connect(onClicked); pal.visibleChanged.connect(onVisibleChanged); pal.closed.connect(off); Users.usernameFromIDReply.connect(usernameFromIDReply); +Users.avatarDisconnected.connect(avatarDisconnected); + function clearLocalQMLDataAndClosePAL() { pal.sendToQml({ method: 'clearLocalQMLData' }); if (pal.visible) { From 6c07a9aece6920794cc0d69a5f60d585911877ae Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 16 Jan 2017 19:06:36 -0800 Subject: [PATCH 12/27] remove debuggng logspam --- libraries/networking/src/NodeList.cpp | 1 - scripts/system/pal.js | 1 - 2 files changed, 2 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 0ad31b70fe..8451b2c4a0 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -855,7 +855,6 @@ void NodeList::maintainIgnoreMuteSets(const QUuid& nodeID) { QWriteLocker personalMutedSetLocker{ &_personalMutedSetLock }; _ignoredNodeIDs.unsafe_erase(nodeID); _personalMutedNodeIDs.unsafe_erase(nodeID); - qCDebug(networking) << "removed" << nodeID.toString() << "from ignore/mute sets (if present)"; } } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index ad7d2bd7b5..7ecce80480 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -582,7 +582,6 @@ function onClicked() { } function avatarDisconnected(nodeID) { // remove from the pal list - print("got avatarDisconnected for " + nodeID); pal.sendToQml({method: 'avatarDisconnected', params: [nodeID]}); } // From c7a561aff9cbcee7a01fb5ef81aa401f6920a31b Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 01:23:03 -0500 Subject: [PATCH 13/27] trim extra debugging code --- .../tutorials/entity_scripts/ambientSound.js | 150 +----------------- 1 file changed, 4 insertions(+), 146 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 3b75ed6720..700db4753c 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -22,19 +22,15 @@ // (function(){ - var VERSION = "0.0.1"; // This sample clip and range will be used if you don't add userData to the entity (see above) var DEFAULT_RANGE = 100; var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; var soundURL = ""; - var soundName = ""; - var startTime; var soundOptions = { loop: true, localOnly: true, - //ignorePenumbra: true, }; var range = DEFAULT_RANGE; var maxVolume = DEFAULT_VOLUME; @@ -59,12 +55,6 @@ } } - var WANT_DEBUG_OVERLAY = false; - var LINEHEIGHT = 0.1; - // Optionally enable debug overlays using a Settings value - WANT_DEBUG_OVERLAY = WANT_DEBUG_OVERLAY || /ambientSound/.test(Settings.getValue("WANT_DEBUG_OVERLAY")); - var WANT_DEBUG_BROADCASTS = WANT_DEBUG_OVERLAY && "ambientSound.js"; - this.updateSettings = function() { // Check user data on the entity for any changes var oldSoundURL = soundURL; @@ -73,7 +63,6 @@ var data = JSON.parse(props.userData); if (data.soundURL && !(soundURL === data.soundURL)) { soundURL = data.soundURL; - soundName = (soundURL||"").split("/").pop(); // just filename part debugPrint("Read ambient sound URL: " + soundURL); } if (data.range && !(range === data.range)) { @@ -111,13 +100,6 @@ debugPrint("Failed to download ambient sound: " + soundURL); debugState("error"); } - debugPrint("onStateChanged: " + JSON.stringify({ - sound: soundName, - state: resource.state, - stateName: Object.keys(Resource.State).filter(function(key) { - return Resource.State[key] === resource.state; - }) - })); } resource.stateChanged.connect(onStateChanged); onStateChanged(resource.state); @@ -149,13 +131,9 @@ var data = JSON.parse(props.userData); data.disabled = !data.disabled; - debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundName + ")"); + debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); var oldState = _debugState; - if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: hint, scriptTimestamp: props.scriptTimestamp, oldState: oldState, newState: _debugState, age: props.age })); - } - this.cleanup(); // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change @@ -182,14 +160,10 @@ this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. - debugPrint("Ambient sound preload " + VERSION); + debugPrint("Ambient sound preload"); entity = entityID; _this = this; - if (WANT_DEBUG_OVERLAY) { - _createDebugOverlays(); - } - var props = Entities.getEntityProperties(entity, [ "userData" ]); if (props.userData) { var data = JSON.parse(props.userData); @@ -209,12 +183,7 @@ var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]); if (!props.position) { - // FIXME: this mysterious state has been happening while testing - // and might indicate a bug where an Entity can become unreachable without `unload` having been called.. print("FIXME: ambientSound.js -- expected Entity unavailable!") - if (WANT_DEBUG_BROADCASTS) { - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "FIXME: maybeUpdate", oldState: _debugState })); - } return _this.cleanup(); } center = props.position; @@ -225,7 +194,7 @@ soundOptions.orientation = rotation; soundOptions.volume = volume; if (!soundPlaying && ambientSound && ambientSound.downloaded) { - debugState("playing", "Starting ambient sound: " + soundName + " (duration: " + ambientSound.duration + ")"); + debugState("playing", "Starting ambient sound: " + soundURL + " (duration: " + ambientSound.duration + ")"); soundPlaying = Audio.playSound(ambientSound, soundOptions); } else if (soundPlaying && soundPlaying.playing) { soundPlaying.setOptions(soundOptions); @@ -233,22 +202,12 @@ } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { soundPlaying.stop(); soundPlaying = false; - debugState("idle", "Out of range, stopping ambient sound: " + soundName); - } - if (WANT_DEBUG_OVERLAY) { - updateDebugOverlay(distance); + debugState("idle", "Out of range, stopping ambient sound: " + soundURL); } } this.unload = function(entityID) { debugPrint("Ambient sound unload "); - if (WANT_DEBUG_BROADCASTS) { - var offset = ambientSound && (new Date - startTime)/1000 % ambientSound.duration; - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, hint: "unload", oldState: _debugState, offset: offset })); - } - if (WANT_DEBUG_OVERLAY) { - _removeDebugOverlays(); - } this.cleanup(); }; @@ -263,105 +222,4 @@ } }; - // Visual debugging overlay (to see set WANT_DEBUG_OVERLAY = true) - - var DEBUG_COLORS = { - //preload: { red: 0, green: 80, blue: 80 }, - disabled: { red: 0, green: 0, blue: 0, alpha: 0.0 }, - downloading: { red: 255, green: 255, blue: 0 }, - error: { red: 255, green: 0, blue: 0 }, - playing: { red: 0, green: 200, blue: 0 }, - idle: { red: 0, green: 100, blue: 0 } - }; - var _debugOverlay; - var _debugState = ""; - function debugState(state, message) { - if (state === "playing") { - startTime = new Date; - } - _debugState = state; - if (message) { - debugPrint(message); - } - updateDebugOverlay(); - if (WANT_DEBUG_BROADCASTS) { - // Broadcast state changes to make multi-user scenarios easier to verify from a single console - Messages.sendMessage(WANT_DEBUG_BROADCASTS, JSON.stringify({ palName: MyAvatar.sessionDisplayName, soundName: soundName, state: state })); - } - } - - function updateDebugOverlay(distance) { - var props = Entities.getEntityProperties(entity, [ "name", "dimensions" ]); - if (!props.dimensions) { - return print("ambientSound.js: updateDebugOverlay -- entity no longer available " + entity); - } - var options = soundPlaying && soundPlaying.options; - if (options) { - var offset = soundPlaying.playing && ambientSound && (new Date - startTime)/1000 % ambientSound.duration; - var deg = Quat.safeEulerAngles(options.orientation); - var orientation = [ deg.x, deg.y, deg.z].map(Math.round).join(", "); - var volume = options.volume; - } - var info = { - //loudness: soundPlaying.loudness && soundPlaying.loudness.toFixed(4) || undefined, - offset: offset && ("00"+offset.toFixed(1)).substr(-4)+"s" || undefined, - orientation: orientation, - injector: soundPlaying && soundPlaying.playing && "playing", - resource: ambientSound && ambientSound.downloaded && "ready (" + ambientSound.duration.toFixed(1) + "s)", - name: props.name || undefined, - uuid: entity.split(/\W/)[1], // extracts just the first part of the UUID - sound: soundName, - volume: Math.max(0,volume||0).toFixed(2) + " / " + maxVolume.toFixed(2), - distance: (distance||0).toFixed(1) + "m / " + range.toFixed(1) + "m", - state: _debugState.toUpperCase(), - }; - - // Pretty print key/value pairs, excluding any undefined values - var outputText = Object.keys(info).filter(function(key) { - return info[key] !== undefined; - }).map(function(key) { - return key + ": " + info[key]; - }).join("\n"); - - // Calculate a local position for displaying info just above the Entity - var textSize = Overlays.textSize(_debugOverlay, outputText); - var size = { - x: textSize.width + LINEHEIGHT, - y: textSize.height + LINEHEIGHT - }; - var pos = { x: 0, y: props.dimensions.y + size.y/2, z: 0 }; - - var backgroundColor = DEBUG_COLORS[_debugState]; - var backgroundAlpha = backgroundColor ? backgroundColor.alpha : 0.6; - Overlays.editOverlay(_debugOverlay, { - visible: true, - backgroundColor: backgroundColor, - backgroundAlpha: backgroundAlpha, - text: outputText, - localPosition: pos, - size: size, - }); - } - - function _removeDebugOverlays() { - if (_debugOverlay) { - Overlays.deleteOverlay(_debugOverlay); - _debugOverlay = 0; - } - } - - function _createDebugOverlays() { - _debugOverlay = Overlays.addOverlay("text3d", { - visible: true, - lineHeight: LINEHEIGHT, - leftMargin: LINEHEIGHT/2, - topMargin: LINEHEIGHT/2, - localPosition: Vec3.ZERO, - parentID: entity, - ignoreRayIntersection: true, - isFacingAvatar: true, - textAlpha: 0.6, - //drawInFront: true, - }); - } }) From 27a23676345b744465d31195c210a1e2cc8ea886 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 01:27:48 -0500 Subject: [PATCH 14/27] update debugPrints --- scripts/tutorials/entity_scripts/ambientSound.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 700db4753c..523b96c076 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -80,25 +80,22 @@ debugPrint("Read ambient disabled state: " + disabled); if (disabled) { this.cleanup(); - debugState("disabled"); return; } } } if (!(soundURL === oldSoundURL) || (soundURL === "")) { if (soundURL) { - debugState("downloading", "Loading ambient sound into cache"); + debugPrint("Loading ambient sound into cache"); // Use prefetch to detect URL loading errors var resource = SoundCache.prefetch(soundURL); function onStateChanged() { if (resource.state === Resource.State.FINISHED) { resource.stateChanged.disconnect(onStateChanged); ambientSound = SoundCache.getSound(soundURL); - debugState("idle"); } else if (resource.state === Resource.State.FAILED) { resource.stateChanged.disconnect(onStateChanged); debugPrint("Failed to download ambient sound: " + soundURL); - debugState("error"); } } resource.stateChanged.connect(onStateChanged); @@ -132,7 +129,6 @@ data.disabled = !data.disabled; debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); - var oldState = _debugState; this.cleanup(); @@ -141,7 +137,6 @@ userData: JSON.stringify(data), scriptTimestamp: Math.round(props.age * 1000) }); - //this._updateColor(data.disabled); }; this._updateColor = function(disabled) { @@ -194,7 +189,7 @@ soundOptions.orientation = rotation; soundOptions.volume = volume; if (!soundPlaying && ambientSound && ambientSound.downloaded) { - debugState("playing", "Starting ambient sound: " + soundURL + " (duration: " + ambientSound.duration + ")"); + debugPrint("Starting ambient sound: " + soundURL + " (duration: " + ambientSound.duration + ")"); soundPlaying = Audio.playSound(ambientSound, soundOptions); } else if (soundPlaying && soundPlaying.playing) { soundPlaying.setOptions(soundOptions); @@ -202,7 +197,7 @@ } else if (soundPlaying && soundPlaying.playing && (distance > range * HYSTERESIS_FRACTION)) { soundPlaying.stop(); soundPlaying = false; - debugState("idle", "Out of range, stopping ambient sound: " + soundURL); + debugPrint("Out of range, stopping ambient sound: " + soundURL); } } From 88b7f9ec9d6edbda0659b48aef1594680627f6f3 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 01:44:03 -0500 Subject: [PATCH 15/27] add ambient sound test --- scripts/developer/tests/ambientSoundTest.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 scripts/developer/tests/ambientSoundTest.js diff --git a/scripts/developer/tests/ambientSoundTest.js b/scripts/developer/tests/ambientSoundTest.js new file mode 100644 index 0000000000..2d5fd832c6 --- /dev/null +++ b/scripts/developer/tests/ambientSoundTest.js @@ -0,0 +1,18 @@ +var WAVE = 'http://cdn.rawgit.com/ambisonictoolkit/atk-sounds/aa31005c/stereo/Aurora_Surgit-Lux_Aeterna.wav'; +var uuid = Entities.addEntity({ + type: "Shape", + shape: "Icosahedron", + dimensions: Vec3.HALF, + script: Script.resolvePath('../../tutorials/entity_scripts/ambientSound.js'), + position: Vec3.sum(Vec3.multiply(5, Quat.getFront(MyAvatar.orientation)), MyAvatar.position), + userData: JSON.stringify({ + soundURL: WAVE, + maxVolume: 0.1, + range: 25, + disabled: true, + }), + lifetime: 600, +}); +Script.scriptEnding.connect(function() { + Entities.deleteEntity(uuid); +}); From 7025ed59090ac719412606975b56000e3edb40a9 Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 17 Jan 2017 03:18:56 -0500 Subject: [PATCH 16/27] update test script to create a triggerable entity --- scripts/developer/tests/ambientSoundTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/developer/tests/ambientSoundTest.js b/scripts/developer/tests/ambientSoundTest.js index 2d5fd832c6..5b373715c0 100644 --- a/scripts/developer/tests/ambientSoundTest.js +++ b/scripts/developer/tests/ambientSoundTest.js @@ -10,6 +10,7 @@ var uuid = Entities.addEntity({ maxVolume: 0.1, range: 25, disabled: true, + grabbableKey: { wantsTrigger: true }, }), lifetime: 600, }); From 2460e89a574613ab615c05c0d2ba283a6d2a5d71 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 17 Jan 2017 09:53:04 -0800 Subject: [PATCH 17/27] CR feedback --- interface/src/avatar/AvatarManager.cpp | 2 +- libraries/networking/src/NodeList.cpp | 3 +-- libraries/networking/src/NodeList.h | 2 +- scripts/system/pal.js | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 848218a27e..ef08a463f4 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -263,7 +263,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar } if (removalReason == KillAvatarReason::AvatarDisconnected) { // remove from node sets, if present - DependencyManager::get()->maintainIgnoreMuteSets(avatar->getSessionUUID()); + DependencyManager::get()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); } _avatarFades.push_back(removedAvatar); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 8451b2c4a0..0fcd207b94 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -847,8 +847,7 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { } } -// removes this UUID from ignore and mute lists. -void NodeList::maintainIgnoreMuteSets(const QUuid& nodeID) { +void NodeList::removeFromIgnoreMuteSets(const QUuid& nodeID) { // don't remove yourself, or nobody if (!nodeID.isNull() && _sessionUUID != nodeID) { QWriteLocker ignoredSetLocker{ &_ignoredSetLock }; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 4cbe3b1c3b..c4564c0889 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -90,7 +90,7 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool isRequesting); - void maintainIgnoreMuteSets(const QUuid& nodeID); + void removeFromIgnoreMuteSets(const QUuid& nodeID); public slots: void reset(); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 7ecce80480..fb0d2b310b 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -620,6 +620,7 @@ Script.scriptEnding.connect(function () { Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL); Messages.unsubscribe(CHANNEL); Messages.messageReceived.disconnect(receiveMessage); + Users.avatarDisconnected.disconnect(avatarDisconnected); off(); }); From 1e04aebb8d33e9e9bb4a4e072690dc7d5b7f381f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 17 Jan 2017 11:25:40 -0800 Subject: [PATCH 18/27] add --fast-hearbeat command line switch for 1s stats --- interface/src/Application.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ceda6c6598..4f35b10a1b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1238,8 +1238,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Add periodic checks to send user activity data static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; - static int SEND_STATS_INTERVAL_MS = 10000; static int NEARBY_AVATAR_RADIUS_METERS = 10; + + // setup the stats interval depending on if the 1s faster hearbeat was requested + static const QString FAST_STATS_ARG = "--fast-heartbeat"; + static int SEND_STATS_INTERVAL_MS = arguments().indexOf(FAST_STATS_ARG) != -1 ? 1000 : 10000; static glm::vec3 lastAvatarPosition = myAvatar->getPosition(); static glm::mat4 lastHMDHeadPose = getHMDSensorPose(); From 246f5fb7f5da02172c45e8c8032bb8274ffd8ef0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 17 Jan 2017 11:51:09 -0800 Subject: [PATCH 19/27] Add log; fix whitespace --- assignment-client/src/avatars/AvatarMixer.cpp | 4 +++- libraries/networking/src/udt/PacketHeaders.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 4127719b7b..cd866cecb2 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -280,12 +280,14 @@ void AvatarMixer::broadcastAvatarData() { QPair& soFar = _sessionDisplayNames[baseName]; // Inserts and answers 0, 0 if not already present, which is what we want. int& highWater = soFar.first; nodeData->setBaseDisplayName(baseName); - avatar.setSessionDisplayName((highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName); + QString sessionDisplayName = (highWater > 0) ? baseName + "_" + QString::number(highWater) : baseName; + avatar.setSessionDisplayName(sessionDisplayName); highWater++; soFar.second++; // refcount nodeData->flagIdentityChange(); nodeData->setAvatarSessionDisplayNameMustChange(false); sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name. Others will find out below. + qDebug() << "Giving session display name" << sessionDisplayName << "to node with ID" << node->getUUID(); } // this is an AGENT we have received head data from diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 9bbd139138..5cef6013d9 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -212,7 +212,7 @@ enum class AvatarMixerPacketVersion : PacketVersion { HasKillAvatarReason, SessionDisplayName, Unignore, - ImmediateSessionDisplayNameUpdates + ImmediateSessionDisplayNameUpdates }; enum class DomainConnectRequestVersion : PacketVersion { From 9b1aaf3bfeb9a136a79396f75565eb02abd110a0 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 17 Jan 2017 12:09:47 -0800 Subject: [PATCH 20/27] CR feedback --- interface/src/avatar/AvatarManager.cpp | 3 +-- libraries/script-engine/src/UsersScriptingInterface.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index ef08a463f4..b0dc9922ff 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -260,8 +260,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar } if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble || removalReason == YourAvatarEnteredTheirBubble) { DependencyManager::get()->radiusIgnoreNodeBySessionID(avatar->getSessionUUID(), true); - } - if (removalReason == KillAvatarReason::AvatarDisconnected) { + } else if (removalReason == KillAvatarReason::AvatarDisconnected) { // remove from node sets, if present DependencyManager::get()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 2dcff02c77..758868ac63 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -142,6 +142,7 @@ signals: /**jsdoc * Notifies scripts that a user has disconnected from the domain * @function Users.avatar.avatarDisconnected + * @param {nodeID} NodeID The session ID of the avatar that has disconnected */ void avatarDisconnected(const QUuid& nodeID); From 59ff970d5b400867506418da8761442fdca6dc3d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 17 Jan 2017 15:01:02 -0800 Subject: [PATCH 21/27] CR feedback --- interface/resources/qml/hifi/NameCard.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 367ef3b25b..2725ea1617 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -75,7 +75,7 @@ Item { id: myDisplayNameText // Properties text: thisNameCard.displayName - maximumLength: 64 + maximumLength: 256 clip: true // Size width: parent.width @@ -84,7 +84,8 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 10 - anchors.rightMargin: editGlyph.implicitWidth + editGlyph.anchors.rightMargin + anchors.right: parent.right + anchors.rightMargin: editGlyph.width + editGlyph.anchors.rightMargin // Style color: hifi.colors.darkGray FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } @@ -98,6 +99,7 @@ Item { // Signals onEditingFinished: { pal.sendToScript({method: 'displayNameUpdate', params: text}) + cursorPosition = 0 focus = false myDisplayName.border.width = 0 color = hifi.colors.darkGray From f5300d3862b8ce9dea56201674aa687965487c0d Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 17 Jan 2017 17:06:18 -0800 Subject: [PATCH 22/27] Removing some PAL-related interface log spam Probably more, but these _seem_ to be the worst --- interface/resources/qml/hifi/Pal.qml | 4 ---- scripts/system/pal.js | 1 - 2 files changed, 5 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 549598dd2e..7260cd1c14 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -476,8 +476,6 @@ Rectangle { // Set the userName appropriately userModel.setProperty(userIndex, "userName", userName); userModelData[userIndex].userName = userName; // Defensive programming - } else { - console.log("updateUsername() called with unknown UUID: ", userId); } } break; @@ -493,8 +491,6 @@ Rectangle { if (userIndex != -1) { userModel.setProperty(userIndex, "audioLevel", audioLevel); userModelData[userIndex].audioLevel = audioLevel; // Defensive programming - } else { - console.log("updateUsername() called with unknown UUID: ", userId); } } } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 2430ce6e87..c61dbba872 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -498,7 +498,6 @@ function getAudioLevel(id) { var audioLevel = 0.0; var data = id ? ExtendedOverlay.get(id) : myData; if (!data) { - print('no data for', id); return audioLevel; } From cbc89e77ab11a9d1a0d0657b4eb9405e6b641618 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 17 Jan 2017 09:32:58 -0800 Subject: [PATCH 23/27] Consume fewer resources in AssetServer when interface is running locally --- assignment-client/src/assets/AssetServer.cpp | 48 +++++++++++++++++ interface/src/main.cpp | 2 +- libraries/shared/src/SharedUtil.cpp | 54 +++++++++++++++++++- libraries/shared/src/SharedUtil.h | 4 ++ 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2fbe2f6dfe..69f3d83583 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -12,6 +12,8 @@ #include "AssetServer.h" +#include + #include #include #include @@ -21,6 +23,7 @@ #include #include +#include #include #include "NetworkLogging.h" @@ -30,6 +33,37 @@ const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; +bool interfaceRunning() { + bool result = false; + +#ifdef Q_OS_WIN + QSharedMemory sharedMemory { getInterfaceSharedMemoryName() }; + result = sharedMemory.attach(QSharedMemory::ReadOnly); + if (result) { + sharedMemory.detach(); + } +#endif + return result; +} + +void updateConsumedCores() { + static bool wasInterfaceRunning = false; + bool isInterfaceRunning = interfaceRunning(); + // If state is unchanged, return early + if (isInterfaceRunning == wasInterfaceRunning) { + return; + } + + wasInterfaceRunning = isInterfaceRunning; + auto coreCount = std::thread::hardware_concurrency(); + if (isInterfaceRunning) { + coreCount = coreCount > 4 ? 2 : 1; + } + qDebug() << "Setting max consumed cores to " << coreCount; + setMaxCores(coreCount); +} + + AssetServer::AssetServer(ReceivedMessage& message) : ThreadedAssignment(message), _taskPool(this) @@ -45,6 +79,20 @@ AssetServer::AssetServer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); + +#ifdef Q_OS_WIN + updateConsumedCores(); + QTimer* timer = new QTimer(this); + auto timerConnection = connect(timer, &QTimer::timeout, [] { + updateConsumedCores(); + }); + connect(qApp, &QCoreApplication::aboutToQuit, [this, timerConnection] { + disconnect(timerConnection); + }); + timer->setInterval(1000); + timer->setTimerType(Qt::CoarseTimer); + timer->start(); +#endif } void AssetServer::run() { diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c83f7a989c..d33dba535e 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -56,7 +56,7 @@ int main(int argc, const char* argv[]) { QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN); QCoreApplication::setApplicationVersion(BuildInfo::VERSION); - QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME"); + const QString& applicationName = getInterfaceSharedMemoryName(); bool instanceMightBeRunning = true; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 89116aa924..4b8699befd 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -1022,4 +1024,54 @@ bool getProcessorInfo(ProcessorInfo& info) { #endif return false; -} \ No newline at end of file +} + + +const QString& getInterfaceSharedMemoryName() { + static const QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME"); + return applicationName; +} + +const std::vector& getAvailableCores() { + static std::vector availableCores; +#ifdef Q_OS_WIN + static std::once_flag once; + std::call_once(once, [&] { + DWORD_PTR defaultProcessAffinity = 0, defaultSystemAffinity = 0; + HANDLE process = GetCurrentProcess(); + GetProcessAffinityMask(process, &defaultProcessAffinity, &defaultSystemAffinity); + for (uint64_t i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { + DWORD_PTR coreMask = 1; + coreMask <<= i; + if (0 != (defaultSystemAffinity & coreMask)) { + availableCores.push_back(i); + } + } + }); +#endif + return availableCores; +} + +void setMaxCores(uint8_t maxCores) { +#ifdef Q_OS_WIN + HANDLE process = GetCurrentProcess(); + auto availableCores = getAvailableCores(); + if (availableCores.size() <= maxCores) { + DWORD_PTR currentProcessAffinity = 0, currentSystemAffinity = 0; + GetProcessAffinityMask(process, ¤tProcessAffinity, ¤tSystemAffinity); + SetProcessAffinityMask(GetCurrentProcess(), currentSystemAffinity); + return; + } + + DWORD_PTR newProcessAffinity = 0; + while (maxCores) { + int index = randIntInRange(0, (int)availableCores.size() - 1); + DWORD_PTR coreMask = 1; + coreMask <<= availableCores[index]; + newProcessAffinity |= coreMask; + availableCores.erase(availableCores.begin() + index); + maxCores--; + } + SetProcessAffinityMask(process, newProcessAffinity); +#endif +} diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 77204c9608..0f30842f47 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -231,4 +231,8 @@ struct ProcessorInfo { bool getProcessorInfo(ProcessorInfo& info); +const QString& getInterfaceSharedMemoryName(); + +void setMaxCores(uint8_t maxCores); + #endif // hifi_SharedUtil_h From a593a2116a069bc8625e8ad2ca57f9d629f56000 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 17 Jan 2017 13:40:19 -0800 Subject: [PATCH 24/27] Removing magic numbers --- assignment-client/src/assets/AssetServer.cpp | 9 +++++++-- libraries/shared/src/SharedUtil.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 69f3d83583..2498af8010 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -31,6 +31,11 @@ #include "SendAssetTask.h" #include "UploadAssetTask.h" +static const uint8_t MIN_CORES_FOR_MULTICORE = 4; +static const uint8_t CPU_AFFINITY_COUNT_HIGH = 2; +static const uint8_t CPU_AFFINITY_COUNT_LOW = 1; +static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000; + const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; bool interfaceRunning() { @@ -57,7 +62,7 @@ void updateConsumedCores() { wasInterfaceRunning = isInterfaceRunning; auto coreCount = std::thread::hardware_concurrency(); if (isInterfaceRunning) { - coreCount = coreCount > 4 ? 2 : 1; + coreCount = coreCount > MIN_CORES_FOR_MULTICORE ? CPU_AFFINITY_COUNT_HIGH : CPU_AFFINITY_COUNT_LOW; } qDebug() << "Setting max consumed cores to " << coreCount; setMaxCores(coreCount); @@ -89,7 +94,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : connect(qApp, &QCoreApplication::aboutToQuit, [this, timerConnection] { disconnect(timerConnection); }); - timer->setInterval(1000); + timer->setInterval(INTERFACE_RUNNING_CHECK_FREQUENCY_MS); timer->setTimerType(Qt::CoarseTimer); timer->start(); #endif diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 4b8699befd..a7e251f0e0 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -1040,7 +1040,7 @@ const std::vector& getAvailableCores() { DWORD_PTR defaultProcessAffinity = 0, defaultSystemAffinity = 0; HANDLE process = GetCurrentProcess(); GetProcessAffinityMask(process, &defaultProcessAffinity, &defaultSystemAffinity); - for (uint64_t i = 0; i < sizeof(DWORD_PTR) * 8; ++i) { + for (uint64_t i = 0; i < sizeof(DWORD_PTR) * BITS_IN_BYTE; ++i) { DWORD_PTR coreMask = 1; coreMask <<= i; if (0 != (defaultSystemAffinity & coreMask)) { From 1048c2a3bf2c099d8912b55096eb48f41bc6c5ce Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 18 Jan 2017 01:39:55 -0500 Subject: [PATCH 25/27] apply default userData values; add error checking; throttle toggle clicks --- .../tutorials/entity_scripts/ambientSound.js | 67 ++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 523b96c076..35c9753221 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -27,6 +27,14 @@ var DEFAULT_URL = "http://hifi-content.s3.amazonaws.com/ken/samples/forest_ambiX.wav"; var DEFAULT_VOLUME = 1.0; + var DEFAULT_USERDATA = { + soundURL: DEFAULT_URL, + range: DEFAULT_RANGE, + maxVolume: DEFAULT_VOLUME, + disabled: true, + grabbableKey: { wantsTrigger: true }, + }; + var soundURL = ""; var soundOptions = { loop: true, @@ -60,7 +68,13 @@ var oldSoundURL = soundURL; var props = Entities.getEntityProperties(entity, [ "userData" ]); if (props.userData) { - var data = JSON.parse(props.userData); + try { + var data = JSON.parse(props.userData); + } catch(e) { + debugPrint("unable to parse userData JSON string: " + props.userData); + this.cleanup(); + return; + } if (data.soundURL && !(soundURL === data.soundURL)) { soundURL = data.soundURL; debugPrint("Read ambient sound URL: " + soundURL); @@ -125,18 +139,27 @@ return; } var props = Entities.getEntityProperties(entity, [ "userData", "age", "scriptTimestamp" ]); + if (!props.userData) { + debugPrint("userData is empty; ignoring " + hint); + this.cleanup(); + return; + } var data = JSON.parse(props.userData); data.disabled = !data.disabled; debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); this.cleanup(); + // Prevent rapid-fire toggling (which seems to sometimes lead to sound injectors becoming unstoppable) + this._toggle = this.clickDownOnEntity = function(hint) { debugPrint("ignoring additonal clicks" + hint); }; - // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change - Entities.editEntity(entity, { - userData: JSON.stringify(data), - scriptTimestamp: Math.round(props.age * 1000) - }); + Script.setTimeout(function() { + // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change + Entities.editEntity(entity, { + userData: JSON.stringify(data), + scriptTimestamp: props.scriptTimestamp + 1 + }); + }, 250); }; this._updateColor = function(disabled) { @@ -155,21 +178,35 @@ this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. - debugPrint("Ambient sound preload"); + debugPrint("Ambient sound preload " + entityID); entity = entityID; _this = this; - var props = Entities.getEntityProperties(entity, [ "userData" ]); + var props = Entities.getEntityProperties(entity, [ "name", "userData" ]); + var data = {}; if (props.userData) { - var data = JSON.parse(props.userData); - this._updateColor(data.disabled); - if (data.disabled) { - _this.maybeUpdate(); - return; + data = JSON.parse(props.userData); + } + var changed = false; + for(var p in DEFAULT_USERDATA) { + if (!(p in data)) { + data[p] = DEFAULT_USERDATA[p]; + changed = true; } } - - checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + if (!data.grabbableKey.wantsTrigger) { + data.grabbableKey.wantsTrigger = true; + changed = true; + } + if (changed) { + debugPrint("applying default values to userData"); + Entities.editEntity(entity, { userData: JSON.stringify(data) }); + } + this._updateColor(data.disabled); + this.updateSettings(); + if (!data.disabled) { + checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + } }; this.maybeUpdate = function() { From f88b39918f8281dd314a188fc41560016727f53f Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 18 Jan 2017 02:54:42 -0500 Subject: [PATCH 26/27] switch to messaging for toggle notifications; cleanup --- .../tutorials/entity_scripts/ambientSound.js | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 35c9753221..810c9769b8 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -92,12 +92,16 @@ if ("disabled" in data && !(disabled === data.disabled)) { disabled = data.disabled; debugPrint("Read ambient disabled state: " + disabled); - if (disabled) { - this.cleanup(); - return; - } + this._updateColor(disabled); } } + if (disabled) { + this.cleanup(); + soundURL = ""; + return; + } else if (!checkTimer) { + checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + } if (!(soundURL === oldSoundURL) || (soundURL === "")) { if (soundURL) { debugPrint("Loading ambient sound into cache"); @@ -138,7 +142,7 @@ if (Settings.getValue("io.highfidelity.isEditting")) { return; } - var props = Entities.getEntityProperties(entity, [ "userData", "age", "scriptTimestamp" ]); + var props = Entities.getEntityProperties(entity, [ "userData" ]); if (!props.userData) { debugPrint("userData is empty; ignoring " + hint); this.cleanup(); @@ -147,19 +151,15 @@ var data = JSON.parse(props.userData); data.disabled = !data.disabled; - debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + soundURL + ")"); + debugPrint(hint + " -- triggering ambient sound " + (data.disabled ? "OFF" : "ON") + " (" + data.soundURL + ")"); this.cleanup(); - // Prevent rapid-fire toggling (which seems to sometimes lead to sound injectors becoming unstoppable) - this._toggle = this.clickDownOnEntity = function(hint) { debugPrint("ignoring additonal clicks" + hint); }; - Script.setTimeout(function() { - // Save the userData and bump scriptTimestamp, which causes all nearby listeners to apply the state change - Entities.editEntity(entity, { - userData: JSON.stringify(data), - scriptTimestamp: props.scriptTimestamp + 1 - }); - }, 250); + // Save the userData and notify nearby listeners of the change + Entities.editEntity(entity, { + userData: JSON.stringify(data) + }); + Messages.sendMessage(entity, "toggled"); }; this._updateColor = function(disabled) { @@ -182,7 +182,7 @@ entity = entityID; _this = this; - var props = Entities.getEntityProperties(entity, [ "name", "userData" ]); + var props = Entities.getEntityProperties(entity, [ "userData" ]); var data = {}; if (props.userData) { data = JSON.parse(props.userData); @@ -204,8 +204,17 @@ } this._updateColor(data.disabled); this.updateSettings(); - if (!data.disabled) { - checkTimer = Script.setInterval(_this.maybeUpdate, UPDATE_INTERVAL_MSECS); + + // Subscribe to toggle notifications using entity ID as a channel name + Messages.subscribe(entity); + Messages.messageReceived.connect(this, "_onMessageReceived"); + }; + + this._onMessageReceived = function(channel, message, sender, local) { + // Handle incoming toggle notifications + if (channel === entity && message === "toggled"/*&& sender !== MyAvatar.sessionUUID*/) { + debugPrint("received " + message + " from " + sender); + this.updateSettings(); } }; @@ -214,9 +223,9 @@ _this.updateSettings(); var HYSTERESIS_FRACTION = 0.1; var props = Entities.getEntityProperties(entity, [ "position", "rotation" ]); - if (!props.position) { - print("FIXME: ambientSound.js -- expected Entity unavailable!") - return _this.cleanup(); + if (disabled || !props.position) { + _this.cleanup(); + return; } center = props.position; rotation = props.rotation; @@ -236,11 +245,13 @@ soundPlaying = false; debugPrint("Out of range, stopping ambient sound: " + soundURL); } - } + }; this.unload = function(entityID) { - debugPrint("Ambient sound unload "); + debugPrint("Ambient sound unload"); this.cleanup(); + Messages.unsubscribe(entity); + Messages.messageReceived.disconnect(this, "_onMessageReceived"); }; this.cleanup = function() { From 6320d872b40a8f6332e82097fbddccae98c62bec Mon Sep 17 00:00:00 2001 From: humbletim Date: Wed, 18 Jan 2017 02:57:13 -0500 Subject: [PATCH 27/27] remove commented code --- scripts/tutorials/entity_scripts/ambientSound.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tutorials/entity_scripts/ambientSound.js b/scripts/tutorials/entity_scripts/ambientSound.js index 810c9769b8..e0a7d0a3cf 100644 --- a/scripts/tutorials/entity_scripts/ambientSound.js +++ b/scripts/tutorials/entity_scripts/ambientSound.js @@ -212,7 +212,7 @@ this._onMessageReceived = function(channel, message, sender, local) { // Handle incoming toggle notifications - if (channel === entity && message === "toggled"/*&& sender !== MyAvatar.sessionUUID*/) { + if (channel === entity && message === "toggled") { debugPrint("received " + message + " from " + sender); this.updateSettings(); }