diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index f4c0cbb0d6..0a9fa4dce1 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, Keyboard + PointerManager, print, Keyboard */ controllerDispatcherPlugins = {}; @@ -53,6 +53,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.blacklist = []; this.pointerManager = new PointerManager(); this.grabSphereOverlays = [null, null]; + this.targetIDs = {}; // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are // not set to false (not in use), a module cannot start. When a module is using a slot, that module's name @@ -225,8 +226,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (tabletIndex !== -1 && closebyOverlays.indexOf(HMD.tabletID) === -1) { nearbyOverlays.splice(tabletIndex, 1); } - if (miniTabletIndex !== -1 - && ((closebyOverlays.indexOf(HMD.miniTabletID) === -1) || h !== HMD.miniTabletHand)) { + if (miniTabletIndex !== -1 && + ((closebyOverlays.indexOf(HMD.miniTabletID) === -1) || h !== HMD.miniTabletHand)) { nearbyOverlays.splice(miniTabletIndex, 1); } } @@ -336,6 +337,23 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }); } + // also make sure we have the properties from the current module's target + for (var tIDRunningPluginName in _this.runningPluginNames) { + if (_this.runningPluginNames.hasOwnProperty(tIDRunningPluginName)) { + var targetIDs = _this.targetIDs[tIDRunningPluginName]; + if (targetIDs) { + for (var k = 0; k < targetIDs.length; k++) { + var targetID = targetIDs[k]; + if (!nearbyEntityPropertiesByID[targetID]) { + var targetProps = Entities.getEntityProperties(targetID, DISPATCHER_PROPERTIES); + targetProps.id = targetID; + nearbyEntityPropertiesByID[targetID] = targetProps; + } + } + } + } + } + // bundle up all the data about the current situation var controllerData = { triggerValues: [_this.leftTriggerValue, _this.rightTriggerValue], @@ -402,10 +420,23 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.beginProfileRange("dispatch.run." + runningPluginName); } var runningness = plugin.run(controllerData, deltaTime); + + if (DEBUG) { + if (JSON.stringify(_this.targetIDs[runningPluginName]) != JSON.stringify(runningness.targets)) { + print("controllerDispatcher targetIDs[" + runningPluginName + "] = " + + JSON.stringify(runningness.targets)); + } + } + + _this.targetIDs[runningPluginName] = runningness.targets; if (!runningness.active) { // plugin is finished running, for now. remove it from the list // of running plugins and mark its activity-slots as "not in use" delete _this.runningPluginNames[runningPluginName]; + delete _this.targetIDs[runningPluginName]; + if (DEBUG) { + print("controllerDispatcher deleted targetIDs[" + runningPluginName + "]"); + } _this.markSlots(plugin, false); _this.pointerManager.makePointerInvisible(plugin.parameters.handLaser); if (DEBUG) { @@ -527,8 +558,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } if (action === "tablet") { - var tabletIDs = message.blacklist - ? [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : []; + var tabletIDs = message.blacklist ? + [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : + []; if (message.hand === LEFT_HAND) { _this.leftBlacklistTabletIDs = tabletIDs; _this.setLeftBlacklist(); diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index b1c1bc7765..54b56ff271 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -7,10 +7,10 @@ /* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print, getControllerJointIndex, - enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther, Messages, makeDispatcherModuleParameters, + enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions, Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, - entityIsCloneable, cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode, getGrabbableData, - entityIsEquippable + entityIsCloneable, cloneEntity, DISPATCHER_PROPERTIES, Uuid, isInEditMode, getGrabbableData, + entityIsEquippable, HMD */ Script.include("/~/system/libraries/Xform.js"); @@ -183,8 +183,9 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var TRIGGER_OFF_VALUE = 0.1; var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab var BUMPER_ON_VALUE = 0.5; + var ATTACHPOINT_MAX_DISTANCE = 3.0; - var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; + // var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}"; var UNEQUIP_KEY = "u"; @@ -200,7 +201,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa indicatorOffset: props.grab.equippableIndicatorOffset }; } else { - return null + return null; } } @@ -231,6 +232,12 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand"; var joints = avatarSettingsData[hotspot.key]; if (joints) { + // make sure they are reasonable + if (joints[jointName] && joints[jointName][0] && + Vec3.length(joints[jointName][0]) > ATTACHPOINT_MAX_DISTANCE) { + print("equipEntity -- Warning: rejecting settings attachPoint " + Vec3.length(joints[jointName][0])); + return undefined; + } return joints[jointName]; } } @@ -456,6 +463,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa }; this.startEquipEntity = function (controllerData) { + var _this = this; + this.dropGestureReset(); this.clearEquipHaptics(); Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); @@ -498,17 +507,23 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa if (entityIsCloneable(grabbedProperties)) { var cloneID = this.cloneHotspot(grabbedProperties, controllerData); this.targetEntityID = cloneID; - Entities.editEntity(this.targetEntityID, reparentProps); controllerData.nearbyEntityPropertiesByID[this.targetEntityID] = grabbedProperties; isClone = true; - } else if (!grabbedProperties.locked) { - Entities.editEntity(this.targetEntityID, reparentProps); - } else { + } else if (grabbedProperties.locked) { this.grabbedHotspot = null; this.targetEntityID = null; return; } + + // HACK -- when + // https://highfidelity.fogbugz.com/f/cases/21767/entity-edits-shortly-after-an-add-often-fail + // is resolved, this can just be an editEntity rather than a setTimeout. + this.editDelayTimeout = Script.setTimeout(function () { + _this.editDelayTimeout = null; + Entities.editEntity(_this.targetEntityID, reparentProps); + }, 100); + // we don't want to send startEquip message until the trigger is released. otherwise, // guns etc will fire right as they are equipped. this.shouldSendStart = true; @@ -519,7 +534,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); - var _this = this; var grabEquipCheck = function() { var args = [_this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(_this.targetEntityID, "startEquip", args); @@ -532,6 +546,12 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa }; this.endEquipEntity = function () { + + if (this.editDelayTimeout) { + Script.clearTimeout(this.editDelayTimeout); + this.editDelayTimeout = null; + } + this.storeAttachPointInSettings(); Entities.editEntity(this.targetEntityID, { parentID: Uuid.NULL, @@ -595,7 +615,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa equipHotspotBuddy.update(deltaTime, timestamp, controllerData); // if the potentialHotspot is cloneable, clone it and return it - // if the potentialHotspot os not cloneable and locked return null + // if the potentialHotspot is not cloneable and locked return null if (potentialEquipHotspot && (((this.triggerSmoothedSqueezed() || this.secondarySmoothedSqueezed()) && !this.waitForTriggerRelease) || this.messageGrabEntity)) { @@ -603,7 +623,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa this.targetEntityID = this.grabbedHotspot.entityID; this.startEquipEntity(controllerData); this.equipedWithSecondary = this.secondarySmoothedSqueezed(); - return makeRunningValues(true, [potentialEquipHotspot.entityID], []); + return makeRunningValues(true, [this.targetEntityID], []); } else { return makeRunningValues(false, [], []); }