mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 21:56:26 +02:00
ESLINT, style and spelling fixes
This commit is contained in:
parent
c7ab4994ea
commit
a25584c90f
1 changed files with 806 additions and 786 deletions
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
//
|
||||
// makeUserConnetion.js
|
||||
// makeUserConnection.js
|
||||
// scripts/system
|
||||
//
|
||||
// Created by David Kelly on 3/7/2017.
|
||||
|
@ -11,31 +11,31 @@
|
|||
//
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
const label = "makeUserConnection";
|
||||
const MAX_AVATAR_DISTANCE = 0.2; // m
|
||||
const GRIP_MIN = 0.05; // goes from 0-1, so 5% pressed is pressed
|
||||
const MESSAGE_CHANNEL = "io.highfidelity.makeUserConnection";
|
||||
const STATES = {
|
||||
inactive : 0,
|
||||
waiting: 1,
|
||||
connecting: 2,
|
||||
makingConnection: 3
|
||||
};
|
||||
const STATE_STRINGS = ["inactive", "waiting", "connecting", "makingConnection"];
|
||||
const WAITING_INTERVAL = 100; // ms
|
||||
const CONNECTING_INTERVAL = 100; // ms
|
||||
const MAKING_CONNECTION_TIMEOUT = 800; // ms
|
||||
const CONNECTING_TIME = 1600; // ms
|
||||
const PARTICLE_RADIUS = 0.15; // m
|
||||
const PARTICLE_ANGLE_INCREMENT = 360/45; // 1hz
|
||||
const HANDSHAKE_SOUND_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/davidkelly/production/audio/4beat_sweep.wav";
|
||||
const SUCCESSFUL_HANDSHAKE_SOUND_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/davidkelly/production/audio/3rdbeat_success_bell.wav";
|
||||
const HAPTIC_DATA = {
|
||||
initial: { duration: 20, strength: 0.6}, // duration is in ms
|
||||
var LABEL = "makeUserConnection";
|
||||
var MAX_AVATAR_DISTANCE = 0.2; // m
|
||||
var GRIP_MIN = 0.05; // goes from 0-1, so 5% pressed is pressed
|
||||
var MESSAGE_CHANNEL = "io.highfidelity.makeUserConnection";
|
||||
var STATES = {
|
||||
INACTIVE: 0,
|
||||
WAITING: 1,
|
||||
CONNECTING: 2,
|
||||
MAKING_CONNECTION: 3
|
||||
};
|
||||
var STATE_STRINGS = ["inactive", "waiting", "connecting", "makingConnection"];
|
||||
var WAITING_INTERVAL = 100; // ms
|
||||
var CONNECTING_INTERVAL = 100; // ms
|
||||
var MAKING_CONNECTION_TIMEOUT = 800; // ms
|
||||
var CONNECTING_TIME = 1600; // ms
|
||||
var PARTICLE_RADIUS = 0.15; // m
|
||||
var PARTICLE_ANGLE_INCREMENT = 360/45; // 1hz
|
||||
var HANDSHAKE_SOUND_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/davidkelly/production/audio/4beat_sweep.wav";
|
||||
var SUCCESSFUL_HANDSHAKE_SOUND_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/davidkelly/production/audio/3rdbeat_success_bell.wav";
|
||||
var HAPTIC_DATA = {
|
||||
initial: { duration: 20, strength: 0.6 }, // duration is in ms
|
||||
background: { duration: 100, strength: 0.3 }, // duration is in ms
|
||||
success: { duration: 60, strength: 1.0} // duration is in ms
|
||||
};
|
||||
const PARTICLE_EFFECT_PROPS = {
|
||||
success: { duration: 60, strength: 1.0 } // duration is in ms
|
||||
};
|
||||
var PARTICLE_EFFECT_PROPS = {
|
||||
"alpha": 0.8,
|
||||
"azimuthFinish": Math.PI,
|
||||
"azimuthStart": -1*Math.PI,
|
||||
|
@ -60,10 +60,10 @@ const PARTICLE_EFFECT_PROPS = {
|
|||
"accelerationSpread": {"x": 0.0, "y": 0.0, "z": 0.0},
|
||||
"dimensions": {"x":0.05, "y": 0.05, "z": 0.05},
|
||||
"type": "ParticleEffect"
|
||||
};
|
||||
const MAKING_CONNECTION_PARTICLE_PROPS = {
|
||||
};
|
||||
var MAKING_CONNECTION_PARTICLE_PROPS = {
|
||||
"alpha": 0.07,
|
||||
"alphaStart":0.011,
|
||||
"alphaStart": 0.011,
|
||||
"alphaSpread": 0,
|
||||
"alphaFinish": 0,
|
||||
"azimuthFinish": Math.PI,
|
||||
|
@ -90,38 +90,38 @@ const MAKING_CONNECTION_PARTICLE_PROPS = {
|
|||
"accelerationSpread": {"x": 0.0, "y": 0.0, "z": 0.0},
|
||||
"dimensions": {"x":0.05, "y": 0.05, "z": 0.05},
|
||||
"type": "ParticleEffect"
|
||||
};
|
||||
};
|
||||
|
||||
var currentHand;
|
||||
var state = STATES.inactive;
|
||||
var connectingInterval;
|
||||
var waitingInterval;
|
||||
var makingConnectionTimeout;
|
||||
var animHandlerId;
|
||||
var connectingId;
|
||||
var connectingHand;
|
||||
var waitingList = {};
|
||||
var particleEffect;
|
||||
var waitingBallScale;
|
||||
var particleRotationAngle = 0.0;
|
||||
var makingConnectionParticleEffect;
|
||||
var makingConnectionEmitRate = 2000;
|
||||
var particleEmitRate = 500;
|
||||
var handshakeInjector;
|
||||
var successfulHandshakeInjector;
|
||||
var handshakeSound;
|
||||
var successfulHandshakeSound;
|
||||
var currentHand;
|
||||
var state = STATES.INACTIVE;
|
||||
var connectingInterval;
|
||||
var waitingInterval;
|
||||
var makingConnectionTimeout;
|
||||
var animHandlerId;
|
||||
var connectingId;
|
||||
var connectingHand;
|
||||
var waitingList = {};
|
||||
var particleEffect;
|
||||
var particleRotationAngle = 0.0;
|
||||
var makingConnectionParticleEffect;
|
||||
var makingConnectionEmitRate = 2000;
|
||||
var particleEmitRate = 500;
|
||||
var handshakeInjector;
|
||||
var successfulHandshakeInjector;
|
||||
var handshakeSound;
|
||||
var successfulHandshakeSound;
|
||||
|
||||
function debug() {
|
||||
function debug() {
|
||||
var stateString = "<" + STATE_STRINGS[state] + ">";
|
||||
var connecting = "[" + connectingId + "/" + connectingHand + "]";
|
||||
print.apply(null, [].concat.apply([label, stateString, JSON.stringify(waitingList), connecting], [].map.call(arguments, JSON.stringify)));
|
||||
}
|
||||
print.apply(null, [].concat.apply([LABEL, stateString, JSON.stringify(waitingList), connecting],
|
||||
[].map.call(arguments, JSON.stringify)));
|
||||
}
|
||||
|
||||
function cleanId(guidWithCurlyBraces) {
|
||||
function cleanId(guidWithCurlyBraces) {
|
||||
return guidWithCurlyBraces.slice(1, -1);
|
||||
}
|
||||
function request(options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request.
|
||||
}
|
||||
function request(options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request.
|
||||
var httpRequest = new XMLHttpRequest(), key;
|
||||
// QT bug: apparently doesn't handle onload. Workaround using readyState.
|
||||
httpRequest.onreadystatechange = function () {
|
||||
|
@ -156,8 +156,10 @@ function request(options, callback) { // cb(error, responseOfCorrectContentType)
|
|||
if (options.body && (options.method === 'GET')) { // add query parameters
|
||||
var params = [], appender = (-1 === options.uri.search('?')) ? '?' : '&';
|
||||
for (key in options.body) {
|
||||
if (options.body.hasOwnProperty(key)) {
|
||||
params.push(key + '=' + options.body[key]);
|
||||
}
|
||||
}
|
||||
options.uri += appender + params.join('&');
|
||||
delete options.body;
|
||||
}
|
||||
|
@ -167,13 +169,15 @@ function request(options, callback) { // cb(error, responseOfCorrectContentType)
|
|||
options.body = JSON.stringify(options.body);
|
||||
}
|
||||
for (key in options.headers || {}) {
|
||||
if (options.headers.hasOwnProperty(key)) {
|
||||
httpRequest.setRequestHeader(key, options.headers[key]);
|
||||
}
|
||||
}
|
||||
httpRequest.open(options.method, options.uri, true);
|
||||
httpRequest.send(options.body);
|
||||
}
|
||||
}
|
||||
|
||||
function handToString(hand) {
|
||||
function handToString(hand) {
|
||||
if (hand === Controller.Standard.RightHand) {
|
||||
return "RightHand";
|
||||
} else if (hand === Controller.Standard.LeftHand) {
|
||||
|
@ -181,19 +185,19 @@ function handToString(hand) {
|
|||
}
|
||||
debug("handToString called without valid hand!");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function stringToHand(hand) {
|
||||
if (hand == "RightHand") {
|
||||
function stringToHand(hand) {
|
||||
if (hand === "RightHand") {
|
||||
return Controller.Standard.RightHand;
|
||||
} else if (hand == "LeftHand") {
|
||||
} else if (hand === "LeftHand") {
|
||||
return Controller.Standard.LeftHand;
|
||||
}
|
||||
debug("stringToHand called with bad hand string:", hand);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function handToHaptic(hand) {
|
||||
function handToHaptic(hand) {
|
||||
if (hand === Controller.Standard.RightHand) {
|
||||
return 1;
|
||||
} else if (hand === Controller.Standard.LeftHand) {
|
||||
|
@ -201,30 +205,30 @@ function handToHaptic(hand) {
|
|||
}
|
||||
debug("handToHaptic called without a valid hand!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
function stopWaiting() {
|
||||
function stopWaiting() {
|
||||
if (waitingInterval) {
|
||||
waitingInterval = Script.clearInterval(waitingInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopConnecting() {
|
||||
function stopConnecting() {
|
||||
if (connectingInterval) {
|
||||
connectingInterval = Script.clearInterval(connectingInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopMakingConnection() {
|
||||
function stopMakingConnection() {
|
||||
if (makingConnectionTimeout) {
|
||||
makingConnectionTimeout = Script.clearTimeout(makingConnectionTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This returns the position of the palm, really. Which relies on the avatar
|
||||
// having the expected middle1 joint. TODO: fallback for when this isn't part
|
||||
// of the avatar?
|
||||
function getHandPosition(avatar, hand) {
|
||||
function getHandPosition(avatar, hand) {
|
||||
if (!hand) {
|
||||
debug("calling getHandPosition with no hand! (returning avatar position but this is a BUG)");
|
||||
debug(new Error().stack);
|
||||
|
@ -232,9 +236,9 @@ function getHandPosition(avatar, hand) {
|
|||
}
|
||||
var jointName = handToString(hand) + "Middle1";
|
||||
return avatar.getJointPosition(avatar.getJointIndex(jointName));
|
||||
}
|
||||
}
|
||||
|
||||
function shakeHandsAnimation(animationProperties) {
|
||||
function shakeHandsAnimation(animationProperties) {
|
||||
// all we are doing here is moving the right hand to a spot
|
||||
// that is in front of and a bit above the hips. Basing how
|
||||
// far in front as scaling with the avatar's height (say hips
|
||||
|
@ -245,36 +249,35 @@ function shakeHandsAnimation(animationProperties) {
|
|||
if (headIndex) {
|
||||
offset = 0.8 * MyAvatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y;
|
||||
}
|
||||
var handPos = Vec3.multiply(offset, {x: -0.25, y: 0.8, z: 1.3});
|
||||
result.rightHandPosition = handPos;
|
||||
result.rightHandPosition = Vec3.multiply(offset, {x: -0.25, y: 0.8, z: 1.3});
|
||||
result.rightHandRotation = Quat.fromPitchYawRollDegrees(90, 0, 90);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function positionFractionallyTowards(posA, posB, frac) {
|
||||
function positionFractionallyTowards(posA, posB, frac) {
|
||||
return Vec3.sum(posA, Vec3.multiply(frac, Vec3.subtract(posB, posA)));
|
||||
}
|
||||
}
|
||||
|
||||
function deleteParticleEffect() {
|
||||
function deleteParticleEffect() {
|
||||
if (particleEffect) {
|
||||
particleEffect = Entities.deleteEntity(particleEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deleteMakeConnectionParticleEffect() {
|
||||
function deleteMakeConnectionParticleEffect() {
|
||||
if (makingConnectionParticleEffect) {
|
||||
makingConnectionParticleEffect = Entities.deleteEntity(makingConnectionParticleEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopHandshakeSound() {
|
||||
function stopHandshakeSound() {
|
||||
if (handshakeInjector) {
|
||||
handshakeInjector.stop();
|
||||
handshakeInjector = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calcParticlePos(myHand, otherHand, otherOrientation, reset) {
|
||||
function calcParticlePos(myHand, otherHand, otherOrientation, reset) {
|
||||
if (reset) {
|
||||
particleRotationAngle = 0.0;
|
||||
}
|
||||
|
@ -283,11 +286,11 @@ function calcParticlePos(myHand, otherHand, otherOrientation, reset) {
|
|||
var radius = Math.min(PARTICLE_RADIUS, PARTICLE_RADIUS * particleRotationAngle / 360);
|
||||
var axis = Vec3.mix(Quat.getFront(MyAvatar.orientation), Quat.inverse(Quat.getFront(otherOrientation)), 0.5);
|
||||
return Vec3.sum(position, Vec3.multiplyQbyV(Quat.angleAxis(particleRotationAngle, axis), {x: 0, y: radius, z: 0}));
|
||||
}
|
||||
}
|
||||
|
||||
// this is called frequently, but usually does nothing
|
||||
function updateVisualization() {
|
||||
if (state == STATES.inactive) {
|
||||
// this is called frequently, but usually does nothing
|
||||
function updateVisualization() {
|
||||
if (state === STATES.INACTIVE) {
|
||||
deleteParticleEffect();
|
||||
deleteMakeConnectionParticleEffect();
|
||||
// this should always be true if inactive, but just in case:
|
||||
|
@ -306,16 +309,14 @@ function updateVisualization() {
|
|||
}
|
||||
}
|
||||
|
||||
var wrist = MyAvatar.getJointPosition(MyAvatar.getJointIndex(handToString(currentHand)));
|
||||
var d = Math.min(MAX_AVATAR_DISTANCE, Vec3.distance(wrist, myHandPosition));
|
||||
switch (state) {
|
||||
case STATES.waiting:
|
||||
case STATES.WAITING:
|
||||
// no visualization while waiting
|
||||
deleteParticleEffect();
|
||||
deleteMakeConnectionParticleEffect();
|
||||
stopHandshakeSound();
|
||||
break;
|
||||
case STATES.connecting:
|
||||
case STATES.CONNECTING:
|
||||
var particleProps = {};
|
||||
// put the position between the 2 hands, if we have a connectingId. This
|
||||
// helps define the plane in which the particles move.
|
||||
|
@ -343,21 +344,28 @@ function updateVisualization() {
|
|||
makingConnectionParticleEffect = Entities.addEntity(props, true);
|
||||
} else {
|
||||
makingConnectionEmitRate *= 0.5;
|
||||
Entities.editEntity(makingConnectionParticleEffect, {emitRate: makingConnectionEmitRate, position: myHandPosition, isEmitting: 1});
|
||||
Entities.editEntity(makingConnectionParticleEffect, {
|
||||
emitRate: makingConnectionEmitRate,
|
||||
position: myHandPosition,
|
||||
isEmitting: true
|
||||
});
|
||||
}
|
||||
break;
|
||||
case STATES.makingConnection:
|
||||
case STATES.MAKING_CONNECTION:
|
||||
particleEmitRate = Math.max(50, particleEmitRate * 0.5);
|
||||
Entities.editEntity(makingConnectionParticleEffect, {emitRate: 0, isEmitting: 0, position: myHandPosition});
|
||||
Entities.editEntity(particleEffect, {position: calcParticlePos(myHandPosition, otherHand, otherOrientation), emitRate: particleEmitRate});
|
||||
Entities.editEntity(particleEffect, {
|
||||
position: calcParticlePos(myHandPosition, otherHand, otherOrientation),
|
||||
emitRate: particleEmitRate
|
||||
});
|
||||
break;
|
||||
default:
|
||||
debug("unexpected state", state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isNearby(id, hand) {
|
||||
function isNearby(id, hand) {
|
||||
if (currentHand) {
|
||||
var handPos = getHandPosition(MyAvatar, currentHand);
|
||||
var avatar = AvatarList.getAvatar(id);
|
||||
|
@ -368,9 +376,9 @@ function isNearby(id, hand) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function findNearestWaitingAvatar() {
|
||||
function findNearestWaitingAvatar() {
|
||||
var handPos = getHandPosition(MyAvatar, currentHand);
|
||||
var minDistance = MAX_AVATAR_DISTANCE;
|
||||
var nearestAvatar = {};
|
||||
|
@ -386,18 +394,18 @@ function findNearestWaitingAvatar() {
|
|||
}
|
||||
});
|
||||
return nearestAvatar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// As currently implemented, we select the closest waiting avatar (if close enough) and send
|
||||
// them a connectionRequest. If nobody is close enough we send a waiting message, and wait for a
|
||||
// connectionRequest. If the 2 people who want to connect are both somewhat out of range when they
|
||||
// initiate the shake, they will race to see who sends the connectionRequest after noticing the
|
||||
// waiting message. Either way, they will start connecting eachother at that point.
|
||||
function startHandshake(fromKeyboard) {
|
||||
// As currently implemented, we select the closest waiting avatar (if close enough) and send
|
||||
// them a connectionRequest. If nobody is close enough we send a waiting message, and wait for a
|
||||
// connectionRequest. If the 2 people who want to connect are both somewhat out of range when they
|
||||
// initiate the shake, they will race to see who sends the connectionRequest after noticing the
|
||||
// waiting message. Either way, they will start connecting each other at that point.
|
||||
function startHandshake(fromKeyboard) {
|
||||
if (fromKeyboard) {
|
||||
debug("adding animation");
|
||||
// just in case order of press/unpress is broken
|
||||
// just in case order of press/release is broken
|
||||
if (animHandlerId) {
|
||||
animHandlerId = MyAvatar.removeAnimationStateHandler(animHandlerId);
|
||||
}
|
||||
|
@ -405,7 +413,7 @@ function startHandshake(fromKeyboard) {
|
|||
}
|
||||
debug("starting handshake for", currentHand);
|
||||
pollCount = 0;
|
||||
state = STATES.waiting;
|
||||
state = STATES.WAITING;
|
||||
connectingId = undefined;
|
||||
connectingHand = undefined;
|
||||
// just in case
|
||||
|
@ -432,9 +440,9 @@ function startHandshake(fromKeyboard) {
|
|||
});
|
||||
lookForWaitingAvatar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function endHandshake() {
|
||||
function endHandshake() {
|
||||
debug("ending handshake for", currentHand);
|
||||
|
||||
deleteParticleEffect();
|
||||
|
@ -444,7 +452,7 @@ function endHandshake() {
|
|||
// only be done here, unless we change how the triggering works,
|
||||
// as we ignore the key release event when inactive. See updateTriggers
|
||||
// below.
|
||||
state = STATES.inactive;
|
||||
state = STATES.INACTIVE;
|
||||
connectingId = undefined;
|
||||
connectingHand = undefined;
|
||||
stopWaiting();
|
||||
|
@ -460,11 +468,12 @@ function endHandshake() {
|
|||
debug("removing animation");
|
||||
MyAvatar.removeAnimationStateHandler(animHandlerId);
|
||||
}
|
||||
// No-op if we were successful, but this way we ensure that failures and abandoned handshakes don't leave us in a weird state.
|
||||
// No-op if we were successful, but this way we ensure that failures and abandoned handshakes don't leave us
|
||||
// in a weird state.
|
||||
request({uri: requestUrl, method: 'DELETE'}, debug);
|
||||
}
|
||||
}
|
||||
|
||||
function updateTriggers(value, fromKeyboard, hand) {
|
||||
function updateTriggers(value, fromKeyboard, hand) {
|
||||
if (currentHand && hand !== currentHand) {
|
||||
debug("currentHand", currentHand, "ignoring messages from", hand);
|
||||
return;
|
||||
|
@ -476,7 +485,7 @@ function updateTriggers(value, fromKeyboard, hand) {
|
|||
var isGripping = value > GRIP_MIN;
|
||||
if (isGripping) {
|
||||
debug("updateTriggers called - gripping", handToString(hand));
|
||||
if (state != STATES.inactive) {
|
||||
if (state !== STATES.INACTIVE) {
|
||||
return;
|
||||
} else {
|
||||
startHandshake(fromKeyboard);
|
||||
|
@ -484,29 +493,29 @@ function updateTriggers(value, fromKeyboard, hand) {
|
|||
} else {
|
||||
// TODO: should we end handshake even when inactive? Ponder
|
||||
debug("updateTriggers called -- no longer gripping", handToString(hand));
|
||||
if (state != STATES.inactive) {
|
||||
if (state !== STATES.INACTIVE) {
|
||||
endHandshake();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function messageSend(message) {
|
||||
function messageSend(message) {
|
||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
|
||||
function lookForWaitingAvatar() {
|
||||
function lookForWaitingAvatar() {
|
||||
// we started with nobody close enough, but maybe I've moved
|
||||
// or they did. Note that 2 people doing this race, so stop
|
||||
// as soon as you have a connectingId (which means you got their
|
||||
// message before noticing they were in range in this loop)
|
||||
|
||||
// just in case we reenter before stopping
|
||||
// just in case we re-enter before stopping
|
||||
stopWaiting();
|
||||
debug("started looking for waiting avatars");
|
||||
waitingInterval = Script.setInterval(function () {
|
||||
if (state == STATES.waiting && !connectingId) {
|
||||
if (state === STATES.WAITING && !connectingId) {
|
||||
// find the closest in-range avatar, and send connection request
|
||||
var nearestAvatar = findNearestWaitingAvatar();
|
||||
if (nearestAvatar.avatar) {
|
||||
|
@ -525,26 +534,33 @@ function lookForWaitingAvatar() {
|
|||
debug("stopped looking for waiting avatars");
|
||||
}
|
||||
}, WAITING_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* There is a mini-state machine after entering STATES.makingConnection.
|
||||
/* There is a mini-state machine after entering STATES.makingConnection.
|
||||
We make a request (which might immediately succeed, fail, or neither.
|
||||
If we immediately fail, we tell the user.
|
||||
Otherwise, we wait MAKING_CONNECTION_TIMEOUT. At that time, we poll until success or fail.
|
||||
*/
|
||||
var result, requestBody, pollCount = 0, requestUrl = location.metaverseServerUrl + '/api/v1/user/connection_request';
|
||||
function connectionRequestCompleted() { // Final result is in. Do effects.
|
||||
var result, requestBody, pollCount = 0, requestUrl = location.metaverseServerUrl + '/api/v1/user/connection_request';
|
||||
function connectionRequestCompleted() { // Final result is in. Do effects.
|
||||
if (result.status === 'success') { // set earlier
|
||||
if (!successfulHandshakeInjector) {
|
||||
successfulHandshakeInjector = Audio.playSound(successfulHandshakeSound, {position: getHandPosition(MyAvatar, currentHand), volume: 0.5, localOnly: true});
|
||||
successfulHandshakeInjector = Audio.playSound(successfulHandshakeSound, {
|
||||
position: getHandPosition(MyAvatar, currentHand),
|
||||
volume: 0.5,
|
||||
localOnly: true
|
||||
});
|
||||
} else {
|
||||
successfulHandshakeInjector.restart();
|
||||
}
|
||||
Controller.triggerHapticPulse(HAPTIC_DATA.success.strength, HAPTIC_DATA.success.duration, handToHaptic(currentHand));
|
||||
Controller.triggerHapticPulse(HAPTIC_DATA.success.strength, HAPTIC_DATA.success.duration,
|
||||
handToHaptic(currentHand));
|
||||
// don't change state (so animation continues while gripped)
|
||||
// but do send a notification, by calling the slot that emits the signal for it
|
||||
Window.makeConnection(true, result.connection.new_connection ? "You and " + result.connection.username + " are now connected!" : result.connection.username);
|
||||
UserActivityLogger.makeUserConnection(connectingId, true, result.connection.new_connection ? "new connection" : "already connected");
|
||||
Window.makeConnection(true, result.connection.new_connection ?
|
||||
"You and " + result.connection.username + " are now connected!" : result.connection.username);
|
||||
UserActivityLogger.makeUserConnection(connectingId, true, result.connection.new_connection ?
|
||||
"new connection" : "already connected");
|
||||
return;
|
||||
} // failed
|
||||
endHandshake();
|
||||
|
@ -552,12 +568,13 @@ function connectionRequestCompleted() { // Final result is in. Do effects.
|
|||
// IWBNI we also did some fail sound/visual effect.
|
||||
Window.makeConnection(false, result.connection);
|
||||
UserActivityLogger.makeUserConnection(connectingId, false, result.connection);
|
||||
}
|
||||
var POLL_INTERVAL_MS = 200, POLL_LIMIT = 5;
|
||||
function handleConnectionResponseAndMaybeRepeat(error, response) {
|
||||
}
|
||||
var POLL_INTERVAL_MS = 200, POLL_LIMIT = 5;
|
||||
function handleConnectionResponseAndMaybeRepeat(error, response) {
|
||||
// If response is 'pending', set a short timeout to try again.
|
||||
// If we fail other than pending, set result and immediately call connectionRequestCompleted.
|
||||
// If we succceed, set result and call connectionRequestCompleted immediately (if we've been polling), and otherwise on a timeout.
|
||||
// If we succeed, set result and call connectionRequestCompleted immediately (if we've been polling),
|
||||
// and otherwise on a timeout.
|
||||
if (response && (response.connection === 'pending')) {
|
||||
debug(response, 'pollCount', pollCount);
|
||||
if (pollCount++ >= POLL_LIMIT) { // server will expire, but let's not wait that long.
|
||||
|
@ -586,27 +603,27 @@ function handleConnectionResponseAndMaybeRepeat(error, response) {
|
|||
result = response;
|
||||
if (pollCount++) {
|
||||
connectionRequestCompleted();
|
||||
} else { // Wait for other guy, so that final succcess is at roughly the same time.
|
||||
} else { // Wait for other guy, so that final success is at roughly the same time.
|
||||
Script.setTimeout(connectionRequestCompleted, MAKING_CONNECTION_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this should be where we make the appropriate connection call. For now just make the
|
||||
// visualization change.
|
||||
function makeConnection(id) {
|
||||
// this should be where we make the appropriate connection call. For now just make the
|
||||
// visualization change.
|
||||
function makeConnection(id) {
|
||||
// send done to let the connection know you have made connection.
|
||||
messageSend({
|
||||
key: "done",
|
||||
connectionId: id
|
||||
});
|
||||
|
||||
state = STATES.makingConnection;
|
||||
state = STATES.MAKING_CONNECTION;
|
||||
|
||||
// continue the haptic background until the timeout fires. When we make calls, we will have an interval
|
||||
// probably, in which we do this.
|
||||
Controller.triggerHapticPulse(HAPTIC_DATA.background.strength, MAKING_CONNECTION_TIMEOUT, handToHaptic(currentHand));
|
||||
requestBody = {node_id: cleanId(MyAvatar.sessionUUID), proposed_node_id: cleanId(id)}; // for use when repeating
|
||||
requestBody = {'node_id': cleanId(MyAvatar.sessionUUID), 'proposed_node_id': cleanId(id)}; // for use when repeating
|
||||
|
||||
// It would be "simpler" to skip this and just look at the response, but:
|
||||
// 1. We don't want to bother the metaverse with request that we know will fail.
|
||||
|
@ -616,31 +633,35 @@ function makeConnection(id) {
|
|||
return;
|
||||
}
|
||||
|
||||
// This will immediately set response if successfull (e.g., the other guy got his request in first), or immediate failure,
|
||||
// and will otherwise poll (using the requestBody we just set).
|
||||
// This will immediately set response if successful (e.g., the other guy got his request in first),
|
||||
// or immediate failure, and will otherwise poll (using the requestBody we just set).
|
||||
request({ //
|
||||
uri: requestUrl,
|
||||
method: 'POST',
|
||||
json: true,
|
||||
body: {user_connection_request: requestBody}
|
||||
body: {'user_connection_request': requestBody}
|
||||
}, handleConnectionResponseAndMaybeRepeat);
|
||||
}
|
||||
}
|
||||
|
||||
// we change states, start the connectionInterval where we check
|
||||
// to be sure the hand is still close enough. If not, we terminate
|
||||
// the interval, go back to the waiting state. If we make it
|
||||
// the entire CONNECTING_TIME, we make the connection.
|
||||
function startConnecting(id, hand) {
|
||||
// we change states, start the connectionInterval where we check
|
||||
// to be sure the hand is still close enough. If not, we terminate
|
||||
// the interval, go back to the waiting state. If we make it
|
||||
// the entire CONNECTING_TIME, we make the connection.
|
||||
function startConnecting(id, hand) {
|
||||
var count = 0;
|
||||
debug("connecting", id, "hand", hand);
|
||||
// do we need to do this?
|
||||
connectingId = id;
|
||||
connectingHand = hand;
|
||||
state = STATES.connecting;
|
||||
state = STATES.CONNECTING;
|
||||
|
||||
// play sound
|
||||
if (!handshakeInjector) {
|
||||
handshakeInjector = Audio.playSound(handshakeSound, {position: getHandPosition(MyAvatar, currentHand), volume: 0.5, localOnly: true});
|
||||
handshakeInjector = Audio.playSound(handshakeSound, {
|
||||
position: getHandPosition(MyAvatar, currentHand),
|
||||
volume: 0.5,
|
||||
localOnly: true
|
||||
});
|
||||
} else {
|
||||
handshakeInjector.restart();
|
||||
}
|
||||
|
@ -655,8 +676,9 @@ function startConnecting(id, hand) {
|
|||
|
||||
connectingInterval = Script.setInterval(function () {
|
||||
count += 1;
|
||||
Controller.triggerHapticPulse(HAPTIC_DATA.background.strength, HAPTIC_DATA.background.duration, handToHaptic(currentHand));
|
||||
if (state != STATES.connecting) {
|
||||
Controller.triggerHapticPulse(HAPTIC_DATA.background.strength, HAPTIC_DATA.background.duration,
|
||||
handToHaptic(currentHand));
|
||||
if (state !== STATES.CONNECTING) {
|
||||
debug("stopping connecting interval, state changed");
|
||||
stopConnecting();
|
||||
} else if (!isNearby(id, hand)) {
|
||||
|
@ -673,15 +695,15 @@ function startConnecting(id, hand) {
|
|||
stopConnecting();
|
||||
}
|
||||
}, CONNECTING_INTERVAL);
|
||||
}
|
||||
/*
|
||||
A simple sequence diagram: NOTE that the ConnectionAck is somewhat
|
||||
vestigial, and probably should be removed shortly.
|
||||
}
|
||||
/*
|
||||
A simple sequence diagram: NOTE that the ConnectionAck is somewhat
|
||||
vestigial, and probably should be removed shortly.
|
||||
|
||||
Avatar A Avatar B
|
||||
| |
|
||||
| <-----(waiting) ----- startHandshake
|
||||
startHandshake - (connectionRequest) -> |
|
||||
startHandshake - (connectionRequest) -> |
|
||||
| |
|
||||
| <----(connectionAck) -------- |
|
||||
| <-----(connecting) -- startConnecting
|
||||
|
@ -691,8 +713,8 @@ startHandshake - (connectionRequest) -> |
|
|||
connected |
|
||||
| <--------- (done) ---------- |
|
||||
| ---------- (done) ---------> |
|
||||
*/
|
||||
function messageHandler(channel, messageString, senderID) {
|
||||
*/
|
||||
function messageHandler(channel, messageString, senderID) {
|
||||
if (channel !== MESSAGE_CHANNEL) {
|
||||
return;
|
||||
}
|
||||
|
@ -713,7 +735,8 @@ function messageHandler(channel, messageString, senderID) {
|
|||
break;
|
||||
case "connectionRequest":
|
||||
delete waitingList[senderID];
|
||||
if (state == STATES.waiting && message.id == MyAvatar.sessionUUID && (!connectingId || connectingId == senderID)) {
|
||||
if (state === STATES.WAITING && message.id === MyAvatar.sessionUUID &&
|
||||
(!connectingId || connectingId === senderID)) {
|
||||
// you were waiting for a connection request, so send the ack. Or, you and the other
|
||||
// guy raced and both send connectionRequests. Handle that too
|
||||
connectingId = senderID;
|
||||
|
@ -723,43 +746,39 @@ function messageHandler(channel, messageString, senderID) {
|
|||
id: senderID,
|
||||
hand: handToString(currentHand)
|
||||
});
|
||||
} else {
|
||||
if (state == STATES.waiting && connectingId == senderID) {
|
||||
} else if (state === STATES.WAITING && connectingId === senderID) {
|
||||
// the person you are trying to connect sent a request to someone else. See the
|
||||
// if statement above. So, don't cry, just start the handshake over again
|
||||
startHandshake();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "connectionAck":
|
||||
delete waitingList[senderID];
|
||||
if (state == STATES.waiting && (!connectingId || connectingId == senderID)) {
|
||||
if (message.id == MyAvatar.sessionUUID) {
|
||||
if (state === STATES.WAITING && (!connectingId || connectingId === senderID)) {
|
||||
if (message.id === MyAvatar.sessionUUID) {
|
||||
// start connecting...
|
||||
connectingId = senderID;
|
||||
connectingHand = message.hand;
|
||||
stopWaiting();
|
||||
startConnecting(senderID, message.hand);
|
||||
} else {
|
||||
if (connectingId) {
|
||||
} else if (connectingId) {
|
||||
// this is for someone else (we lost race in connectionRequest),
|
||||
// so lets start over
|
||||
startHandshake();
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: check to see if we are waiting for this but the person we are connecting sent it to
|
||||
// someone else, and try again
|
||||
break;
|
||||
case "connecting":
|
||||
delete waitingList[senderID];
|
||||
if (state == STATES.waiting && senderID == connectingId) {
|
||||
if (state === STATES.WAITING && senderID === connectingId) {
|
||||
// temporary logging
|
||||
if (connectingHand != message.hand) {
|
||||
if (connectingHand !== message.hand) {
|
||||
debug("connecting hand", connectingHand, "not same as connecting hand in message", message.hand);
|
||||
}
|
||||
connectingHand = message.hand;
|
||||
if (message.id != MyAvatar.sessionUUID) {
|
||||
if (message.id !== MyAvatar.sessionUUID) {
|
||||
// the person we were trying to connect is connecting to someone else
|
||||
// so try again
|
||||
startHandshake();
|
||||
|
@ -770,7 +789,7 @@ function messageHandler(channel, messageString, senderID) {
|
|||
break;
|
||||
case "done":
|
||||
delete waitingList[senderID];
|
||||
if (state == STATES.connecting && connectingId == senderID) {
|
||||
if (state === STATES.CONNECTING && connectingId === senderID) {
|
||||
// if they are done, and didn't connect us, terminate our
|
||||
// connecting
|
||||
if (message.connectionId !== MyAvatar.sessionUUID) {
|
||||
|
@ -783,10 +802,10 @@ function messageHandler(channel, messageString, senderID) {
|
|||
} else {
|
||||
// if waiting or inactive, lets clear the connecting id. If in makingConnection,
|
||||
// do nothing
|
||||
if (state != STATES.makingConnection && connectingId == senderID) {
|
||||
if (state !== STATES.MAKING_CONNECTION && connectingId === senderID) {
|
||||
connectingId = undefined;
|
||||
connectingHand = undefined;
|
||||
if (state != STATES.inactive) {
|
||||
if (state !== STATES.INACTIVE) {
|
||||
startHandshake();
|
||||
}
|
||||
}
|
||||
|
@ -796,13 +815,13 @@ function messageHandler(channel, messageString, senderID) {
|
|||
debug("unknown message", message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Messages.subscribe(MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.connect(messageHandler);
|
||||
Messages.subscribe(MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.connect(messageHandler);
|
||||
|
||||
|
||||
function makeGripHandler(hand, animate) {
|
||||
function makeGripHandler(hand, animate) {
|
||||
// determine if we are gripping or un-gripping
|
||||
if (animate) {
|
||||
return function(value) {
|
||||
|
@ -814,41 +833,43 @@ function makeGripHandler(hand, animate) {
|
|||
updateTriggers(value, false, hand);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
if ((event.text === "x") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
|
||||
function keyPressEvent(event) {
|
||||
if ((event.text === "x") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl &&
|
||||
!event.isAlt) {
|
||||
updateTriggers(1.0, true, Controller.Standard.RightHand);
|
||||
}
|
||||
}
|
||||
function keyReleaseEvent(event) {
|
||||
if ((event.text === "x") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
|
||||
}
|
||||
function keyReleaseEvent(event) {
|
||||
if ((event.text === "x") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl &&
|
||||
!event.isAlt) {
|
||||
updateTriggers(0.0, true, Controller.Standard.RightHand);
|
||||
}
|
||||
}
|
||||
// map controller actions
|
||||
var connectionMapping = Controller.newMapping(Script.resolvePath('') + '-grip');
|
||||
connectionMapping.from(Controller.Standard.LeftGrip).peek().to(makeGripHandler(Controller.Standard.LeftHand));
|
||||
connectionMapping.from(Controller.Standard.RightGrip).peek().to(makeGripHandler(Controller.Standard.RightHand));
|
||||
}
|
||||
// map controller actions
|
||||
var connectionMapping = Controller.newMapping(Script.resolvePath('') + '-grip');
|
||||
connectionMapping.from(Controller.Standard.LeftGrip).peek().to(makeGripHandler(Controller.Standard.LeftHand));
|
||||
connectionMapping.from(Controller.Standard.RightGrip).peek().to(makeGripHandler(Controller.Standard.RightHand));
|
||||
|
||||
// setup keyboard initiation
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
// setup keyboard initiation
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
|
||||
// xbox controller cuz that's important
|
||||
connectionMapping.from(Controller.Standard.RB).peek().to(makeGripHandler(Controller.Standard.RightHand, true));
|
||||
// Xbox controller because that is important
|
||||
connectionMapping.from(Controller.Standard.RB).peek().to(makeGripHandler(Controller.Standard.RightHand, true));
|
||||
|
||||
// it is easy to forget this and waste a lot of time for nothing
|
||||
connectionMapping.enable();
|
||||
// it is easy to forget this and waste a lot of time for nothing
|
||||
connectionMapping.enable();
|
||||
|
||||
// connect updateVisualization to update frequently
|
||||
Script.update.connect(updateVisualization);
|
||||
// connect updateVisualization to update frequently
|
||||
Script.update.connect(updateVisualization);
|
||||
|
||||
// load the sounds when the script loads
|
||||
handshakeSound = SoundCache.getSound(HANDSHAKE_SOUND_URL);
|
||||
successfulHandshakeSound = SoundCache.getSound(SUCCESSFUL_HANDSHAKE_SOUND_URL);
|
||||
// load the sounds when the script loads
|
||||
handshakeSound = SoundCache.getSound(HANDSHAKE_SOUND_URL);
|
||||
successfulHandshakeSound = SoundCache.getSound(SUCCESSFUL_HANDSHAKE_SOUND_URL);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
Script.scriptEnding.connect(function () {
|
||||
debug("removing controller mappings");
|
||||
connectionMapping.disable();
|
||||
debug("removing key mappings");
|
||||
|
@ -858,7 +879,6 @@ Script.scriptEnding.connect(function () {
|
|||
Script.update.disconnect(updateVisualization);
|
||||
deleteParticleEffect();
|
||||
deleteMakeConnectionParticleEffect();
|
||||
});
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
||||
|
|
Loading…
Reference in a new issue