diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 9469b59a95..3826222666 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -5,11 +5,12 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/*jslint bitwise: true */ +/* jslint bitwise: true */ /* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation, RayPick, - controllerDispatcherPlugins, controllerDispatcherPluginsNeedSort, entityIsGrabbable, - LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES + controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true, entityIsGrabbable:true, + LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, + getGrabPointSphereOffset */ controllerDispatcherPlugins = {}; @@ -21,18 +22,16 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); (function() { var _this = this; - - var NEAR_MIN_RADIUS = 0.1; var NEAR_MAX_RADIUS = 1.0; var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ; - var lastInterval = Date.now(); - var intervalCount = 0; - var totalDelta = 0; - var totalVariance = 0; - var highVarianceCount = 0; - var veryhighVarianceCount = 0; + this.lastInterval = Date.now(); + this.intervalCount = 0; + this.totalDelta = 0; + this.totalVariance = 0; + this.highVarianceCount = 0; + this.veryhighVarianceCount = 0; this.tabletID = null; this.blacklist = []; @@ -63,7 +62,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); this.unmarkSlotsForPluginName = function (runningPluginName) { // this is used to free activity-slots when a plugin is deactivated while it's running. for (var activitySlot in _this.activitySlots) { - if (activitySlot.hasOwnProperty(activitySlot) && _this.activitySlots[activitySlot] == runningPluginName) { + if (activitySlot.hasOwnProperty(activitySlot) && _this.activitySlots[activitySlot] === runningPluginName) { _this.activitySlots[activitySlot] = false; } } @@ -106,23 +105,23 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); }; this.updateTimings = function () { - intervalCount++; + _this.intervalCount++; var thisInterval = Date.now(); - var deltaTimeMsec = thisInterval - lastInterval; + var deltaTimeMsec = thisInterval - _this.lastInterval; var deltaTime = deltaTimeMsec / 1000; - lastInterval = thisInterval; + _this.lastInterval = thisInterval; - totalDelta += deltaTimeMsec; + _this.totalDelta += deltaTimeMsec; var variance = Math.abs(deltaTimeMsec - BASIC_TIMER_INTERVAL_MS); - totalVariance += variance; + _this.totalVariance += variance; if (variance > 1) { - highVarianceCount++; + _this.highVarianceCount++; } if (variance > 5) { - veryhighVarianceCount++; + _this.veryhighVarianceCount++; } return deltaTime; @@ -132,13 +131,12 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); if (HMD.tabletID !== _this.tabletID) { RayPick.setIgnoreOverlays(_this.leftControllerRayPick, [HMD.tabletID]); RayPick.setIgnoreOverlays(_this.rightControllerRayPick, [HMD.tabletID]); - tabletIgnored = true } - } + }; this.update = function () { - var deltaTime = this.updateTimings(); - this.setIgnoreTablet() + var deltaTime = this.updateTimings(); + this.setIgnoreTablet(); if (controllerDispatcherPluginsNeedSort) { this.orderedPluginNames = []; @@ -167,8 +165,10 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); controllerDispatcherPluginsNeedSort = false; } - var controllerLocations = [_this.dataGatherers.leftControllerLocation(), - _this.dataGatherers.rightControllerLocation()]; + var controllerLocations = [ + _this.dataGatherers.leftControllerLocation(), + _this.dataGatherers.rightControllerLocation() + ]; // find 3d overlays near each hand var nearbyOverlayIDs = []; @@ -221,7 +221,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); length: 1000 }; - if (rayPicks[h].type == RayPick.INTERSECTED_ENTITY) { + if (rayPicks[h].type === RayPick.INTERSECTED_ENTITY) { // XXX check to make sure this one isn't already in nearbyEntityProperties? if (rayPicks[h].distance < NEAR_GRAB_PICK_RADIUS) { var nearEntityID = rayPicks[h].objectID; @@ -259,7 +259,6 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); var candidatePlugin = controllerDispatcherPlugins[orderedPluginName]; if (_this.slotsAreAvailableForPlugin(candidatePlugin)) { - //print(orderedPluginName); var readiness = candidatePlugin.isReady(controllerData, deltaTime); if (readiness.active) { // this plugin will start. add it to the list of running plugins and mark the @@ -297,7 +296,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); this.setBlacklist = function() { RayPick.setIgnoreEntities(_this.leftControllerRayPick, this.blacklist); RayPick.setIgnoreEntities(_this.rightControllerRayPick, this.blacklist); - + }; var MAPPING_NAME = "com.highfidelity.controllerDispatcher"; @@ -314,19 +313,6 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); Controller.enableMapping(MAPPING_NAME); - - this.mouseRayPick = RayPick.createRayPick({ - joint: "Mouse", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, - enabled: true - }); - - this.mouseHudRayPick = RayPick.createRayPick({ - joint: "Mouse", - filter: RayPick.PICK_HUD, - enabled: true - }); - this.leftControllerRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_LEFTHAND", filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, @@ -357,7 +343,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); }); this.handleHandMessage = function(channel, message, sender) { - var data + var data; if (sender === MyAvatar.sessionUUID) { try { if (channel === 'Hifi-Hand-RayPick-Blacklist') { @@ -365,33 +351,29 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); var action = data.action; var id = data.id; var index = this.blacklis.indexOf(id); - + if (action === 'add' && index === -1) { this.blacklist.push(id); - //this.setBlacklist(); + this.setBlacklist(); } - + if (action === 'remove') { if (index > -1) { - blacklist.splice(index, 1); - //this.setBlacklist(); + this.blacklist.splice(index, 1); + this.setBlacklist(); } } } - + } catch (e) { print("WARNING: handControllerGrab.js -- error parsing Hifi-Hand-RayPick-Blacklist message: " + message); } } }; - - - this.cleanup = function () { Script.update.disconnect(_this.update); Controller.disableMapping(MAPPING_NAME); - // RayPick.removeRayPick(_this.mouseRayPick); RayPick.removeRayPick(_this.leftControllerRayPick); RayPick.removeRayPick(_this.rightControllerRayPick); RayPick.removeRayPick(_this.rightControllerHudRayPick); diff --git a/scripts/system/controllers/controllerDispatcherUtils.js b/scripts/system/controllers/controllerDispatcherUtils.js index 808623fc79..773f79754d 100644 --- a/scripts/system/controllers/controllerDispatcherUtils.js +++ b/scripts/system/controllers/controllerDispatcherUtils.js @@ -6,37 +6,37 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global Camera, HMD, MyAvatar, controllerDispatcherPlugins, Quat, Vec3, Overlays, - MSECS_PER_SEC, LEFT_HAND, RIGHT_HAND, NULL_UUID, AVATAR_SELF_ID, FORBIDDEN_GRAB_TYPES, - HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, ZERO_VEC, ONE_VEC, DEFAULT_REGISTRATION_POINT, INCHES_TO_METERS, - TRIGGER_OFF_VALUE, - TRIGGER_ON_VALUE, - PICK_MAX_DISTANCE, - DEFAULT_SEARCH_SPHERE_DISTANCE, - NEAR_GRAB_PICK_RADIUS, - COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - COLORS_GRAB_DISTANCE_HOLD, - NEAR_GRAB_RADIUS, - DISPATCHER_PROPERTIES, +/* global Camera, HMD, MyAvatar, controllerDispatcherPlugins:true, Quat, Vec3, Overlays, + MSECS_PER_SEC:true , LEFT_HAND:true, RIGHT_HAND:true, NULL_UUID:true, AVATAR_SELF_ID:true, FORBIDDEN_GRAB_TYPES:true, + HAPTIC_PULSE_STRENGTH:true, HAPTIC_PULSE_DURATION:true, ZERO_VEC:true, ONE_VEC:true, DEFAULT_REGISTRATION_POINT:true, INCHES_TO_METERS:true, + TRIGGER_OFF_VALUE:true, + TRIGGER_ON_VALUE:true, + PICK_MAX_DISTANCE:true, + DEFAULT_SEARCH_SPHERE_DISTANCE:true, + NEAR_GRAB_PICK_RADIUS:true, + COLORS_GRAB_SEARCHING_HALF_SQUEEZE:true, + COLORS_GRAB_SEARCHING_FULL_SQUEEZE:true, + COLORS_GRAB_DISTANCE_HOLD:true, + NEAR_GRAB_RADIUS:true, + DISPATCHER_PROPERTIES:true, Entities, - makeDispatcherModuleParameters, - makeRunningValues, - enableDispatcherModule, - disableDispatcherModule, - getEnabledModuleByName, - getGrabbableData, - entityIsGrabbable, - entityIsDistanceGrabbable, - getControllerJointIndex, - propsArePhysical, - controllerDispatcherPluginsNeedSort, - projectOntoXYPlane, - projectOntoEntityXYPlane, - projectOntoOverlayXYPlane, - entityHasActions, - ensureDynamic, - findGroupParent + makeDispatcherModuleParameters:true, + makeRunningValues:true, + enableDispatcherModule:true, + disableDispatcherModule:true, + getEnabledModuleByName:true, + getGrabbableData:true, + entityIsGrabbable:true, + entityIsDistanceGrabbable:true, + getControllerJointIndex:true, + propsArePhysical:true, + controllerDispatcherPluginsNeedSort:true, + projectOntoXYPlane:true, + projectOntoEntityXYPlane:true, + projectOntoOverlayXYPlane:true, + entityHasActions:true, + ensureDynamic:true, + findGroupParent:true */ MSECS_PER_SEC = 1000.0; @@ -69,11 +69,8 @@ COLORS_GRAB_SEARCHING_HALF_SQUEEZE = { red: 10, green: 10, blue: 255 }; COLORS_GRAB_SEARCHING_FULL_SQUEEZE = { red: 250, green: 10, blue: 10 }; COLORS_GRAB_DISTANCE_HOLD = { red: 238, green: 75, blue: 214 }; - NEAR_GRAB_RADIUS = 0.1; - - DISPATCHER_PROPERTIES = [ "position", "registrationPoint", @@ -92,9 +89,6 @@ DISPATCHER_PROPERTIES = [ "userData" ]; - - - // 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 @@ -211,12 +205,12 @@ getControllerJointIndex = function (hand) { var controllerJointIndex = -1; if (Camera.mode === "first person") { controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ? - "_CONTROLLER_RIGHTHAND" : - "_CONTROLLER_LEFTHAND"); + "_CONTROLLER_RIGHTHAND" : + "_CONTROLLER_LEFTHAND"); } else if (Camera.mode === "third person") { controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ? - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); + "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : + "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); } return controllerJointIndex; @@ -229,19 +223,24 @@ propsArePhysical = function (props) { if (!props.dynamic) { return false; } - var isPhysical = (props.shapeType && props.shapeType != 'none'); + var isPhysical = (props.shapeType && props.shapeType !== 'none'); return isPhysical; }; projectOntoXYPlane = function (worldPos, position, rotation, dimensions, registrationPoint) { var invRot = Quat.inverse(rotation); var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(worldPos, position)); - var invDimensions = { x: 1 / dimensions.x, - y: 1 / dimensions.y, - z: 1 / dimensions.z }; + var invDimensions = { + x: 1 / dimensions.x, + y: 1 / dimensions.y, + z: 1 / dimensions.z + }; + var normalizedPos = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), registrationPoint); - return { x: normalizedPos.x * dimensions.x, - y: (1 - normalizedPos.y) * dimensions.y }; // flip y-axis + return { + x: normalizedPos.x * dimensions.x, + y: (1 - normalizedPos.y) * dimensions.y // flip y-axis + }; }; projectOntoEntityXYPlane = function (entityID, worldPos, props) { @@ -257,14 +256,14 @@ projectOntoOverlayXYPlane = function projectOntoOverlayXYPlane(overlayID, worldP if (dpi) { // Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale. var resolution = Overlays.getProperty(overlayID, "resolution"); - resolution.z = 1; // Circumvent divide-by-zero. + resolution.z = 1; // Circumvent divide-by-zero. var scale = Overlays.getProperty(overlayID, "dimensions"); - scale.z = 0.01; // overlay dimensions are 2D, not 3D. + scale.z = 0.01; // overlay dimensions are 2D, not 3D. dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale); } else { dimensions = Overlays.getProperty(overlayID, "dimensions"); if (dimensions.z) { - dimensions.z = 0.01; // overlay dimensions are 2D, not 3D. + dimensions.z = 0.01; // overlay dimensions are 2D, not 3D. } } @@ -279,7 +278,7 @@ ensureDynamic = function (entityID) { // if we distance hold something and keep it very still before releasing it, it ends up // non-dynamic in bullet. If it's too still, give it a little bounce so it will fall. var props = Entities.getEntityProperties(entityID, ["velocity", "dynamic", "parentID"]); - if (props.dynamic && props.parentID == NULL_UUID) { + if (props.dynamic && props.parentID === NULL_UUID) { var velocity = props.velocity; if (Vec3.length(velocity) < 0.05) { // see EntityMotionState.cpp DYNAMIC_LINEAR_VELOCITY_THRESHOLD velocity = { x: 0.0, y: 0.2, z: 0.0 }; @@ -289,7 +288,7 @@ ensureDynamic = function (entityID) { }; findGroupParent = function (controllerData, targetProps) { - while (targetProps.parentID && targetProps.parentID != NULL_UUID) { + while (targetProps.parentID && targetProps.parentID !== NULL_UUID) { // XXX use controllerData.nearbyEntityPropertiesByID ? var parentProps = Entities.getEntityProperties(targetProps.parentID, DISPATCHER_PROPERTIES); if (!parentProps) { diff --git a/scripts/system/controllers/controllerModules/disableOtherModule.js b/scripts/system/controllers/controllerModules/disableOtherModule.js new file mode 100644 index 0000000000..65732dd08d --- /dev/null +++ b/scripts/system/controllers/controllerModules/disableOtherModule.js @@ -0,0 +1,85 @@ +"use strict"; + +// nearTrigger.js +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + +/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, + enableDispatcherModule, disableDispatcherModule, getGrabbableData, Vec3, + TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS, + getEnabledModuleByName +*/ + +Script.include("/~/system/controllers/controllerDispatcherUtils.js"); + +(function() { + function DisableModules(hand) { + this.hand = hand; + this.disableModules = false; + this.parameters = makeDispatcherModuleParameters( + 90, + this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"], + 100); + + this.isReady = function(controllerData) { + if (this.disableModules) { + return makeRunningValues(true, [], []); + } + return false; + }; + + this.run = function(controllerData) { + var teleportModuleName = this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter"; + var teleportModule = getEnabledModuleByName(teleportModuleName); + + if (teleportModule) { + var ready = teleportModule.isReady(controllerData); + if (ready) { + return makeRunningValues(false, [], []); + } + } + if (!this.disablemodules) { + return makeRunningValues(false, [], []); + } + return makeRunningValues(true, [], []); + }; + } + + var leftDisableModules = new DisableModules(LEFT_HAND); + var rightDisableModules = new DisableModules(RIGHT_HAND); + + enableDispatcherModule("LeftDisableModules", leftDisableModules); + enableDispatcherModule("RightDisableModules", rightDisableModules); + this.handleMessage = function(channel, message, sender) { + if (sender === MyAvatar.sessionUUID) { + if (channel === 'Hifi-Hand-Disabler') { + if (message === 'left') { + leftDisableModules.disableModules = true; + } + if (message === 'right') { + rightDisableModules.disableModules = true; + + } + if (message === 'both' || message === 'none') { + if (message === 'both') { + leftDisableModules.disableModules = true; + rightDisableModules.disableModules = true; + } else if (message === 'none') { + leftDisableModules.disableModules = false; + rightDisableModules.disableModules = false; + } + } + } + } + }; + + Messages.subscribe('Hifi-Hand-Disabler'); + this.cleanup = function() { + disableDispatcherModule("LeftDisableModules"); + disableDispatcherModule("RightDisableModules"); + }; + Messages.messageReceived.connect(this.handleMessage); + Script.scriptEnding.connect(this.cleanup); +}()); diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 5b73204c8e..a9e62de4df 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -187,6 +187,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa wearable = props.userDataParsed.wearable ? props.userDataParsed.wearable : {}; } catch (err) { + // don't want to spam the logs } return wearable; } @@ -199,6 +200,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa equipHotspots = props.userDataParsed.equipHotspots ? props.userDataParsed.equipHotspots : []; } catch (err) { + // don't want to spam the logs } return equipHotspots; } @@ -255,7 +257,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.parameters = makeDispatcherModuleParameters( 300, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], + this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip"] : ["leftHand", "rightHandEquip"], [], 100); @@ -556,8 +558,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldHandPosition = controllerLocation.position; var candidateEntityProps = controllerData.nearbyEntityProperties[this.hand]; - - + + var potentialEquipHotspot = null; if (this.messageGrabEntity) { var hotspots = this.collectEquipHotspots(this.grabEntityProps); @@ -567,7 +569,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa } else { potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntityProps, controllerData); } - + if (!this.waitForTriggerRelease) { this.updateEquipHaptics(potentialEquipHotspot, worldHandPosition); } @@ -675,7 +677,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var handleMessage = function(channel, message, sender) { var data; - print(channel); if (sender === MyAvatar.sessionUUID) { if (channel === 'Hifi-Hand-Grab') { try { diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 2b748e60d6..7883222c73 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -527,6 +527,19 @@ Script.include("/~/system/libraries/controllers.js"); this.distanceRotate(otherFarGrabModule); } } + return this.exitIfDisabled(); + }; + + this.exitIfDisabled = function() { + var moduleName = this.hand === RIGHT_HAND ? "RightDisableModules" : "LeftDisableModules"; + var disableModule = getEnabledModuleByName(moduleName); + if (disableModule) { + if (disableModule.disableModules) { + this.laserPointerOff(); + this.endNearGrabAction(); + return makeRunningValues(false, [], []); + } + } return makeRunningValues(true, [], []); }; diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index fc7e0b526e..c6ac0c01bc 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -93,7 +93,7 @@ Script.include("/~/system/libraries/utils.js"); this.parameters = makeDispatcherModuleParameters( 160, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], + this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"], 100); this.nearTablet = function(overlays) { diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index a2673f8bca..2b3a2405fb 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -9,11 +9,12 @@ getControllerJointIndex, getGrabbableData, NULL_UUID, enableDispatcherModule, disableDispatcherModule, propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable, Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation, makeDispatcherModuleParameters, makeRunningValues, - TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent + TRIGGER_OFF_VALUE, NEAR_GRAB_RADIUS, findGroupParent, entityIsCloneable, propsAreCloneDynamic, cloneEntity */ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); +Script.include("/~/system/libraries/cloneEntityUtils.js"); (function() { @@ -172,7 +173,7 @@ Script.include("/~/system/libraries/controllers.js"); var targetProps = this.getTargetProps(controllerData); if (targetProps) { - if (!propsArePhysical(targetProps)) { + if (!propsArePhysical(targetProps) && !propsAreCloneDynamic) { return makeRunningValues(false, [], []); // let nearParentGrabEntity handle it } else { this.targetEntityID = targetProps.id; @@ -185,13 +186,12 @@ Script.include("/~/system/libraries/controllers.js"); this.run = function (controllerData) { if (this.actionID) { - if (controllerData.triggerClicks[this.hand] == 0) { + if (controllerData.triggerClicks[this.hand] === 0) { this.endNearGrabAction(); return makeRunningValues(false, [], []); } this.refreshNearGrabAction(controllerData); - var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); } else { @@ -204,9 +204,18 @@ Script.include("/~/system/libraries/controllers.js"); var targetProps = this.getTargetProps(controllerData); if (targetProps) { - if (controllerData.triggerClicks[this.hand] == 1) { + if (controllerData.triggerClicks[this.hand] === 1) { // switch to grabbing - this.startNearGrabAction(controllerData, targetProps); + var targetCloneable = entityIsCloneable(targetProps); + if (targetCloneable) { + var worldEntityProps = controllerData.nearbyEntityProperties[this.hand]; + var cloneID = cloneEntity(targetProps, worldEntityProps); + var cloneProps = Entities.getEntityProperties(cloneID); + this.targetEntityID = cloneID; + this.startNearGrabAction(controllerData, cloneProps); + } else { + this.startNearGrabAction(controllerData, targetProps); + } } } } diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 00fba45ae6..4a59fd727f 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -10,7 +10,7 @@ getControllerJointIndex, NULL_UUID, enableDispatcherModule, disableDispatcherModule, propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, - findGroupParent, Vec3, cloneEntity, entityIsCloneable + findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic */ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); @@ -40,6 +40,14 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); this.controllerJointIndex = getControllerJointIndex(this.hand); + this.getOtherModule = function() { + return (this.hand === RIGHT_HAND) ? leftNearParentingGrabEntity : rightNearParentingGrabEntity; + }; + + this.otherHandIsParent = function(props) { + return this.getOtherModule().thisHandIsParent(props); + }; + this.thisHandIsParent = function(props) { if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) { return false; @@ -67,7 +75,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); }; this.startNearParentingGrabEntity = function (controllerData, targetProps) { - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); var handJointIndex; @@ -92,10 +99,18 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); // this should never happen, but if it does, don't set previous parent to be this hand. // this.previousParentID[targetProps.id] = NULL; // this.previousParentJointIndex[targetProps.id] = -1; + } else if (this.otherHandIsParent(targetProps)) { + // the other hand is parent. Steal the object and information + var otherModule = this.getOtherModule(); + this.previousParentID[targetProps.id] = otherModule.previousParentID[targetProps.id]; + this.previousParentJointIndex[targetProps.id] = otherModule.previousParentJointIndex[targetProps.id]; + otherModule.endNearParentingGrabEntity(); } else { this.previousParentID[targetProps.id] = targetProps.parentID; this.previousParentJointIndex[targetProps.id] = targetProps.parentJointIndex; } + + this.targetEntityID = targetProps.id; Entities.editEntity(targetProps.id, reparentProps); Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ @@ -103,10 +118,11 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); grabbedEntity: targetProps.id, joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); + this.grabbing = true; }; this.endNearParentingGrabEntity = function () { - if (this.previousParentID[this.targetEntityID] === NULL_UUID) { + if (this.previousParentID[this.targetEntityID] === NULL_UUID || this.previousParentID === undefined) { Entities.editEntity(this.targetEntityID, { parentID: this.previousParentID[this.targetEntityID], parentJointIndex: this.previousParentJointIndex[this.targetEntityID] @@ -123,7 +139,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args); - this.grabbing = false; this.targetEntityID = null; }; @@ -160,7 +175,7 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); var targetProps = this.getTargetProps(controllerData); if (targetProps) { - if (propsArePhysical(targetProps)) { + if (propsArePhysical(targetProps) || propsAreCloneDynamic(targetProps)) { return makeRunningValues(false, [], []); // let nearActionGrabEntity handle it } else { this.targetEntityID = targetProps.id; @@ -178,6 +193,13 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); return makeRunningValues(false, [], []); } + var props = Entities.getEntityProperties(this.targetEntityID); + if (!this.thisHandIsParent(props)) { + this.grabbing = false; + this.targetEntityID = null; + return makeRunningValues(false, [], []); + } + var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "continueNearGrab", args); } else { diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index f0a5b9f07d..46ed8df271 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -38,31 +38,52 @@ var GRAB_RADIUS = 0.35; this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); this.controllerJointIndex = getControllerJointIndex(this.hand); + this.getOtherModule = function() { + return (this.hand === RIGHT_HAND) ? leftNearParentingGrabOverlay : rightNearParentingGrabOverlay; + }; + + this.otherHandIsParent = function(props) { + return this.getOtherModule().thisHandIsParent(props); + }; + this.thisHandIsParent = function(props) { if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) { return false; } var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - if (props.parentJointIndex == handJointIndex) { + if (props.parentJointIndex === handJointIndex) { return true; } var controllerJointIndex = this.controllerJointIndex; - if (props.parentJointIndex == controllerJointIndex) { + if (props.parentJointIndex === controllerJointIndex) { return true; } var controllerCRJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); - if (props.parentJointIndex == controllerCRJointIndex) { + "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : + "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); + + if (props.parentJointIndex === controllerCRJointIndex) { return true; } return false; }; + this.getGrabbedProperties = function() { + return { + position: Overlays.getProperty(this.grabbedThingID, "position"), + rotation: Overlays.getProperty(this.grabbedThingID, "rotation"), + parentID: Overlays.getProperty(this.grabbedThingID, "parentID"), + parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"), + dynamic: false, + shapeType: "none" + }; + }; + + this.startNearParentingGrabOverlay = function (controllerData) { Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); @@ -74,15 +95,8 @@ var GRAB_RADIUS = 0.35; // } handJointIndex = this.controllerJointIndex; - var grabbedProperties = { - position: Overlays.getProperty(this.grabbedThingID, "position"), - rotation: Overlays.getProperty(this.grabbedThingID, "rotation"), - parentID: Overlays.getProperty(this.grabbedThingID, "parentID"), - parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"), - dynamic: false, - shapeType: "none" - }; - + var grabbedProperties = this.getGrabbedProperties(); + var reparentProps = { parentID: AVATAR_SELF_ID, parentJointIndex: handJointIndex, @@ -94,6 +108,12 @@ var GRAB_RADIUS = 0.35; // this should never happen, but if it does, don't set previous parent to be this hand. // this.previousParentID[this.grabbedThingID] = NULL; // this.previousParentJointIndex[this.grabbedThingID] = -1; + } else if (this.otherHandIsParent(grabbedProperties)) { + // the other hand is parent. Steal the object and information + var otherModule = this.getOtherModule(); + this.previousParentID[this.grabbedThingID] = otherModule.previousParentID[this.garbbedThingID]; + this.previousParentJointIndex[this.grabbedThingID] = otherModule.previousParentJointIndex[this.grabbedThingID]; + } else { this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID; this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex; @@ -117,7 +137,7 @@ var GRAB_RADIUS = 0.35; // before we grabbed it, overlay was a child of something; put it back. Overlays.editOverlay(this.grabbedThingID, { parentID: this.previousParentID[this.grabbedThingID], - parentJointIndex: this.previousParentJointIndex[this.grabbedThingID], + parentJointIndex: this.previousParentJointIndex[this.grabbedThingID] }); } @@ -135,10 +155,10 @@ var GRAB_RADIUS = 0.35; } return null; }; - + this.isReady = function (controllerData) { - if (controllerData.triggerClicks[this.hand] == 0) { + if (controllerData.triggerClicks[this.hand] === 0) { return makeRunningValues(false, [], []); } @@ -160,10 +180,16 @@ var GRAB_RADIUS = 0.35; }; this.run = function (controllerData) { - if (controllerData.triggerClicks[this.hand] == 0) { + if (controllerData.triggerClicks[this.hand] === 0) { this.endNearParentingGrabOverlay(); return makeRunningValues(false, [], []); } else { + // check if someone stole the target from us + var grabbedProperties = this.getGrabbedProperties(); + if (!this.thisHandIsParent(grabbedProperties)) { + return makeRunningValues(false, [], []); + } + return makeRunningValues(true, [this.grabbedThingID], []); } }; diff --git a/scripts/system/controllers/controllerModules/nearTrigger.js b/scripts/system/controllers/controllerModules/nearTrigger.js index 239778040c..4d31a8a22b 100644 --- a/scripts/system/controllers/controllerModules/nearTrigger.js +++ b/scripts/system/controllers/controllerModules/nearTrigger.js @@ -30,7 +30,7 @@ Script.include("/~/system/controllers/controllerDispatcherUtils.js"); this.parameters = makeDispatcherModuleParameters( 520, - this.hand === RIGHT_HAND ? ["rightHandTrigger"] : ["leftHandTrigger"], + this.hand === RIGHT_HAND ? ["rightHandTrigger", "rightHand"] : ["leftHandTrigger", "leftHand"], [], 100); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index cd572b901a..60b820f06b 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -26,6 +26,7 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/overlayLaserInput.js", "controllerModules/webEntityLaserInput.js", "controllerModules/inEditMode.js", + "controllerModules/disableOtherModule.js", "teleport.js" ]; diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index 6246c0f03a..17ac36d955 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -14,6 +14,7 @@ Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions, Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ Script.include("/~/system/libraries/Xform.js"); Script.include("/~/system/controllers/controllerDispatcherUtils.js"); @@ -225,7 +226,7 @@ function Teleporter(hand) { } this.parameters = makeDispatcherModuleParameters( - 300, + 80, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], 100); @@ -338,12 +339,12 @@ function Teleporter(hand) { } }; } - + // related to repositioning the avatar after you teleport var FOOT_JOINT_NAMES = ["RightToe_End", "RightToeBase", "RightFoot"]; var DEFAULT_ROOT_TO_FOOT_OFFSET = 0.5; function getAvatarFootOffset() { - + // find a valid foot jointIndex var footJointIndex = -1; var i, l = FOOT_JOINT_NAMES.length; diff --git a/scripts/system/libraries/cloneEntityUtils.js b/scripts/system/libraries/cloneEntityUtils.js index 69c91fc398..a8e8bc227d 100644 --- a/scripts/system/libraries/cloneEntityUtils.js +++ b/scripts/system/libraries/cloneEntityUtils.js @@ -5,11 +5,13 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +/* global entityIsCloneable:true, getGrabbableData:true, cloneEntity:true propsAreCloneDynamic:true */ + Script.include("/~/system/controllers/controllerDispatcherUtils.js"); // Object assign polyfill -if (typeof Object.assign != 'function') { +if (typeof Object.assign !== 'function') { Object.assign = function(target, varArgs) { if (target === null) { throw new TypeError('Cannot convert undefined or null to object'); @@ -36,7 +38,18 @@ entityIsCloneable = function(props) { } return false; -} +}; + +propsAreCloneDynamic = function(props) { + var cloneable = entityIsCloneable(props); + if (cloneable) { + var grabInfo = getGrabbableData(props); + if (grabInfo.cloneDynamic) { + return true; + } + } + return false; +}; cloneEntity = function(props, worldEntityProps) { @@ -49,26 +62,26 @@ cloneEntity = function(props, worldEntityProps) { count++; } }); - + var grabInfo = getGrabbableData(cloneableProps); var limit = grabInfo.cloneLimit ? grabInfo.cloneLimit : 0; if (count >= limit && limit !== 0) { return null; } - + cloneableProps.name = cloneableProps.name + '-clone-' + cloneableProps.id; var lifetime = grabInfo.cloneLifetime ? grabInfo.cloneLifetime : 300; var dynamic = grabInfo.cloneDynamic ? grabInfo.cloneDynamic : false; var cUserData = Object.assign({}, JSON.parse(cloneableProps.userData)); var cProperties = Object.assign({}, cloneableProps); - + delete cUserData.grabbableKey.cloneLifetime; delete cUserData.grabbableKey.cloneable; delete cUserData.grabbableKey.cloneDynamic; delete cUserData.grabbableKey.cloneLimit; delete cProperties.id; - + cProperties.dynamic = dynamic; cProperties.locked = false; @@ -76,7 +89,7 @@ cloneEntity = function(props, worldEntityProps) { cUserData.grabbableKey.grabbable = true; cProperties.lifetime = lifetime; cProperties.userData = JSON.stringify(cUserData); - + var cloneID = Entities.addEntity(cProperties); return cloneID; -} +};