From 0eead13fb95d78ff8ee856a64db6523c8c82535d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Oct 2018 15:03:47 +1300 Subject: [PATCH 01/13] Make Create not grab tablet if editing an entity with hand --- .../nearParentGrabOverlay.js | 35 ++++++++++++++++--- .../libraries/controllerDispatcherUtils.js | 4 +++ .../system/libraries/entitySelectionTool.js | 13 ++++++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index 763a0a0a27..69aaad4247 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -9,7 +9,7 @@ /* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings, - NEAR_GRAB_RADIUS, HMD, Uuid + NEAR_GRAB_RADIUS, HMD, Uuid, HIFI_EDIT_MANIPULATION_CHANNEL */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -172,10 +172,14 @@ Script.include("/~/system/libraries/utils.js"); return null; }; + this.isEditing = false; + this.setIsEditing = function (editing) { + this.isEditing = editing; + }; this.isReady = function (controllerData) { - if ((controllerData.triggerClicks[this.hand] === 0 && - controllerData.secondaryValues[this.hand] === 0)) { + if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) + || this.isEditing) { this.robbed = false; return makeRunningValues(false, [], []); } @@ -198,7 +202,8 @@ Script.include("/~/system/libraries/utils.js"); }; this.run = function (controllerData) { - if (controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) { + if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) + || this.isEditing) { this.endNearParentingGrabOverlay(); this.robbed = false; return makeRunningValues(false, [], []); @@ -226,6 +231,28 @@ Script.include("/~/system/libraries/utils.js"); enableDispatcherModule("LeftNearParentingGrabOverlay", leftNearParentingGrabOverlay); enableDispatcherModule("RightNearParentingGrabOverlay", rightNearParentingGrabOverlay); + function onMessageReceived(channel, data, senderID) { + var message; + + if (channel !== HIFI_EDIT_MANIPULATION_CHANNEL || senderID !== MyAvatar.sessionUUID) { + return; + } + + try { + message = JSON.parse(data); + } catch (e) { + return; + } + + if (message.hand === Controller.Standard.LeftHand) { + leftNearParentingGrabOverlay.setIsEditing(message.action === "startEdit"); + } else if (message.hand === Controller.Standard.RightHand) { + rightNearParentingGrabOverlay.setIsEditing(message.action === "startEdit"); + } + } + Messages.subscribe(HIFI_EDIT_MANIPULATION_CHANNEL); + Messages.messageReceived.connect(onMessageReceived); + function cleanup() { leftNearParentingGrabOverlay.cleanup(); rightNearParentingGrabOverlay.cleanup(); diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index e9d5255d28..f7b997a897 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -24,6 +24,7 @@ HAPTIC_PULSE_DURATION:true, DISPATCHER_HOVERING_LIST:true, DISPATCHER_HOVERING_STYLE:true, + HIFI_EDIT_MANIPULATION_CHANNEL:true, Entities, makeDispatcherModuleParameters:true, makeRunningValues:true, @@ -149,6 +150,8 @@ DISPATCHER_PROPERTIES = [ "userData" ]; +HIFI_EDIT_MANIPULATION_CHANNEL = "HiFi-Edit-Manipulation"; + // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step // activitySlots -- indicates which "slots" must not yet be in use for this module to start // requiredDataForReady -- which "situation" parts this module looks at to decide if it will start @@ -590,6 +593,7 @@ if (typeof module !== 'undefined') { TRIGGER_OFF_VALUE: TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE: TRIGGER_ON_VALUE, DISPATCHER_HOVERING_LIST: DISPATCHER_HOVERING_LIST, + HIFI_EDIT_MANIPULATION_CHANNEL: HIFI_EDIT_MANIPULATION_CHANNEL, worldPositionToRegistrationFrameMatrix: worldPositionToRegistrationFrameMatrix }; } diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 3bb36d632e..8f972e14c2 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -14,7 +14,7 @@ // /* global SelectionManager, SelectionDisplay, grid, rayPlaneIntersection, rayPlaneIntersection2, pushCommandForSelections, - getMainTabletIDs, getControllerWorldLocation, TRIGGER_ON_VALUE */ + getMainTabletIDs, getControllerWorldLocation, TRIGGER_ON_VALUE, HIFI_EDIT_MANIPULATION_CHANNEL */ const SPACE_LOCAL = "local"; const SPACE_WORLD = "world"; @@ -983,6 +983,7 @@ SelectionDisplay = (function() { that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); that.triggeredHand = NO_HAND; that.pressedHand = NO_HAND; + that.editingHand = NO_HAND; that.triggered = function() { return that.triggeredHand !== NO_HAND; }; @@ -1115,6 +1116,11 @@ SelectionDisplay = (function() { activeTool = hitTool; that.clearDebugPickPlane(); if (activeTool.onBegin) { + Messages.sendLocalMessage(HIFI_EDIT_MANIPULATION_CHANNEL, JSON.stringify({ + action: "startEdit", + hand: that.triggeredHand + })); + that.editingHand = that.triggeredHand; activeTool.onBegin(event, pickRay, results); } else { print("ERROR: entitySelectionTool.mousePressEvent - ActiveTool(" + activeTool.mode + ") missing onBegin"); @@ -1263,6 +1269,11 @@ SelectionDisplay = (function() { if (wantDebug) { print(" Triggering ActiveTool(" + activeTool.mode + ")'s onEnd"); } + Messages.sendLocalMessage(HIFI_EDIT_MANIPULATION_CHANNEL, JSON.stringify({ + action: "finishEdit", + hand: that.editingHand + })); + that.editingHand = NO_HAND; activeTool.onEnd(event); } else if (wantDebug) { print(" ActiveTool(" + activeTool.mode + ")'s missing onEnd"); From 1460e43f6e1348850a965f93f926af67f43a397d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Oct 2018 15:04:59 +1300 Subject: [PATCH 02/13] Make tablet highlight not display if editing an entity with hand --- .../controllerModules/nearTabletHighlight.js | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js index c24464ab38..3ced0a9e87 100644 --- a/scripts/system/controllers/controllerModules/nearTabletHighlight.js +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -11,7 +11,7 @@ // /* global LEFT_HAND, RIGHT_HAND, makeDispatcherModuleParameters, makeRunningValues, enableDispatcherModule, - * disableDispatcherModule */ + * disableDispatcherModule, HIFI_EDIT_MANIPULATION_CHANNEL */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -66,12 +66,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); 100 ); + this.isEditing = false; + this.setIsEditing = function (editing) { + this.isEditing = editing; + }; + this.isNearTablet = function (controllerData) { return HMD.tabletID && controllerData.nearbyOverlayIDs[this.hand].indexOf(HMD.tabletID) !== -1; }; this.isReady = function (controllerData) { - if (this.isNearTablet(controllerData)) { + if (!this.isEditing && this.isNearTablet(controllerData)) { return makeRunningValues(true, [], []); } setTabletNearGrabbable(this.hand, false); @@ -79,7 +84,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.run = function (controllerData) { - if (!this.isNearTablet(controllerData)) { + if (this.isEditing || !this.isNearTablet(controllerData)) { setTabletNearGrabbable(this.hand, false); return makeRunningValues(false, [], []); } @@ -111,6 +116,28 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); HMD.mountedChanged.connect(onDisplayModeChanged); onDisplayModeChanged(); + function onMessageReceived(channel, data, senderID) { + var message; + + if (channel !== HIFI_EDIT_MANIPULATION_CHANNEL || senderID !== MyAvatar.sessionUUID) { + return; + } + + try { + message = JSON.parse(data); + } catch (e) { + return; + } + + if (message.hand === Controller.Standard.LeftHand) { + leftNearTabletHighlight.setIsEditing(message.action === "startEdit"); + } else if (message.hand === Controller.Standard.RightHand) { + rightNearTabletHighlight.setIsEditing(message.action === "startEdit"); + } + } + Messages.subscribe(HIFI_EDIT_MANIPULATION_CHANNEL); + Messages.messageReceived.connect(onMessageReceived); + function cleanUp() { disableDispatcherModule("LeftNearTabletHighlight"); disableDispatcherModule("RightNearTabletHighlight"); From 1e3549d2637bd7ee30f67f0cd32c6b7ed239cbc3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Nov 2018 08:33:14 +1300 Subject: [PATCH 03/13] Increase delay in shrinking the mini tablet after start of trigger --- scripts/system/miniTablet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/miniTablet.js b/scripts/system/miniTablet.js index a2f0d074f0..63ee91d976 100644 --- a/scripts/system/miniTablet.js +++ b/scripts/system/miniTablet.js @@ -551,7 +551,7 @@ // Trigger values. leftTriggerOn = 0, rightTriggerOn = 0, - MAX_TRIGGER_ON_TIME = 100, + MAX_TRIGGER_ON_TIME = 400, // Visibility. MAX_HAND_CAMERA_ANGLE = 30, From 8924f0832a547068fb73989b72fe63bb58eeafc0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Nov 2018 18:06:00 +1300 Subject: [PATCH 04/13] Use half angles relative to palm normal for mini tablet visibility --- scripts/system/miniTablet.js | 65 +++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/scripts/system/miniTablet.js b/scripts/system/miniTablet.js index 63ee91d976..16673d373f 100644 --- a/scripts/system/miniTablet.js +++ b/scripts/system/miniTablet.js @@ -250,11 +250,8 @@ } - function getUIPositionAndRotation(hand) { - return { - position: MINI_POSITIONS[hand], - rotation: MINI_ROTATIONS[hand] - }; + function getUIPosition(hand) { + return MINI_POSITIONS[hand]; } function getMiniTabletID() { @@ -492,7 +489,7 @@ create(); return { - getUIPositionAndRotation: getUIPositionAndRotation, + getUIPosition: getUIPosition, getMiniTabletID: getMiniTabletID, getMiniTabletProperties: getMiniTabletProperties, isLaserPointingAt: isLaserPointingAt, @@ -554,13 +551,22 @@ MAX_TRIGGER_ON_TIME = 400, // Visibility. - MAX_HAND_CAMERA_ANGLE = 30, - MAX_CAMERA_HAND_ANGLE = 30, + MAX_MEDIAL_FINGER_CAMERA_ANGLE = 25, // From palm normal along palm towards fingers. + MAX_MEDIAL_WRIST_CAMERA_ANGLE = 65, // From palm normal along palm towards wrist. + MAX_LATERAL_THUMB_CAMERA_ANGLE = 25, // From palm normal across palm towards of thumb. + MAX_LATERAL_PINKY_CAMERA_ANGLE = 25, // From palm normal across palm towards pinky. DEGREES_180 = 180, - MAX_HAND_CAMERA_ANGLE_COS = Math.cos(Math.PI * MAX_HAND_CAMERA_ANGLE / DEGREES_180), - MAX_CAMERA_HAND_ANGLE_COS = Math.cos(Math.PI * MAX_CAMERA_HAND_ANGLE / DEGREES_180), + DEGREES_TO_RADIANS = Math.PI / DEGREES_180, + MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_MEDIAL_FINGER_CAMERA_ANGLE, + MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_MEDIAL_WRIST_CAMERA_ANGLE, + MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_LATERAL_THUMB_CAMERA_ANGLE, + MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_LATERAL_PINKY_CAMERA_ANGLE, + MAX_CAMERA_MINI_ANGLE = 30, + MAX_CAMERA_MINI_ANGLE_COS = Math.cos(MAX_CAMERA_MINI_ANGLE * DEGREES_TO_RADIANS), HIDING_DELAY = 1000, // ms - lastVisible = [0, 0]; + lastVisible = [0, 0], + + HALF_PI = Math.PI / 2; function enterMiniDisabled() { @@ -597,11 +603,13 @@ jointIndex, handPosition, handOrientation, - uiPositionAndOrientation, miniPosition, - miniOrientation, miniToCameraDirection, - cameraToHand; + medialHandVector, + lateralHandVector, + medialAngle, + lateralAngle, + cameraToMini; // Shouldn't show mini tablet if hand isn't being controlled. pose = Controller.getPoseValue(hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand); @@ -646,15 +654,24 @@ Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(jointIndex))); handOrientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(jointIndex)); - uiPositionAndOrientation = ui.getUIPositionAndRotation(hand); + var uiPosition = ui.getUIPosition(hand); miniPosition = Vec3.sum(handPosition, Vec3.multiply(MyAvatar.sensorToWorldScale, - Vec3.multiplyQbyV(handOrientation, uiPositionAndOrientation.position))); - miniOrientation = Quat.multiply(handOrientation, uiPositionAndOrientation.rotation); + Vec3.multiplyQbyV(handOrientation, uiPosition))); miniToCameraDirection = Vec3.normalize(Vec3.subtract(Camera.position, miniPosition)); - show = Vec3.dot(miniToCameraDirection, Quat.getForward(miniOrientation)) > MAX_HAND_CAMERA_ANGLE_COS; - show = show || (-Vec3.dot(miniToCameraDirection, Quat.getForward(handOrientation)) > MAX_HAND_CAMERA_ANGLE_COS); - cameraToHand = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation)); - show = show && (cameraToHand > MAX_CAMERA_HAND_ANGLE_COS); + + // Mini tablet aimed toward camera? + medialHandVector = Vec3.multiplyQbyV(handOrientation, Vec3.UNIT_NEG_Y); + lateralHandVector = Vec3.multiplyQbyV(handOrientation, hand === LEFT_HAND ? Vec3.UNIT_X : Vec3.UNIT_NEG_X); + medialAngle = Math.acos(Vec3.dot(medialHandVector, miniToCameraDirection)) - HALF_PI; + lateralAngle = Math.acos(Vec3.dot(lateralHandVector, miniToCameraDirection)) - HALF_PI; + show = -MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD <= medialAngle + && medialAngle <= MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD + && -MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD <= lateralAngle + && lateralAngle <= MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD; + + // Camera looking at mini tablet? + cameraToMini = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation)); + show = show && (cameraToMini > MAX_CAMERA_MINI_ANGLE_COS); // Persist showing for a while after it would otherwise be hidden. if (show) { @@ -666,7 +683,7 @@ return { show: show, - cameraToHand: cameraToHand + cameraToMini: cameraToMini }; } @@ -689,7 +706,7 @@ showRight = shouldShowMini(RIGHT_HAND); if (showLeft.show && showRight.show) { // Both hands would be pointing at camera; show the one the camera is gazing at. - if (showLeft.cameraToHand > showRight.cameraToHand) { + if (showLeft.cameraToMini > showRight.cameraToMini) { setState(MINI_SHOWING, LEFT_HAND); } else { setState(MINI_SHOWING, RIGHT_HAND); @@ -751,7 +768,7 @@ showLeft = shouldShowMini(LEFT_HAND); showRight = shouldShowMini(RIGHT_HAND); if (showLeft.show && showRight.show) { - if (showLeft.cameraToHand > showRight.cameraToHand) { + if (showLeft.cameraToMini > showRight.cameraToMini) { if (miniHand !== LEFT_HAND) { setState(MINI_HIDING); } From 55d0822b1a3224af0c95de0ed41de965693a80b7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Nov 2018 18:18:41 +1300 Subject: [PATCH 05/13] Delay showing mini tablet --- scripts/system/miniTablet.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts/system/miniTablet.js b/scripts/system/miniTablet.js index 16673d373f..a4cd0baf45 100644 --- a/scripts/system/miniTablet.js +++ b/scripts/system/miniTablet.js @@ -563,6 +563,8 @@ MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD = DEGREES_TO_RADIANS * MAX_LATERAL_PINKY_CAMERA_ANGLE, MAX_CAMERA_MINI_ANGLE = 30, MAX_CAMERA_MINI_ANGLE_COS = Math.cos(MAX_CAMERA_MINI_ANGLE * DEGREES_TO_RADIANS), + SHOWING_DELAY = 1000, // ms + lastInvisible = [0, 0], HIDING_DELAY = 1000, // ms lastVisible = [0, 0], @@ -609,7 +611,8 @@ lateralHandVector, medialAngle, lateralAngle, - cameraToMini; + cameraToMini, + now; // Shouldn't show mini tablet if hand isn't being controlled. pose = Controller.getPoseValue(hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand); @@ -673,11 +676,19 @@ cameraToMini = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation)); show = show && (cameraToMini > MAX_CAMERA_MINI_ANGLE_COS); + // Delay showing for a while after it would otherwise be shown, unless it was showing on the other hand. + now = Date.now(); + if (show) { + show = now - lastInvisible[hand] >= SHOWING_DELAY || now - lastVisible[otherHand(hand)] <= HIDING_DELAY; + } else { + lastInvisible[hand] = now; + } + // Persist showing for a while after it would otherwise be hidden. if (show) { - lastVisible[hand] = Date.now(); + lastVisible[hand] = now; } else { - show = Date.now() - lastVisible[hand] <= HIDING_DELAY; + show = now - lastVisible[hand] <= HIDING_DELAY; } } From b24c4827433eaae0c1e6fa1746f7f0f1ac3a70b9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 16 Nov 2018 16:29:57 +1300 Subject: [PATCH 06/13] Terminate Create far grab etc. upon laser intersecting tablet --- .../controllerModules/inEditMode.js | 42 +++++++++++++++---- .../system/libraries/entitySelectionTool.js | 5 ++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 6adfa88fb2..5d0b64606d 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -20,6 +20,7 @@ Script.include("/~/system/libraries/utils.js"); var MARGIN = 25; function InEditMode(hand) { this.hand = hand; + this.running = false; this.triggerClicked = false; this.selectedTarget = null; this.reticleMinX = MARGIN; @@ -62,25 +63,27 @@ Script.include("/~/system/libraries/utils.js"); return point2d; }; + this.ENTITY_TOOL_UPDATES_CHANNEL = "entityToolUpdates"; + this.sendPickData = function(controllerData) { if (controllerData.triggerClicks[this.hand]) { var hand = this.hand === RIGHT_HAND ? Controller.Standard.RightHand : Controller.Standard.LeftHand; if (!this.triggerClicked) { this.selectedTarget = controllerData.rayPicks[this.hand]; if (!this.selectedTarget.intersects) { - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "clearSelection", hand: hand })); } else { if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "selectEntity", entityID: this.selectedTarget.objectID, hand: hand })); } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "selectOverlay", overlayID: this.selectedTarget.objectID, hand: hand @@ -102,7 +105,7 @@ Script.include("/~/system/libraries/utils.js"); var desktopWindow = Window.isPointOnDesktopWindow(point2d); var tablet = this.pointingAtTablet(rayPick.objectID); var rightHand = this.hand === RIGHT_HAND; - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "pointingAt", desktopWindow: desktopWindow, tablet: tablet, @@ -110,7 +113,27 @@ Script.include("/~/system/libraries/utils.js"); })); }; + this.runModule = function() { + if (!this.running) { + Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ + method: "moduleRunning", + hand: this.hand, + running: true + })); + this.running = true; + } + return makeRunningValues(true, [], []); + }; + this.exitModule = function() { + if (this.running) { + Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ + method: "moduleRunning", + hand: this.hand, + running: false + })); + this.running = false; + } return makeRunningValues(false, [], []); }; @@ -120,13 +143,15 @@ Script.include("/~/system/libraries/utils.js"); this.triggerClicked = false; } Messages.sendLocalMessage('Hifi-unhighlight-all', ''); - return makeRunningValues(true, [], []); + return this.runModule(); } this.triggerClicked = false; - return makeRunningValues(false, [], []); + return this.exitModule(); }; this.run = function(controllerData) { + + // Tablet stylus. var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTabletStylusInput" : "LeftTabletStylusInput"); if (tabletStylusInput) { @@ -136,6 +161,7 @@ Script.include("/~/system/libraries/utils.js"); } } + // Tablet surface. var webLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); if (webLaser) { @@ -147,6 +173,7 @@ Script.include("/~/system/libraries/utils.js"); } } + // HUD overlay. if (!controllerData.triggerClicks[this.hand]) { // Don't grab if trigger pressed when laser starts intersecting. var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightHudOverlayPointer" : "LeftHudOverlayPointer"); @@ -168,6 +195,7 @@ Script.include("/~/system/libraries/utils.js"); } } + // Teleport. var teleport = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter"); if (teleport) { var teleportReady = teleport.isReady(controllerData); @@ -176,8 +204,6 @@ Script.include("/~/system/libraries/utils.js"); } } - var stopRunning = false; - if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0)) { var stopRunning = false; controllerData.nearbyOverlayIDs[this.hand].forEach(function(overlayID) { diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 4552ed27fb..191a961228 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -58,7 +58,10 @@ SelectionManager = (function() { return; } - if (messageParsed.method === "selectEntity") { + if (messageParsed.method === "moduleRunning") { + // Terminate any current laser or mouse action. + SelectionDisplay.mouseReleaseEvent({}); + } else if (messageParsed.method === "selectEntity") { if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) { if (wantDebug) { print("setting selection to " + messageParsed.entityID); From 44efd18882ee8454a1c9c27d10f659b049a001e9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 21 Nov 2018 08:38:30 +1300 Subject: [PATCH 07/13] Make Create and Shapes lasers ignore tablet while editing --- .../controllers/controllerDispatcher.js | 33 ++++++++++++++++--- .../controllerModules/inEditMode.js | 17 ---------- .../system/libraries/entitySelectionTool.js | 5 +-- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index b657faefba..a393205b5b 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -12,7 +12,7 @@ LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, - PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE + PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE, HIFI_EDIT_MANIPULATION_CHANNEL */ controllerDispatcherPlugins = {}; @@ -427,9 +427,19 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; + this.leftBlacklistTabletIDs = []; + this.rightBlacklistTabletIDs = []; + + this.setLeftBlacklist = function () { + Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist.concat(_this.leftBlacklistTabletIDs)); + }; + this.setRightBlacklist = function () { + Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist.concat(_this.rightBlacklistTabletIDs)); + }; + this.setBlacklist = function() { - Pointers.setIgnoreItems(_this.leftPointer, this.blacklist); - Pointers.setIgnoreItems(_this.rightPointer, this.blacklist); + _this.setLeftBlacklist(); + _this.setRightBlacklist(); }; var MAPPING_NAME = "com.highfidelity.controllerDispatcher"; @@ -493,7 +503,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_NONCOLLIDABLE, enabled: true }); - this.handleHandMessage = function(channel, data, sender) { + this.handleMessage = function (channel, data, sender) { var message; if (sender === MyAvatar.sessionUUID) { try { @@ -514,6 +524,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.setBlacklist(); } } + } else if (channel === HIFI_EDIT_MANIPULATION_CHANNEL) { + message = JSON.parse(data); + var tabletIDs = message.action === "startEdit" ? + [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : []; + if (message.hand === Controller.Standard.LeftHand) { + _this.leftBlacklistTabletIDs = tabletIDs; + _this.setLeftBlacklist(); + } else if (message.hand === Controller.Standard.RightHand) { + _this.rightBlacklistTabletIDs = tabletIDs; + _this.setRightBlacklist(); + } } } catch (e) { print("WARNING: handControllerGrab.js -- error parsing message: " + data); @@ -554,7 +575,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var controllerDispatcher = new ControllerDispatcher(); Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); - Messages.messageReceived.connect(controllerDispatcher.handleHandMessage); + Messages.subscribe(HIFI_EDIT_MANIPULATION_CHANNEL); + Messages.messageReceived.connect(controllerDispatcher.handleMessage); + Script.scriptEnding.connect(controllerDispatcher.cleanup); Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS); }()); diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 5d0b64606d..3a1b835146 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -20,7 +20,6 @@ Script.include("/~/system/libraries/utils.js"); var MARGIN = 25; function InEditMode(hand) { this.hand = hand; - this.running = false; this.triggerClicked = false; this.selectedTarget = null; this.reticleMinX = MARGIN; @@ -114,26 +113,10 @@ Script.include("/~/system/libraries/utils.js"); }; this.runModule = function() { - if (!this.running) { - Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ - method: "moduleRunning", - hand: this.hand, - running: true - })); - this.running = true; - } return makeRunningValues(true, [], []); }; this.exitModule = function() { - if (this.running) { - Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ - method: "moduleRunning", - hand: this.hand, - running: false - })); - this.running = false; - } return makeRunningValues(false, [], []); }; diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 191a961228..4552ed27fb 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -58,10 +58,7 @@ SelectionManager = (function() { return; } - if (messageParsed.method === "moduleRunning") { - // Terminate any current laser or mouse action. - SelectionDisplay.mouseReleaseEvent({}); - } else if (messageParsed.method === "selectEntity") { + if (messageParsed.method === "selectEntity") { if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) { if (wantDebug) { print("setting selection to " + messageParsed.entityID); From c3a0805db1eadb9386297452b2a8692296c77cd3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 21 Nov 2018 10:28:46 +1300 Subject: [PATCH 08/13] Make far grab ignore tablet while grabbing an entity --- .../farActionGrabEntityDynOnly.js | 14 +++++++++----- .../controllerModules/farParentGrabEntity.js | 17 +++++++++-------- .../controllers/controllerModules/farTrigger.js | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js index f983ed1e7d..0ba3dd6e6b 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js @@ -48,6 +48,7 @@ Script.include("/~/system/libraries/controllers.js"); function FarActionGrabEntity(hand) { this.hand = hand; + this.grabbing = false; this.grabbedThingID = null; this.targetObject = null; this.actionID = null; // action this script created... @@ -151,6 +152,7 @@ Script.include("/~/system/libraries/controllers.js"); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); this.previousRoomControllerPosition = roomControllerPosition; + this.grabbing = true; }; this.continueDistanceHolding = function(controllerData) { @@ -246,6 +248,7 @@ Script.include("/~/system/libraries/controllers.js"); this.grabbedThingID = null; this.targetObject = null; this.potentialEntityWithContextOverlay = false; + this.grabbing = false; }; this.updateRecommendedArea = function() { @@ -357,8 +360,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function (controllerData) { - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || - this.notPointingAtEntity(controllerData) || this.targetIsNull()) { + if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { this.endFarGrabAction(); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); @@ -375,10 +377,12 @@ Script.include("/~/system/libraries/controllers.js"); this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay", - this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight" + this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity" ]; + if (!this.grabbing) { + nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); + nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); + } var nearGrabReadiness = []; for (var i = 0; i < nearGrabNames.length; i++) { diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index f85869aa7f..c023c4032d 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -47,6 +47,7 @@ Script.include("/~/system/libraries/controllers.js"); function FarParentGrabEntity(hand) { this.hand = hand; + this.grabbing = false; this.targetEntityID = null; this.targetObject = null; this.previouslyUnhooked = {}; @@ -453,8 +454,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function (controllerData) { - if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || - this.notPointingAtEntity(controllerData) || this.targetIsNull()) { + if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { this.endFarParentGrab(controllerData); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); this.highlightedEntity = null; @@ -470,10 +470,12 @@ Script.include("/~/system/libraries/controllers.js"); this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay", - this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight" + this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity" ]; + if (!this.grabbing) { + nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); + nearGrabNames.push(this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); + } var nearGrabReadiness = []; for (var i = 0; i < nearGrabNames.length; i++) { @@ -483,11 +485,10 @@ Script.include("/~/system/libraries/controllers.js"); } if (this.targetEntityID) { - // if we are doing a distance grab and the object or tablet gets close enough to the controller, + // if we are doing a distance grab and the object gets close enough to the controller, // stop the far-grab so the near-grab or equip can take over. for (var k = 0; k < nearGrabReadiness.length; k++) { - if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.targetEntityID || - HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) { + if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.targetEntityID)) { this.endFarParentGrab(controllerData); return makeRunningValues(false, [], []); } diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index 2b003e4732..c9c9d3deee 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -37,7 +37,7 @@ Script.include("/~/system/libraries/controllers.js"); this.getTargetProps = function (controllerData) { var targetEntity = controllerData.rayPicks[this.hand].objectID; - if (targetEntity) { + if (targetEntity && controllerData.rayPicks[this.hand].type === RayPick.INTERSECTED_ENTITY) { var targetProperties = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); if (entityWantsFarTrigger(targetProperties)) { return targetProperties; From 5e51ba051ab5dbdc13b063eff0735a4c2a63772f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 22 Nov 2018 11:12:22 +1300 Subject: [PATCH 09/13] Improve code responsibilities --- .../controllers/controllerDispatcher.js | 24 +++---- .../controllerModules/inEditMode.js | 32 +++++++++ .../controllerModules/inVREditMode.js | 65 ++++++++++++------- .../nearParentGrabOverlay.js | 43 +++++------- .../controllerModules/nearTabletHighlight.js | 43 +++++------- .../libraries/controllerDispatcherUtils.js | 4 -- .../system/libraries/entitySelectionTool.js | 20 +++--- 7 files changed, 127 insertions(+), 104 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index a393205b5b..a880eb8b10 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -12,7 +12,7 @@ LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers, - PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE, HIFI_EDIT_MANIPULATION_CHANNEL + PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE */ controllerDispatcherPlugins = {}; @@ -524,16 +524,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.setBlacklist(); } } - } else if (channel === HIFI_EDIT_MANIPULATION_CHANNEL) { - message = JSON.parse(data); - var tabletIDs = message.action === "startEdit" ? - [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : []; - if (message.hand === Controller.Standard.LeftHand) { - _this.leftBlacklistTabletIDs = tabletIDs; - _this.setLeftBlacklist(); - } else if (message.hand === Controller.Standard.RightHand) { - _this.rightBlacklistTabletIDs = tabletIDs; - _this.setRightBlacklist(); + + if (action === "tablet") { + var tabletIDs = message.blacklist + ? [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : []; + if (message.hand === LEFT_HAND) { + _this.leftBlacklistTabletIDs = tabletIDs; + _this.setLeftBlacklist(); + } else { + _this.rightBlacklistTabletIDs = tabletIDs; + _this.setRightBlacklist(); + } } } } catch (e) { @@ -575,7 +576,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var controllerDispatcher = new ControllerDispatcher(); Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); - Messages.subscribe(HIFI_EDIT_MANIPULATION_CHANNEL); Messages.messageReceived.connect(controllerDispatcher.handleMessage); Script.scriptEnding.connect(controllerDispatcher.cleanup); diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 3a1b835146..5709b19efe 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -20,6 +20,7 @@ Script.include("/~/system/libraries/utils.js"); var MARGIN = 25; function InEditMode(hand) { this.hand = hand; + this.isEditing = false; this.triggerClicked = false; this.selectedTarget = null; this.reticleMinX = MARGIN; @@ -212,6 +213,37 @@ Script.include("/~/system/libraries/utils.js"); enableDispatcherModule("LeftHandInEditMode", leftHandInEditMode); enableDispatcherModule("RightHandInEditMode", rightHandInEditMode); + var INEDIT_STATUS_CHANNEL = "Hifi-InEdit-Status"; + var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist"; + this.handleMessage = function (channel, data, sender) { + if (channel === INEDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) { + var message; + + try { + message = JSON.parse(data); + } catch (e) { + return; + } + + switch (message.method) { + case "editing": + if (message.hand === LEFT_HAND) { + leftHandInEditMode.isEditing = message.editing; + } else { + rightHandInEditMode.isEditing = message.editing; + } + Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({ + action: "tablet", + hand: message.hand, + blacklist: message.editing + })); + break; + } + } + }; + Messages.subscribe(INEDIT_STATUS_CHANNEL); + Messages.messageReceived.connect(this.handleMessage); + function cleanup() { disableDispatcherModule("LeftHandInEditMode"); disableDispatcherModule("RightHandInEditMode"); diff --git a/scripts/system/controllers/controllerModules/inVREditMode.js b/scripts/system/controllers/controllerModules/inVREditMode.js index 0c04918ab1..104e37d76c 100644 --- a/scripts/system/controllers/controllerModules/inVREditMode.js +++ b/scripts/system/controllers/controllerModules/inVREditMode.js @@ -18,7 +18,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); function InVREditMode(hand) { this.hand = hand; - this.disableModules = false; + this.isAppActive = false; + this.isEditing = false; this.running = false; var NO_HAND_LASER = -1; // Invalid hand parameter so that standard laser is not displayed. this.parameters = makeDispatcherModuleParameters( @@ -66,7 +67,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.isReady = function (controllerData) { - if (this.disableModules) { + if (this.isAppActive) { return makeRunningValues(true, [], []); } return makeRunningValues(false, [], []); @@ -74,14 +75,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.run = function (controllerData) { // Default behavior if disabling is not enabled. - if (!this.disableModules) { + if (!this.isAppActive) { return this.exitModule(); } // Tablet stylus. - var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND ? - "RightTabletStylusInput" : - "LeftTabletStylusInput"); + var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightTabletStylusInput" : "LeftTabletStylusInput"); if (tabletStylusInput) { var tabletReady = tabletStylusInput.isReady(controllerData); if (tabletReady.active) { @@ -90,9 +90,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } // Tablet surface. - var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? - "RightWebSurfaceLaserInput" : - "LeftWebSurfaceLaserInput"); + var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); if (overlayLaser) { var overlayLaserReady = overlayLaser.isReady(controllerData); var target = controllerData.rayPicks[this.hand].objectID; @@ -114,8 +113,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // HUD overlay. if (!controllerData.triggerClicks[this.hand]) { var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightHudOverlayPointer" - : "LeftHudOverlayPointer"); + ? "RightHudOverlayPointer" : "LeftHudOverlayPointer"); if (hudLaser) { var hudLaserReady = hudLaser.isReady(controllerData); if (hudLaserReady.active) { @@ -125,9 +123,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } // Teleport. - var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND ? - "RightTeleporter" : - "LeftTeleporter"); + var teleporter = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightTeleporter" : "LeftTeleporter"); if (teleporter) { var teleporterReady = teleporter.isReady(controllerData); if (teleporterReady.active) { @@ -145,19 +142,39 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); enableDispatcherModule("LeftHandInVREditMode", leftHandInVREditMode); enableDispatcherModule("RightHandInVREditMode", rightHandInVREditMode); - var INVREDIT_DISABLER_MESSAGE_CHANNEL = "Hifi-InVREdit-Disabler"; - this.handleMessage = function (channel, message, sender) { - if (sender === MyAvatar.sessionUUID && channel === INVREDIT_DISABLER_MESSAGE_CHANNEL) { - if (message === "both") { - leftHandInVREditMode.disableModules = true; - rightHandInVREditMode.disableModules = true; - } else if (message === "none") { - leftHandInVREditMode.disableModules = false; - rightHandInVREditMode.disableModules = false; + var INVREDIT_STATUS_CHANNEL = "Hifi-InVREdit-Status"; + var HAND_RAYPICK_BLACKLIST_CHANNEL = "Hifi-Hand-RayPick-Blacklist"; + this.handleMessage = function (channel, data, sender) { + if (channel === INVREDIT_STATUS_CHANNEL && sender === MyAvatar.sessionUUID) { + var message; + + try { + message = JSON.parse(data); + } catch (e) { + return; + } + + switch (message.method) { + case "active": + leftHandInVREditMode.isAppActive = message.active; + rightHandInVREditMode.isAppActive = message.active; + break; + case "editing": + if (message.hand === LEFT_HAND) { + leftHandInVREditMode.isEditing = message.editing; + } else { + rightHandInVREditMode.isEditing = message.editing; + } + Messages.sendLocalMessage(HAND_RAYPICK_BLACKLIST_CHANNEL, JSON.stringify({ + action: "tablet", + hand: message.hand, + blacklist: message.editing + })); + break; } } }; - Messages.subscribe(INVREDIT_DISABLER_MESSAGE_CHANNEL); + Messages.subscribe(INVREDIT_STATUS_CHANNEL); Messages.messageReceived.connect(this.handleMessage); this.cleanup = function () { diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index cbee8cabf7..e59b2e35ad 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -9,7 +9,7 @@ /* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings, - NEAR_GRAB_RADIUS, HMD, Uuid, HIFI_EDIT_MANIPULATION_CHANNEL + NEAR_GRAB_RADIUS, HMD, Uuid, getEnabledModuleByName */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -176,14 +176,23 @@ Script.include("/~/system/libraries/utils.js"); return null; }; - this.isEditing = false; - this.setIsEditing = function (editing) { - this.isEditing = editing; + this.isEditing = function () { + var inEditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightHandInEditMode" : "LeftHandInEditMode"); + if (inEditModeModule && inEditModeModule.isEditing) { + return true; + } + var inVREditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightHandInVREditMode" : "LeftHandInVREditMode"); + if (inVREditModeModule && inVREditModeModule.isEditing) { + return true; + } + return false; }; this.isReady = function (controllerData) { if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) - || this.isEditing) { + || this.isEditing()) { this.robbed = false; return makeRunningValues(false, [], []); } @@ -207,7 +216,7 @@ Script.include("/~/system/libraries/utils.js"); this.run = function (controllerData) { if ((controllerData.triggerClicks[this.hand] === 0 && controllerData.secondaryValues[this.hand] === 0) - || this.isEditing || !this.isGrabbedThingVisible()) { + || this.isEditing() || !this.isGrabbedThingVisible()) { this.endNearParentingGrabOverlay(); this.robbed = false; return makeRunningValues(false, [], []); @@ -235,28 +244,6 @@ Script.include("/~/system/libraries/utils.js"); enableDispatcherModule("LeftNearParentingGrabOverlay", leftNearParentingGrabOverlay); enableDispatcherModule("RightNearParentingGrabOverlay", rightNearParentingGrabOverlay); - function onMessageReceived(channel, data, senderID) { - var message; - - if (channel !== HIFI_EDIT_MANIPULATION_CHANNEL || senderID !== MyAvatar.sessionUUID) { - return; - } - - try { - message = JSON.parse(data); - } catch (e) { - return; - } - - if (message.hand === Controller.Standard.LeftHand) { - leftNearParentingGrabOverlay.setIsEditing(message.action === "startEdit"); - } else if (message.hand === Controller.Standard.RightHand) { - rightNearParentingGrabOverlay.setIsEditing(message.action === "startEdit"); - } - } - Messages.subscribe(HIFI_EDIT_MANIPULATION_CHANNEL); - Messages.messageReceived.connect(onMessageReceived); - function cleanup() { leftNearParentingGrabOverlay.cleanup(); rightNearParentingGrabOverlay.cleanup(); diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js index 3ced0a9e87..2e046f5dc6 100644 --- a/scripts/system/controllers/controllerModules/nearTabletHighlight.js +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -11,7 +11,7 @@ // /* global LEFT_HAND, RIGHT_HAND, makeDispatcherModuleParameters, makeRunningValues, enableDispatcherModule, - * disableDispatcherModule, HIFI_EDIT_MANIPULATION_CHANNEL */ + * disableDispatcherModule, getEnabledModuleByName */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -66,9 +66,18 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); 100 ); - this.isEditing = false; - this.setIsEditing = function (editing) { - this.isEditing = editing; + this.isEditing = function () { + var inEditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightHandInEditMode" : "LeftHandInEditMode"); + if (inEditModeModule && inEditModeModule.isEditing) { + return true; + } + var inVREditModeModule = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightHandInVREditMode" : "LeftHandInVREditMode"); + if (inVREditModeModule && inVREditModeModule.isEditing) { + return true; + } + return false; }; this.isNearTablet = function (controllerData) { @@ -76,7 +85,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.isReady = function (controllerData) { - if (!this.isEditing && this.isNearTablet(controllerData)) { + if (!this.isEditing() && this.isNearTablet(controllerData)) { return makeRunningValues(true, [], []); } setTabletNearGrabbable(this.hand, false); @@ -84,7 +93,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.run = function (controllerData) { - if (this.isEditing || !this.isNearTablet(controllerData)) { + if (this.isEditing() || !this.isNearTablet(controllerData)) { setTabletNearGrabbable(this.hand, false); return makeRunningValues(false, [], []); } @@ -116,28 +125,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); HMD.mountedChanged.connect(onDisplayModeChanged); onDisplayModeChanged(); - function onMessageReceived(channel, data, senderID) { - var message; - - if (channel !== HIFI_EDIT_MANIPULATION_CHANNEL || senderID !== MyAvatar.sessionUUID) { - return; - } - - try { - message = JSON.parse(data); - } catch (e) { - return; - } - - if (message.hand === Controller.Standard.LeftHand) { - leftNearTabletHighlight.setIsEditing(message.action === "startEdit"); - } else if (message.hand === Controller.Standard.RightHand) { - rightNearTabletHighlight.setIsEditing(message.action === "startEdit"); - } - } - Messages.subscribe(HIFI_EDIT_MANIPULATION_CHANNEL); - Messages.messageReceived.connect(onMessageReceived); - function cleanUp() { disableDispatcherModule("LeftNearTabletHighlight"); disableDispatcherModule("RightNearTabletHighlight"); diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index f7b997a897..e9d5255d28 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -24,7 +24,6 @@ HAPTIC_PULSE_DURATION:true, DISPATCHER_HOVERING_LIST:true, DISPATCHER_HOVERING_STYLE:true, - HIFI_EDIT_MANIPULATION_CHANNEL:true, Entities, makeDispatcherModuleParameters:true, makeRunningValues:true, @@ -150,8 +149,6 @@ DISPATCHER_PROPERTIES = [ "userData" ]; -HIFI_EDIT_MANIPULATION_CHANNEL = "HiFi-Edit-Manipulation"; - // priority -- a lower priority means the module will be asked sooner than one with a higher priority in a given update step // activitySlots -- indicates which "slots" must not yet be in use for this module to start // requiredDataForReady -- which "situation" parts this module looks at to decide if it will start @@ -593,7 +590,6 @@ if (typeof module !== 'undefined') { TRIGGER_OFF_VALUE: TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE: TRIGGER_ON_VALUE, DISPATCHER_HOVERING_LIST: DISPATCHER_HOVERING_LIST, - HIFI_EDIT_MANIPULATION_CHANNEL: HIFI_EDIT_MANIPULATION_CHANNEL, worldPositionToRegistrationFrameMatrix: worldPositionToRegistrationFrameMatrix }; } diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 4552ed27fb..e1427b0a51 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -14,7 +14,7 @@ // /* global SelectionManager, SelectionDisplay, grid, rayPlaneIntersection, rayPlaneIntersection2, pushCommandForSelections, - getMainTabletIDs, getControllerWorldLocation, TRIGGER_ON_VALUE, HIFI_EDIT_MANIPULATION_CHANNEL */ + getMainTabletIDs, getControllerWorldLocation, TRIGGER_ON_VALUE */ const SPACE_LOCAL = "local"; const SPACE_WORLD = "world"; @@ -639,6 +639,8 @@ SelectionDisplay = (function() { ROLL: 2 }; + const INEDIT_STATUS_CHANNEL = "Hifi-InEdit-Status"; + /** * The current space mode, this could have been a forced space mode since we do not support multi selection while in * local space mode. @@ -1118,11 +1120,12 @@ SelectionDisplay = (function() { activeTool = hitTool; that.clearDebugPickPlane(); if (activeTool.onBegin) { - Messages.sendLocalMessage(HIFI_EDIT_MANIPULATION_CHANNEL, JSON.stringify({ - action: "startEdit", - hand: that.triggeredHand - })); that.editingHand = that.triggeredHand; + Messages.sendLocalMessage(INEDIT_STATUS_CHANNEL, JSON.stringify({ + method: "editing", + hand: that.editingHand === Controller.Standard.LeftHand ? LEFT_HAND : RIGHT_HAND, + editing: true + })); activeTool.onBegin(event, pickRay, results); } else { print("ERROR: entitySelectionTool.mousePressEvent - ActiveTool(" + activeTool.mode + ") missing onBegin"); @@ -1271,9 +1274,10 @@ SelectionDisplay = (function() { if (wantDebug) { print(" Triggering ActiveTool(" + activeTool.mode + ")'s onEnd"); } - Messages.sendLocalMessage(HIFI_EDIT_MANIPULATION_CHANNEL, JSON.stringify({ - action: "finishEdit", - hand: that.editingHand + Messages.sendLocalMessage(INEDIT_STATUS_CHANNEL, JSON.stringify({ + method: "editing", + hand: that.editingHand === Controller.Standard.LeftHand ? LEFT_HAND : RIGHT_HAND, + editing: false })); that.editingHand = NO_HAND; activeTool.onEnd(event); From aa952e91429af6ee05224aa5c9815c4e2f163be1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 6 Dec 2018 15:24:03 +1300 Subject: [PATCH 10/13] Fix mini tablet visibility angle calculations --- scripts/system/miniTablet.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/scripts/system/miniTablet.js b/scripts/system/miniTablet.js index a933116dc8..780dacf85e 100644 --- a/scripts/system/miniTablet.js +++ b/scripts/system/miniTablet.js @@ -567,9 +567,7 @@ SHOWING_DELAY = 1000, // ms lastInvisible = [0, 0], HIDING_DELAY = 1000, // ms - lastVisible = [0, 0], - - HALF_PI = Math.PI / 2; + lastVisible = [0, 0]; function enterMiniDisabled() { @@ -608,8 +606,12 @@ handOrientation, miniPosition, miniToCameraDirection, + normalHandVector, medialHandVector, lateralHandVector, + normalDot, + medialDot, + lateralDot, medialAngle, lateralAngle, cameraToMini, @@ -664,14 +666,18 @@ miniToCameraDirection = Vec3.normalize(Vec3.subtract(Camera.position, miniPosition)); // Mini tablet aimed toward camera? - medialHandVector = Vec3.multiplyQbyV(handOrientation, Vec3.UNIT_NEG_Y); + medialHandVector = Vec3.multiplyQbyV(handOrientation, Vec3.UNIT_Y); lateralHandVector = Vec3.multiplyQbyV(handOrientation, hand === LEFT_HAND ? Vec3.UNIT_X : Vec3.UNIT_NEG_X); - medialAngle = Math.acos(Vec3.dot(medialHandVector, miniToCameraDirection)) - HALF_PI; - lateralAngle = Math.acos(Vec3.dot(lateralHandVector, miniToCameraDirection)) - HALF_PI; + normalHandVector = Vec3.multiplyQbyV(handOrientation, Vec3.UNIT_Z); + medialDot = Vec3.dot(medialHandVector, miniToCameraDirection); + lateralDot = Vec3.dot(lateralHandVector, miniToCameraDirection); + normalDot = Vec3.dot(normalHandVector, miniToCameraDirection); + medialAngle = Math.atan2(medialDot, normalDot); + lateralAngle = Math.atan2(lateralDot, normalDot); show = -MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD <= medialAngle && medialAngle <= MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD - && -MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD <= lateralAngle - && lateralAngle <= MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD; + && -MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD <= lateralAngle + && lateralAngle <= MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD; // Camera looking at mini tablet? cameraToMini = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation)); From 72a91668a5d43f3e6245e26e30645192d90e4de4 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Sat, 13 Oct 2018 00:14:33 +0300 Subject: [PATCH 11/13] FB19219 Make avatarapp to handle wearables update via drag&drop --- libraries/entities/src/EntityItem.cpp | 5 ++ libraries/entities/src/EntityItem.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 14 +++++ .../entities/src/EntityScriptingInterface.h | 27 ++++++++ libraries/entities/src/EntityTree.cpp | 1 + libraries/entities/src/EntityTree.h | 1 + libraries/entities/src/ModelEntityItem.cpp | 5 ++ libraries/entities/src/ModelEntityItem.h | 1 + scripts/system/avatarapp.js | 61 ++++++++++++++----- 9 files changed, 101 insertions(+), 16 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5855306994..35c491a331 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3277,4 +3277,9 @@ void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properti properties.setEntityHostType(getEntityHostType()); properties.setOwningAvatarID(getOwningAvatarID()); setLastBroadcast(now); // for debug/physics status icons +} + +bool EntityItem::isWearable() const { + return isVisible() && getParentJointIndex() != INVALID_JOINT_INDEX + && (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); } \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 8c78dd1cd6..eb1cdf24e4 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -489,7 +489,7 @@ public: void scriptHasUnloaded(); void setScriptHasFinishedPreload(bool value); bool isScriptPreloadFinished(); - + virtual bool isWearable() const; bool isDomainEntity() const { return _hostType == entity::HostType::DOMAIN; } bool isAvatarEntity() const { return _hostType == entity::HostType::AVATAR; } bool isLocalEntity() const { return _hostType == entity::HostType::LOCAL; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4a634899c4..1b1853762b 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -114,6 +114,8 @@ bool EntityScriptingInterface::canReplaceContent() { void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { if (_entityTree) { + disconnect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity); + disconnect(_entityTree.get(), &EntityTree::deletingEntityPointer, this, &EntityScriptingInterface::onDeletingEntity); disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); disconnect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); disconnect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); @@ -122,6 +124,8 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { _entityTree = elementTree; if (_entityTree) { + connect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity, Qt::DirectConnection); + connect(_entityTree.get(), &EntityTree::deletingEntityPointer, this, &EntityScriptingInterface::onDeletingEntity, Qt::DirectConnection); connect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); connect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); connect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); @@ -1060,7 +1064,17 @@ void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer } } +void EntityScriptingInterface::onAddingEntity(EntityItem* entity) { + if (entity->isWearable()) { + emit addingWearable(entity->getEntityItemID()); + } +} +void EntityScriptingInterface::onDeletingEntity(EntityItem* entity) { + if (entity->isWearable()) { + emit deletingWearable(entity->getEntityItemID()); + } +} QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { PROFILE_RANGE(script_entities, __FUNCTION__); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index ff1149fb06..0cea005ddd 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -1908,6 +1908,31 @@ signals: */ void addingEntity(const EntityItemID& entityID); + /**jsdoc + * Triggered when an 'wearable' entity is deleted. + * @function Entities.deletingWearable + * @param {Uuid} entityID - The ID of the 'wearable' entity deleted. + * @returns {Signal} + * @example Report when an 'wearable' entity is deleted. + * Entities.deletingWearable.connect(function (entityID) { + * print("Deleted wearable: " + entityID); + * }); + */ + void deletingWearable(const EntityItemID& entityID); + + /**jsdoc + * Triggered when an 'wearable' entity is added to Interface's local in-memory tree of entities it knows about. This may occur when + * 'wearable' entities are added to avatar + * @function Entities.addingWearable + * @param {Uuid} entityID - The ID of the 'wearable' entity added. + * @returns {Signal} + * @example Report when an 'wearable' entity is added. + * Entities.addingWearable.connect(function (entityID) { + * print("Added wearable: " + entityID); + * }); + */ + void addingWearable(const EntityItemID& entityID); + /**jsdoc * Triggered when you disconnect from a domain, at which time Interface's local in-memory tree of entities it knows about * is cleared. @@ -1938,6 +1963,8 @@ protected: private slots: void handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode); + void onAddingEntity(EntityItem* entity); + void onDeletingEntity(EntityItem* entity); private: bool actionWorker(const QUuid& entityID, std::function actor); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index b23be66ade..dd020da5a0 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -305,6 +305,7 @@ void EntityTree::postAddEntity(EntityItemPointer entity) { fixupNeedsParentFixups(); emit addingEntity(entity->getEntityItemID()); + emit addingEntityPointer(entity.get()); } bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index c6a590ec71..d7f93b1eb2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -309,6 +309,7 @@ signals: void deletingEntity(const EntityItemID& entityID); void deletingEntityPointer(EntityItem* entityID); void addingEntity(const EntityItemID& entityID); + void addingEntityPointer(EntityItem* entityID); void editingEntityPointer(const EntityItemPointer& entityID); void entityScriptChanging(const EntityItemID& entityItemID, const bool reload); void entityServerScriptChanging(const EntityItemID& entityItemID, const bool reload); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index b4b00e57a7..caa67ade9a 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -519,6 +519,11 @@ QVector ModelEntityItem::getJointTranslationsSet() const { return result; } +bool ModelEntityItem::isWearable() const +{ + return isVisible() && (getParentJointIndex() != INVALID_JOINT_INDEX || getRelayParentJoints()) + && (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); +} bool ModelEntityItem::hasModel() const { return resultWithReadLock([&] { diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 5ca3e2caa1..3de1ebdbdc 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -123,6 +123,7 @@ public: QVector getJointTranslations() const; QVector getJointTranslationsSet() const; + virtual bool isWearable() const override; private: void setAnimationSettings(const QString& value); // only called for old bitstream format bool applyNewAnimationProperties(AnimationPropertyGroup newProperties); diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 81a6447aae..65abf791a5 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -69,12 +69,12 @@ function getMyAvatarSettings() { } } -function updateAvatarWearables(avatar, bookmarkAvatarName, callback) { +function updateAvatarWearables(avatar, callback) { executeLater(function() { var wearables = getMyAvatarWearables(); avatar[ENTRY_AVATAR_ENTITIES] = wearables; - sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables, 'avatarName' : bookmarkAvatarName}) + sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables}) if(callback) callback(); @@ -188,7 +188,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See sendToQml(message) break; case 'selectAvatar': + Entities.addingWearable.disconnect(onAddingWearable); + Entities.deletingWearable.disconnect(onDeletingWearable); AvatarBookmarks.loadBookmark(message.name); + Entities.addingWearable.connect(onAddingWearable); + Entities.deletingWearable.connect(onDeletingWearable); break; case 'deleteAvatar': AvatarBookmarks.removeBookmark(message.name); @@ -223,7 +227,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See // revert changes using snapshot of wearables if(currentAvatarWearablesBackup !== null) { AvatarBookmarks.updateAvatarEntities(currentAvatarWearablesBackup); - updateAvatarWearables(currentAvatar, message.avatarName); + updateAvatarWearables(currentAvatar); } } else { sendToQml({'method' : 'updateAvatarInBookmarks'}); @@ -256,8 +260,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See parentJointIndex: hipsIndex }; + Entities.addingWearable.disconnect(onAddingWearable); var entityID = Entities.addEntity(properties, true); - updateAvatarWearables(currentAvatar, message.avatarName, function() { + Entities.addingWearable.connect(onAddingWearable); + + updateAvatarWearables(currentAvatar, function() { onSelectedEntity(entityID); }); break; @@ -265,8 +272,12 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See ensureWearableSelected(message.entityID); break; case 'deleteWearable': + + Entities.deletingWearable.disconnect(onDeletingWearable); Entities.deleteEntity(message.entityID); - updateAvatarWearables(currentAvatar, message.avatarName); + Entities.deletingWearable.connect(onDeletingWearable); + + updateAvatarWearables(currentAvatar); break; case 'changeDisplayName': if (MyAvatar.displayName !== message.displayName) { @@ -380,6 +391,18 @@ function onSelectedEntity(entityID, pointerEvent) { } } +function onAddingWearable(entityID) { + updateAvatarWearables(currentAvatar, function() { + sendToQml({'method' : 'updateAvatarInBookmarks'}); + }); +} + +function onDeletingWearable(entityID) { + updateAvatarWearables(currentAvatar, function() { + sendToQml({'method' : 'updateAvatarInBookmarks'}); + }); +} + function handleWearableMessages(channel, message, sender) { if (channel !== 'Hifi-Object-Manipulation') { return; @@ -485,6 +508,8 @@ function off() { AvatarBookmarks.bookmarkDeleted.disconnect(onBookmarkDeleted); AvatarBookmarks.bookmarkAdded.disconnect(onBookmarkAdded); + Entities.addingWearable.disconnect(onAddingWearable); + Entities.deletingWearable.disconnect(onDeletingWearable); MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); @@ -495,16 +520,23 @@ function off() { } function on() { - AvatarBookmarks.bookmarkLoaded.connect(onBookmarkLoaded); - AvatarBookmarks.bookmarkDeleted.connect(onBookmarkDeleted); - AvatarBookmarks.bookmarkAdded.connect(onBookmarkAdded); - MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); - MyAvatar.dominantHandChanged.connect(onDominantHandChanged); - MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); - MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); - MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); + if (!isWired) { // It is not ok to connect these twice, hence guard. + isWired = true; + + AvatarBookmarks.bookmarkLoaded.connect(onBookmarkLoaded); + AvatarBookmarks.bookmarkDeleted.connect(onBookmarkDeleted); + AvatarBookmarks.bookmarkAdded.connect(onBookmarkAdded); + + Entities.addingWearable.connect(onAddingWearable); + Entities.deletingWearable.connect(onDeletingWearable); + MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); + MyAvatar.dominantHandChanged.connect(onDominantHandChanged); + MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); + MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); + MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); + MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); + } } function onTabletButtonClicked() { @@ -514,7 +546,6 @@ function onTabletButtonClicked() { } else { ContextOverlay.enabled = false; tablet.loadQMLSource(AVATARAPP_QML_SOURCE); - isWired = true; } } var hasEventBridge = false; From 600d09e533e2c3c27ff9dbdf5c6ee44c31b36c1e Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Mon, 19 Nov 2018 00:53:51 +0530 Subject: [PATCH 12/13] relax 'isWearable()' condition to match latest changes in 'master' --- libraries/entities/src/EntityItem.cpp | 3 +-- libraries/entities/src/ModelEntityItem.cpp | 6 ------ libraries/entities/src/ModelEntityItem.h | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 35c491a331..94d0024fd5 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3280,6 +3280,5 @@ void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properti } bool EntityItem::isWearable() const { - return isVisible() && getParentJointIndex() != INVALID_JOINT_INDEX - && (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); + return isVisible() && (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); } \ No newline at end of file diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index caa67ade9a..e68e287ee2 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -519,12 +519,6 @@ QVector ModelEntityItem::getJointTranslationsSet() const { return result; } -bool ModelEntityItem::isWearable() const -{ - return isVisible() && (getParentJointIndex() != INVALID_JOINT_INDEX || getRelayParentJoints()) - && (getParentID() == DependencyManager::get()->getSessionUUID() || getParentID() == AVATAR_SELF_ID); -} - bool ModelEntityItem::hasModel() const { return resultWithReadLock([&] { return !_modelURL.isEmpty(); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 3de1ebdbdc..5ca3e2caa1 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -123,7 +123,6 @@ public: QVector getJointTranslations() const; QVector getJointTranslationsSet() const; - virtual bool isWearable() const override; private: void setAnimationSettings(const QString& value); // only called for old bitstream format bool applyNewAnimationProperties(AnimationPropertyGroup newProperties); From 177a94b9a990a79056d090c9aaa3ef7fd5cfc5c2 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 6 Dec 2018 14:01:29 -0800 Subject: [PATCH 13/13] fix realod all scripts functionality --- libraries/script-engine/src/ScriptEngines.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 399ccf1919..e198502b3d 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -31,6 +31,8 @@ static const QUrl DEFAULT_SCRIPTS_LOCATION { "file:///~//defaultScripts.js" }; // Using a QVariantList so this is human-readable in the settings file static Setting::Handle runningScriptsHandle(SETTINGS_KEY, { QVariant(DEFAULT_SCRIPTS_LOCATION) }); +const int RELOAD_ALL_SCRIPTS_TIMEOUT = 1000; + ScriptsModel& getScriptsModel() { static ScriptsModel scriptsModel; @@ -386,15 +388,10 @@ void ScriptEngines::stopAllScripts(bool restart) { // queue user scripts if restarting if (restart && scriptEngine->isUserLoaded()) { _isReloading = true; - bool lastScript = (it == _scriptEnginesHash.constEnd() - 1); ScriptEngine::Type type = scriptEngine->getType(); - connect(scriptEngine.data(), &ScriptEngine::finished, this, [this, type, lastScript] (QString scriptName) { + connect(scriptEngine.data(), &ScriptEngine::finished, this, [this, type] (QString scriptName) { reloadScript(scriptName, true)->setType(type); - - if (lastScript) { - _isReloading = false; - } }); } @@ -404,6 +401,9 @@ void ScriptEngines::stopAllScripts(bool restart) { if (restart) { qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading"; + QTimer::singleShot(RELOAD_ALL_SCRIPTS_TIMEOUT, this, [&] { + _isReloading = false; + }); emit scriptsReloading(); } }