From c72c6a0a4773c377524fecfb587b18b3c2cbcbe4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 21 Nov 2015 10:44:21 +1300 Subject: [PATCH 01/18] Make multiline strings from JavaScript's print() readably in log file Addresses quoting of newline characters as "\n" which was introduced in Qt 5.5. --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5326090723..f313cd7d9e 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -62,7 +62,7 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ } message += context->argument(i).toString(); } - qCDebug(scriptengine) << "script:print()<<" << message; + qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline message = message.replace("\\", "\\\\") .replace("\n", "\\n") From 75dfef067c790fd5c250bbaef74dc11d69713207 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 20 Nov 2015 14:40:27 -0800 Subject: [PATCH 02/18] test script --- examples/acScripts/acSessionID.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/acScripts/acSessionID.js diff --git a/examples/acScripts/acSessionID.js b/examples/acScripts/acSessionID.js new file mode 100644 index 0000000000..d32185daa1 --- /dev/null +++ b/examples/acScripts/acSessionID.js @@ -0,0 +1 @@ +print("sessionID:" + Agent.sessionUUID); \ No newline at end of file From a43b0e0ed8551a5227a80dbb86ee51929d5e9a80 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 20 Nov 2015 15:03:31 -0800 Subject: [PATCH 03/18] Remove obsolete script (superseed by animatedAvatarAgent.js), per https://app.asana.com/0/26225263936266/55964805077915/f (This PR does _not_ remove proceduralAnimationAPI.js that it includes, as the api is included in other scripts. Nor does this PR remove other scripts.) --- examples/acScripts/bot_procedural.js | 673 --------------------------- 1 file changed, 673 deletions(-) delete mode 100644 examples/acScripts/bot_procedural.js diff --git a/examples/acScripts/bot_procedural.js b/examples/acScripts/bot_procedural.js deleted file mode 100644 index 18d42a0e60..0000000000 --- a/examples/acScripts/bot_procedural.js +++ /dev/null @@ -1,673 +0,0 @@ -// -// bot_procedural.js -// hifi -// -// Created by Ben Arnold on 7/29/2013 -// -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// This is an example script that demonstrates an NPC avatar. -// -// - -//For procedural walk animation -HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -Script.include(HIFI_PUBLIC_BUCKET + "scripts/acScripts/proceduralAnimationAPI.js"); - -var procAnimAPI = new ProcAnimAPI(); - -function getRandomFloat(min, max) { - return Math.random() * (max - min) + min; -} - -function getRandomInt (min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -function printVector(string, vector) { - print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); -} - -var CHANCE_OF_MOVING = 0.005; -var CHANCE_OF_SOUND = 0.005; -var CHANCE_OF_HEAD_TURNING = 0.01; -var CHANCE_OF_BIG_MOVE = 1.0; - -var isMoving = false; -var isTurningHead = false; -var isPlayingAudio = false; - -var X_MIN = 0.50; -var X_MAX = 15.60; -var Z_MIN = 0.50; -var Z_MAX = 15.10; -var Y_FEET = 0.0; -var AVATAR_PELVIS_HEIGHT = 0.84; -var Y_PELVIS = Y_FEET + AVATAR_PELVIS_HEIGHT; -var MAX_PELVIS_DELTA = 2.5; - -var MOVE_RANGE_SMALL = 3.0; -var MOVE_RANGE_BIG = 10.0; -var TURN_RANGE = 70.0; -var STOP_TOLERANCE = 0.05; -var MOVE_RATE = 0.05; -var TURN_RATE = 0.2; -var HEAD_TURN_RATE = 0.05; -var PITCH_RANGE = 15.0; -var YAW_RANGE = 35.0; - -var firstPosition = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) }; -var targetPosition = { x: 0, y: 0, z: 0 }; -var targetOrientation = { x: 0, y: 0, z: 0, w: 0 }; -var currentOrientation = { x: 0, y: 0, z: 0, w: 0 }; -var targetHeadPitch = 0.0; -var targetHeadYaw = 0.0; - -var basePelvisHeight = 0.0; -var pelvisOscillatorPosition = 0.0; -var pelvisOscillatorVelocity = 0.0; - -function clamp(val, min, max){ - return Math.max(min, Math.min(max, val)) -} - -//Array of all valid bot numbers -var validBotNumbers = []; - -// right now we only use bot 63, since many other bots have messed up skeletons and LOD issues -var botNumber = 63;//getRandomInt(0, 99); - -var newFaceFilePrefix = "ron"; - -var newBodyFilePrefix = "bot" + botNumber; - -// set the face model fst using the bot number -// there is no need to change the body model - we're using the default -Avatar.faceModelURL = HIFI_PUBLIC_BUCKET + "meshes/" + newFaceFilePrefix + ".fst"; -Avatar.skeletonModelURL = HIFI_PUBLIC_BUCKET + "meshes/" + newBodyFilePrefix + "_a.fst"; -Avatar.billboardURL = HIFI_PUBLIC_BUCKET + "meshes/billboards/bot" + botNumber + ".png"; - -Agent.isAvatar = true; -Agent.isListeningToAudioStream = true; - -// change the avatar's position to the random one -Avatar.position = firstPosition; -basePelvisHeight = firstPosition.y; -printVector("New dancer, position = ", Avatar.position); - -function loadSounds() { - var sound_filenames = ["AB1.raw", "Anchorman2.raw", "B1.raw", "B1.raw", "Bale1.raw", "Bandcamp.raw", - "Big1.raw", "Big2.raw", "Brian1.raw", "Buster1.raw", "CES1.raw", "CES2.raw", "CES3.raw", "CES4.raw", - "Carrie1.raw", "Carrie3.raw", "Charlotte1.raw", "EN1.raw", "EN2.raw", "EN3.raw", "Eugene1.raw", "Francesco1.raw", - "Italian1.raw", "Japanese1.raw", "Leigh1.raw", "Lucille1.raw", "Lucille2.raw", "MeanGirls.raw", "Murray2.raw", - "Nigel1.raw", "PennyLane.raw", "Pitt1.raw", "Ricardo.raw", "SN.raw", "Sake1.raw", "Samantha1.raw", "Samantha2.raw", - "Spicoli1.raw", "Supernatural.raw", "Swearengen1.raw", "TheDude.raw", "Tony.raw", "Triumph1.raw", "Uma1.raw", - "Walken1.raw", "Walken2.raw", "Z1.raw", "Z2.raw" - ]; - - var footstep_filenames = ["FootstepW2Left-12db.wav", "FootstepW2Right-12db.wav", "FootstepW3Left-12db.wav", "FootstepW3Right-12db.wav", - "FootstepW5Left-12db.wav", "FootstepW5Right-12db.wav"]; - - var SOUND_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Raws/"; - - var FOOTSTEP_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Footsteps/"; - - for (var i = 0; i < sound_filenames.length; i++) { - sounds.push(SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i])); - } - - for (var i = 0; i < footstep_filenames.length; i++) { - footstepSounds.push(SoundCache.getSound(FOOTSTEP_BASE_URL + footstep_filenames[i])); - } -} - -var sounds = []; -var footstepSounds = []; -loadSounds(); - - -function playRandomSound() { - if (!Agent.isPlayingAvatarSound) { - var whichSound = Math.floor((Math.random() * sounds.length)); - Agent.playAvatarSound(sounds[whichSound]); - } -} - -function playRandomFootstepSound() { - var whichSound = Math.floor((Math.random() * footstepSounds.length)); - Audio.playSound(footstepSounds[whichSound], { - position: Avatar.position, - volume: 1.0 - }); -} - -// ************************************ Facial Animation ********************************** -var allBlendShapes = []; -var targetBlendCoefficient = []; -var currentBlendCoefficient = []; - -//Blendshape constructor -function addBlendshapeToPose(pose, shapeIndex, val) { - var index = pose.blendShapes.length; - pose.blendShapes[index] = {shapeIndex: shapeIndex, val: val }; -} -//The mood of the avatar, determines face. 0 = happy, 1 = angry, 2 = sad. - -//Randomly pick avatar mood. 80% happy, 10% mad 10% sad -var randMood = Math.floor(Math.random() * 11); -var avatarMood; -if (randMood == 0) { - avatarMood = 1; -} else if (randMood == 2) { - avatarMood = 2; -} else { - avatarMood = 0; -} - -var currentExpression = -1; -//Face pose constructor -var happyPoses = []; - -happyPoses[0] = {blendShapes: []}; -addBlendshapeToPose(happyPoses[0], 28, 0.7); //MouthSmile_L -addBlendshapeToPose(happyPoses[0], 29, 0.7); //MouthSmile_R - -happyPoses[1] = {blendShapes: []}; -addBlendshapeToPose(happyPoses[1], 28, 1.0); //MouthSmile_L -addBlendshapeToPose(happyPoses[1], 29, 1.0); //MouthSmile_R -addBlendshapeToPose(happyPoses[1], 21, 0.2); //JawOpen - -happyPoses[2] = {blendShapes: []}; -addBlendshapeToPose(happyPoses[2], 28, 1.0); //MouthSmile_L -addBlendshapeToPose(happyPoses[2], 29, 1.0); //MouthSmile_R -addBlendshapeToPose(happyPoses[2], 21, 0.5); //JawOpen -addBlendshapeToPose(happyPoses[2], 46, 1.0); //CheekSquint_L -addBlendshapeToPose(happyPoses[2], 47, 1.0); //CheekSquint_R -addBlendshapeToPose(happyPoses[2], 17, 1.0); //BrowsU_L -addBlendshapeToPose(happyPoses[2], 18, 1.0); //BrowsU_R - -var angryPoses = []; - -angryPoses[0] = {blendShapes: []}; -addBlendshapeToPose(angryPoses[0], 26, 0.6); //MouthFrown_L -addBlendshapeToPose(angryPoses[0], 27, 0.6); //MouthFrown_R -addBlendshapeToPose(angryPoses[0], 14, 0.6); //BrowsD_L -addBlendshapeToPose(angryPoses[0], 15, 0.6); //BrowsD_R - -angryPoses[1] = {blendShapes: []}; -addBlendshapeToPose(angryPoses[1], 26, 0.9); //MouthFrown_L -addBlendshapeToPose(angryPoses[1], 27, 0.9); //MouthFrown_R -addBlendshapeToPose(angryPoses[1], 14, 0.9); //BrowsD_L -addBlendshapeToPose(angryPoses[1], 15, 0.9); //BrowsD_R - -angryPoses[2] = {blendShapes: []}; -addBlendshapeToPose(angryPoses[2], 26, 1.0); //MouthFrown_L -addBlendshapeToPose(angryPoses[2], 27, 1.0); //MouthFrown_R -addBlendshapeToPose(angryPoses[2], 14, 1.0); //BrowsD_L -addBlendshapeToPose(angryPoses[2], 15, 1.0); //BrowsD_R -addBlendshapeToPose(angryPoses[2], 21, 0.5); //JawOpen -addBlendshapeToPose(angryPoses[2], 46, 1.0); //CheekSquint_L -addBlendshapeToPose(angryPoses[2], 47, 1.0); //CheekSquint_R - -var sadPoses = []; - -sadPoses[0] = {blendShapes: []}; -addBlendshapeToPose(sadPoses[0], 26, 0.6); //MouthFrown_L -addBlendshapeToPose(sadPoses[0], 27, 0.6); //MouthFrown_R -addBlendshapeToPose(sadPoses[0], 16, 0.2); //BrowsU_C -addBlendshapeToPose(sadPoses[0], 2, 0.6); //EyeSquint_L -addBlendshapeToPose(sadPoses[0], 3, 0.6); //EyeSquint_R - -sadPoses[1] = {blendShapes: []}; -addBlendshapeToPose(sadPoses[1], 26, 0.9); //MouthFrown_L -addBlendshapeToPose(sadPoses[1], 27, 0.9); //MouthFrown_R -addBlendshapeToPose(sadPoses[1], 16, 0.6); //BrowsU_C -addBlendshapeToPose(sadPoses[1], 2, 0.9); //EyeSquint_L -addBlendshapeToPose(sadPoses[1], 3, 0.9); //EyeSquint_R - -sadPoses[2] = {blendShapes: []}; -addBlendshapeToPose(sadPoses[2], 26, 1.0); //MouthFrown_L -addBlendshapeToPose(sadPoses[2], 27, 1.0); //MouthFrown_R -addBlendshapeToPose(sadPoses[2], 16, 0.1); //BrowsU_C -addBlendshapeToPose(sadPoses[2], 2, 1.0); //EyeSquint_L -addBlendshapeToPose(sadPoses[2], 3, 1.0); //EyeSquint_R -addBlendshapeToPose(sadPoses[2], 21, 0.3); //JawOpen - -var facePoses = []; -facePoses[0] = happyPoses; -facePoses[1] = angryPoses; -facePoses[2] = sadPoses; - - -function addBlendShape(s) { - allBlendShapes[allBlendShapes.length] = s; -} - -//It is imperative that the following blendshapes are all present and are in the correct order -addBlendShape("EyeBlink_L"); //0 -addBlendShape("EyeBlink_R"); //1 -addBlendShape("EyeSquint_L"); //2 -addBlendShape("EyeSquint_R"); //3 -addBlendShape("EyeDown_L"); //4 -addBlendShape("EyeDown_R"); //5 -addBlendShape("EyeIn_L"); //6 -addBlendShape("EyeIn_R"); //7 -addBlendShape("EyeOpen_L"); //8 -addBlendShape("EyeOpen_R"); //9 -addBlendShape("EyeOut_L"); //10 -addBlendShape("EyeOut_R"); //11 -addBlendShape("EyeUp_L"); //12 -addBlendShape("EyeUp_R"); //13 -addBlendShape("BrowsD_L"); //14 -addBlendShape("BrowsD_R"); //15 -addBlendShape("BrowsU_C"); //16 -addBlendShape("BrowsU_L"); //17 -addBlendShape("BrowsU_R"); //18 -addBlendShape("JawFwd"); //19 -addBlendShape("JawLeft"); //20 -addBlendShape("JawOpen"); //21 -addBlendShape("JawChew"); //22 -addBlendShape("JawRight"); //23 -addBlendShape("MouthLeft"); //24 -addBlendShape("MouthRight"); //25 -addBlendShape("MouthFrown_L"); //26 -addBlendShape("MouthFrown_R"); //27 -addBlendShape("MouthSmile_L"); //28 -addBlendShape("MouthSmile_R"); //29 -addBlendShape("MouthDimple_L"); //30 -addBlendShape("MouthDimple_R"); //31 -addBlendShape("LipsStretch_L"); //32 -addBlendShape("LipsStretch_R"); //33 -addBlendShape("LipsUpperClose"); //34 -addBlendShape("LipsLowerClose"); //35 -addBlendShape("LipsUpperUp"); //36 -addBlendShape("LipsLowerDown"); //37 -addBlendShape("LipsUpperOpen"); //38 -addBlendShape("LipsLowerOpen"); //39 -addBlendShape("LipsFunnel"); //40 -addBlendShape("LipsPucker"); //41 -addBlendShape("ChinLowerRaise"); //42 -addBlendShape("ChinUpperRaise"); //43 -addBlendShape("Sneer"); //44 -addBlendShape("Puff"); //45 -addBlendShape("CheekSquint_L"); //46 -addBlendShape("CheekSquint_R"); //47 - -for (var i = 0; i < allBlendShapes.length; i++) { - targetBlendCoefficient[i] = 0; - currentBlendCoefficient[i] = 0; -} - -function setRandomExpression() { - - //Clear all expression data for current expression - if (currentExpression != -1) { - var expression = facePoses[avatarMood][currentExpression]; - for (var i = 0; i < expression.blendShapes.length; i++) { - targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = 0.0; - } - } - //Get a new current expression - currentExpression = Math.floor(Math.random() * facePoses[avatarMood].length); - var expression = facePoses[avatarMood][currentExpression]; - for (var i = 0; i < expression.blendShapes.length; i++) { - targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = expression.blendShapes[i].val; - } -} - -var expressionChangeSpeed = 0.1; -function updateBlendShapes(deltaTime) { - - for (var i = 0; i < allBlendShapes.length; i++) { - currentBlendCoefficient[i] += (targetBlendCoefficient[i] - currentBlendCoefficient[i]) * expressionChangeSpeed; - Avatar.setBlendshape(allBlendShapes[i], currentBlendCoefficient[i]); - } -} - -var BLINK_SPEED = 0.15; -var CHANCE_TO_BLINK = 0.0025; -var MAX_BLINK = 0.85; -var blink = 0.0; -var isBlinking = false; -function updateBlinking(deltaTime) { - if (isBlinking == false) { - if (Math.random() < CHANCE_TO_BLINK) { - isBlinking = true; - } else { - blink -= BLINK_SPEED; - if (blink < 0.0) blink = 0.0; - } - } else { - blink += BLINK_SPEED; - if (blink > MAX_BLINK) { - blink = MAX_BLINK; - isBlinking = false; - } - } - - currentBlendCoefficient[0] = blink; - currentBlendCoefficient[1] = blink; - targetBlendCoefficient[0] = blink; - targetBlendCoefficient[1] = blink; -} - -// ************************************************************************************* - -//Procedural walk animation using two keyframes -//We use a separate array for front and back joints -//Pitch, yaw, and roll for the joints -var rightAngles = []; -var leftAngles = []; -//for non mirrored joints such as the spine -var middleAngles = []; - -//Actual joint mappings -var SHOULDER_JOINT_NUMBER = 15; -var ELBOW_JOINT_NUMBER = 16; -var JOINT_R_HIP = 1; -var JOINT_R_KNEE = 2; -var JOINT_L_HIP = 6; -var JOINT_L_KNEE = 7; -var JOINT_R_ARM = 15; -var JOINT_R_FOREARM = 16; -var JOINT_L_ARM = 39; -var JOINT_L_FOREARM = 40; -var JOINT_SPINE = 11; -var JOINT_R_FOOT = 3; -var JOINT_L_FOOT = 8; -var JOINT_R_TOE = 4; -var JOINT_L_TOE = 9; - -// ******************************* Animation Is Defined Below ************************************* - -var NUM_FRAMES = 2; -for (var i = 0; i < NUM_FRAMES; i++) { - rightAngles[i] = []; - leftAngles[i] = []; - middleAngles[i] = []; -} -//Joint order for actual joint mappings, should be interleaved R,L,R,L,...S,S,S for R = right, L = left, S = single -var JOINT_ORDER = []; -//*** right / left joints *** -var HIP = 0; -JOINT_ORDER.push(JOINT_R_HIP); -JOINT_ORDER.push(JOINT_L_HIP); -var KNEE = 1; -JOINT_ORDER.push(JOINT_R_KNEE); -JOINT_ORDER.push(JOINT_L_KNEE); -var ARM = 2; -JOINT_ORDER.push(JOINT_R_ARM); -JOINT_ORDER.push(JOINT_L_ARM); -var FOREARM = 3; -JOINT_ORDER.push(JOINT_R_FOREARM); -JOINT_ORDER.push(JOINT_L_FOREARM); -var FOOT = 4; -JOINT_ORDER.push(JOINT_R_FOOT); -JOINT_ORDER.push(JOINT_L_FOOT); -var TOE = 5; -JOINT_ORDER.push(JOINT_R_TOE); -JOINT_ORDER.push(JOINT_L_TOE); -//*** middle joints *** -var SPINE = 0; -JOINT_ORDER.push(JOINT_SPINE); - -//We have to store the angles so we can invert yaw and roll when making the animation -//symmetrical - -//Front refers to leg, not arm. -//Legs Extending -rightAngles[0][HIP] = [30.0, 0.0, 8.0]; -rightAngles[0][KNEE] = [-15.0, 0.0, 0.0]; -rightAngles[0][ARM] = [85.0, -25.0, 0.0]; -rightAngles[0][FOREARM] = [0.0, 0.0, -15.0]; -rightAngles[0][FOOT] = [0.0, 0.0, 0.0]; -rightAngles[0][TOE] = [0.0, 0.0, 0.0]; - -leftAngles[0][HIP] = [-15, 0.0, 8.0]; -leftAngles[0][KNEE] = [-26, 0.0, 0.0]; -leftAngles[0][ARM] = [85.0, 20.0, 0.0]; -leftAngles[0][FOREARM] = [10.0, 0.0, -25.0]; -leftAngles[0][FOOT] = [-13.0, 0.0, 0.0]; -leftAngles[0][TOE] = [34.0, 0.0, 0.0]; - -middleAngles[0][SPINE] = [0.0, -15.0, 5.0]; - -//Legs Passing -rightAngles[1][HIP] = [6.0, 0.0, 8.0]; -rightAngles[1][KNEE] = [-12.0, 0.0, 0.0]; -rightAngles[1][ARM] = [85.0, 0.0, 0.0]; -rightAngles[1][FOREARM] = [0.0, 0.0, -15.0]; -rightAngles[1][FOOT] = [6.0, -8.0, 0.0]; -rightAngles[1][TOE] = [0.0, 0.0, 0.0]; - -leftAngles[1][HIP] = [10.0, 0.0, 8.0]; -leftAngles[1][KNEE] = [-60.0, 0.0, 0.0]; -leftAngles[1][ARM] = [85.0, 0.0, 0.0]; -leftAngles[1][FOREARM] = [0.0, 0.0, -15.0]; -leftAngles[1][FOOT] = [0.0, 0.0, 0.0]; -leftAngles[1][TOE] = [0.0, 0.0, 0.0]; - -middleAngles[1][SPINE] = [0.0, 0.0, 0.0]; - -//Actual keyframes for the animation -var walkKeyFrames = procAnimAPI.generateKeyframes(rightAngles, leftAngles, middleAngles, NUM_FRAMES); - -// ******************************* Animation Is Defined Above ************************************* - -// ********************************** Standing Key Frame ****************************************** -//We don't have to do any mirroring or anything, since this is just a single pose. -var rightQuats = []; -var leftQuats = []; -var middleQuats = []; - -rightQuats[HIP] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 7.0); -rightQuats[KNEE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); -rightQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); -rightQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, -10.0); -rightQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, -8.0, 0.0); -rightQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); - -leftQuats[HIP] = Quat.fromPitchYawRollDegrees(0, 0.0, -7.0); -leftQuats[KNEE] = Quat.fromPitchYawRollDegrees(0, 0.0, 0.0); -leftQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0); -leftQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 10.0); -leftQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, 8.0, 0.0); -leftQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); - -middleQuats[SPINE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0); - -var standingKeyFrame = new procAnimAPI.KeyFrame(rightQuats, leftQuats, middleQuats); - -// ************************************************************************************************ - - -var currentFrame = 0; - -var walkTime = 0.0; - -var walkWheelRadius = 0.5; -var walkWheelRate = 2.0 * 3.141592 * walkWheelRadius / 8.0; - -var avatarAcceleration = 0.75; -var avatarVelocity = 0.0; -var avatarMaxVelocity = 1.4; - -function handleAnimation(deltaTime) { - - updateBlinking(deltaTime); - updateBlendShapes(deltaTime); - - if (Math.random() < 0.01) { - setRandomExpression(); - } - - if (avatarVelocity == 0.0) { - walkTime = 0.0; - currentFrame = 0; - } else { - walkTime += avatarVelocity * deltaTime; - if (walkTime > walkWheelRate) { - walkTime = 0.0; - currentFrame++; - if (currentFrame % 2 == 1) { - playRandomFootstepSound(); - } - if (currentFrame > 3) { - currentFrame = 0; - } - } - } - - var frame = walkKeyFrames[currentFrame]; - - var walkInterp = walkTime / walkWheelRate; - var animInterp = avatarVelocity / (avatarMaxVelocity / 1.3); - if (animInterp > 1.0) animInterp = 1.0; - - for (var i = 0; i < JOINT_ORDER.length; i++) { - var walkJoint = procAnimAPI.deCasteljau(frame.rotations[i], frame.nextFrame.rotations[i], frame.controlPoints[i][0], frame.controlPoints[i][1], walkInterp); - var standJoint = standingKeyFrame.rotations[i]; - var finalJoint = Quat.mix(standJoint, walkJoint, animInterp); - Avatar.setJointData(JOINT_ORDER[i], finalJoint); - } -} - -function jumpWithLoudness(deltaTime) { - // potentially change pelvis height depending on trailing average loudness - - pelvisOscillatorVelocity += deltaTime * Agent.lastReceivedAudioLoudness * 700.0 ; - - pelvisOscillatorVelocity -= pelvisOscillatorPosition * 0.75; - pelvisOscillatorVelocity *= 0.97; - pelvisOscillatorPosition += deltaTime * pelvisOscillatorVelocity; - Avatar.headPitch = pelvisOscillatorPosition * 60.0; - - var pelvisPosition = Avatar.position; - pelvisPosition.y = (Y_PELVIS - 0.35) + pelvisOscillatorPosition; - - if (pelvisPosition.y < Y_PELVIS) { - pelvisPosition.y = Y_PELVIS; - } else if (pelvisPosition.y > Y_PELVIS + 1.0) { - pelvisPosition.y = Y_PELVIS + 1.0; - } - - Avatar.position = pelvisPosition; -} - -var forcedMove = false; - -var wasMovingLastFrame = false; - -function handleHeadTurn() { - if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) { - targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE); - targetHeadYaw = getRandomFloat(-YAW_RANGE, YAW_RANGE); - isTurningHead = true; - } else { - Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * HEAD_TURN_RATE; - Avatar.headYaw = Avatar.headYaw + (targetHeadYaw - Avatar.headYaw) * HEAD_TURN_RATE; - if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE && - Math.abs(Avatar.headYaw - targetHeadYaw) < STOP_TOLERANCE) { - isTurningHead = false; - } - } -} - -function stopWalking() { - avatarVelocity = 0.0; - isMoving = false; -} - -var MAX_ATTEMPTS = 40; -function handleWalking(deltaTime) { - - if (forcedMove || (!isMoving && Math.random() < CHANCE_OF_MOVING)) { - // Set new target location - - var moveRange; - if (Math.random() < CHANCE_OF_BIG_MOVE) { - moveRange = MOVE_RANGE_BIG; - } else { - moveRange = MOVE_RANGE_SMALL; - } - - //Keep trying new orientations if the desired target location is out of bounds - var attempts = 0; - do { - targetOrientation = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 })); - var front = Quat.getFront(targetOrientation); - - targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, moveRange))); - } - while ((targetPosition.x < X_MIN || targetPosition.x > X_MAX || targetPosition.z < Z_MIN || targetPosition.z > Z_MAX) - && attempts < MAX_ATTEMPTS); - - targetPosition.x = clamp(targetPosition.x, X_MIN, X_MAX); - targetPosition.z = clamp(targetPosition.z, Z_MIN, Z_MAX); - targetPosition.y = Y_PELVIS; - - wasMovingLastFrame = true; - isMoving = true; - forcedMove = false; - } else if (isMoving) { - - var targetVector = Vec3.subtract(targetPosition, Avatar.position); - var distance = Vec3.length(targetVector); - if (distance <= avatarVelocity * deltaTime) { - Avatar.position = targetPosition; - stopWalking(); - } else { - var direction = Vec3.normalize(targetVector); - //Figure out if we should be slowing down - var t = avatarVelocity / avatarAcceleration; - var d = (avatarVelocity / 2.0) * t; - if (distance < d) { - avatarVelocity -= avatarAcceleration * deltaTime; - if (avatarVelocity <= 0) { - stopWalking(); - } - } else { - avatarVelocity += avatarAcceleration * deltaTime; - if (avatarVelocity > avatarMaxVelocity) avatarVelocity = avatarMaxVelocity; - } - Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(direction, avatarVelocity * deltaTime)); - Avatar.orientation = Quat.mix(Avatar.orientation, targetOrientation, TURN_RATE); - - wasMovingLastFrame = true; - - } - } -} - -function handleTalking() { - if (Math.random() < CHANCE_OF_SOUND) { - playRandomSound(); - } -} - -function changePelvisHeight(newHeight) { - var newPosition = Avatar.position; - newPosition.y = newHeight; - Avatar.position = newPosition; -} - -function updateBehavior(deltaTime) { - - if (AvatarList.containsAvatarWithDisplayName("mrdj")) { - if (wasMovingLastFrame) { - isMoving = false; - } - - // we have a DJ, shouldn't we be dancing? - jumpWithLoudness(deltaTime); - } else { - - // no DJ, let's just chill on the dancefloor - randomly walking and talking - handleHeadTurn(); - handleAnimation(deltaTime); - handleWalking(deltaTime); - handleTalking(); - } -} - -Script.update.connect(updateBehavior); \ No newline at end of file From aba65bd9b8484d5bc93cfa98e04922cc370c2dd7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 20 Nov 2015 15:45:08 -0800 Subject: [PATCH 04/18] rename linearDamping to damping --- examples/FlockOfbirds.js | 2 +- examples/libraries/easyStarExample.js | 2 +- examples/toybox/basketball/createRack.js | 4 ++-- examples/toybox/basketball/createSingleBasketball.js | 2 +- examples/toybox/blockers/createTestBlocks.js | 6 +++--- examples/toybox/bubblewand/wand.js | 4 ++-- examples/toybox/ping_pong_gun/pingPongGun.js | 2 +- unpublishedScripts/basketballsResetter.js | 2 +- unpublishedScripts/hiddenEntityReset.js | 12 ++++++------ unpublishedScripts/masterReset.js | 12 ++++++------ 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/FlockOfbirds.js b/examples/FlockOfbirds.js index dab086eff4..5d67c25c17 100644 --- a/examples/FlockOfbirds.js +++ b/examples/FlockOfbirds.js @@ -271,7 +271,7 @@ function loadBirds(howMany) { dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE }, gravity: { x: 0, y: BIRD_GRAVITY, z: 0 }, velocity: { x: 0, y: -0.1, z: 0 }, - linearDamping: LINEAR_DAMPING, + damping: LINEAR_DAMPING, collisionsWillMove: true, lifetime: STARTING_LIFETIME, color: colors[whichBird] diff --git a/examples/libraries/easyStarExample.js b/examples/libraries/easyStarExample.js index 20a50d2f7d..76c791a81f 100644 --- a/examples/libraries/easyStarExample.js +++ b/examples/libraries/easyStarExample.js @@ -76,7 +76,7 @@ var playerSphere = Entities.addEntity({ z: 0 }, collisionsWillMove: true, - linearDamping: 0.2 + damping: 0.2 }); Script.setInterval(function(){ diff --git a/examples/toybox/basketball/createRack.js b/examples/toybox/basketball/createRack.js index cda1a115d4..aee492f684 100644 --- a/examples/toybox/basketball/createRack.js +++ b/examples/toybox/basketball/createRack.js @@ -41,7 +41,7 @@ var rack = Entities.addEntity({ y: -9.8, z: 0 }, - linearDamping: 1, + damping: 1, dimensions: { x: 0.4, y: 1.37, @@ -83,7 +83,7 @@ function createBalls() { z: DIAMETER }, restitution: 1.0, - linearDamping: 0.00001, + damping: 0.00001, gravity: { x: 0, y: -9.8, diff --git a/examples/toybox/basketball/createSingleBasketball.js b/examples/toybox/basketball/createSingleBasketball.js index 162b572bd1..a1e0140553 100644 --- a/examples/toybox/basketball/createSingleBasketball.js +++ b/examples/toybox/basketball/createSingleBasketball.js @@ -46,7 +46,7 @@ function makeBasketball() { collisionSoundURL: collisionSoundURL, modelURL: basketballURL, restitution: 1.0, - linearDamping: 0.00001, + damping: 0.00001, shapeType: "sphere" }); originalPosition = position; diff --git a/examples/toybox/blockers/createTestBlocks.js b/examples/toybox/blockers/createTestBlocks.js index d92d8d2b32..10bdb14d76 100644 --- a/examples/toybox/blockers/createTestBlocks.js +++ b/examples/toybox/blockers/createTestBlocks.js @@ -88,7 +88,7 @@ var topBlock = Entities.addEntity({ dimensions: blockDimensions, position: topBlock_position, rotation: topBlock_rotation, - linearDamping: LINEAR_DAMPING, + damping: LINEAR_DAMPING, gravity: BLOCK_GRAVITY, collisionsWillMove: true, velocity: { @@ -106,7 +106,7 @@ var sideBlock1 = Entities.addEntity({ dimensions: blockDimensions, position: sideBlock1_position, rotation: sideBlock1_rotation, - linearDamping: LINEAR_DAMPING, + damping: LINEAR_DAMPING, gravity: BLOCK_GRAVITY, collisionsWillMove: true }); @@ -120,7 +120,7 @@ var sideBlock2 = Entities.addEntity({ position: sideBlock2_position, rotation: sideBlock2_rotation, collsionsWillMove: true, - linearDamping: LINEAR_DAMPING, + damping: LINEAR_DAMPING, gravity: BLOCK_GRAVITY, collisionsWillMove: true }); diff --git a/examples/toybox/bubblewand/wand.js b/examples/toybox/bubblewand/wand.js index f429ef6d55..a6e4eae34d 100644 --- a/examples/toybox/bubblewand/wand.js +++ b/examples/toybox/bubblewand/wand.js @@ -28,7 +28,7 @@ var BUBBLE_LIFETIME_MAX = 8; var BUBBLE_SIZE_MIN = 0.02; var BUBBLE_SIZE_MAX = 0.1; - var BUBBLE_LINEAR_DAMPING = 0.4; + var BUBBLE_LINEAR_DAMPING = 0.2; var BUBBLE_GRAVITY_MIN = 0.1; var BUBBLE_GRAVITY_MAX = 0.3; var GROWTH_FACTOR = 0.005; @@ -163,7 +163,7 @@ dimensions: BUBBLE_INITIAL_DIMENSIONS, collisionsWillMove: false, ignoreForCollisions: true, - linearDamping: BUBBLE_LINEAR_DAMPING, + damping: BUBBLE_LINEAR_DAMPING, shapeType: "sphere" }); diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js index 48b82f0a36..bd8b5f710d 100644 --- a/examples/toybox/ping_pong_gun/pingPongGun.js +++ b/examples/toybox/ping_pong_gun/pingPongGun.js @@ -123,7 +123,7 @@ type:'Sphere', color: BALL_COLOR, dimensions: BALL_DIMENSIONS, - linearDamping: BALL_LINEAR_DAMPING, + damping: BALL_LINEAR_DAMPING, gravity: BALL_GRAVITY, restitution: BALL_RESTITUTION, collisionsWillMove: true, diff --git a/unpublishedScripts/basketballsResetter.js b/unpublishedScripts/basketballsResetter.js index 791ac1c0cf..6b8bc75f0d 100644 --- a/unpublishedScripts/basketballsResetter.js +++ b/unpublishedScripts/basketballsResetter.js @@ -75,7 +75,7 @@ var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; z: DIAMETER }, restitution: 1.0, - linearDamping: 0.00001, + damping: 0.00001, gravity: { x: 0, y: -9.8, diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index a8b4383b04..cf9eaaa451 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -253,7 +253,7 @@ y: -9.8, z: 0 }, - linearDamping: 1, + damping: 1, dimensions: { x: 0.4, y: 1.37, @@ -301,7 +301,7 @@ z: DIAMETER }, restitution: 1.0, - linearDamping: 0.00001, + damping: 0.00001, gravity: { x: 0, y: -9.8, @@ -871,7 +871,7 @@ y: -100, z: 0 }, - linearDamping: 1, + damping: 1, angularDamping: 10, mass: 10, userData: JSON.stringify({ @@ -990,7 +990,7 @@ z: 0 }, restitution: 10, - linearDamping: 0.0, + damping: 0.0, velocity: { x: 0, y: -0.01, @@ -1113,7 +1113,7 @@ y: 0, z: 0 }, - linearDamping: 0.4, + damping: 0.4, userData: JSON.stringify({ resetMe: { resetMe: true @@ -1156,7 +1156,7 @@ y: 0, z: 0 }, - linearDamping: 0.2, + damping: 0.2, userData: JSON.stringify({ resetMe: { resetMe: true diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 1b4c83a1d5..60b4e7a72f 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -233,7 +233,7 @@ MasterReset = function() { y: -9.8, z: 0 }, - linearDamping: 1, + damping: 1, dimensions: { x: 0.4, y: 1.37, @@ -282,7 +282,7 @@ MasterReset = function() { z: DIAMETER }, restitution: 1.0, - linearDamping: 0.00001, + damping: 0.00001, gravity: { x: 0, y: -9.8, @@ -853,7 +853,7 @@ MasterReset = function() { y: -100, z: 0 }, - linearDamping: 1, + damping: 1, angularDamping: 10, mass: 10, userData: JSON.stringify({ @@ -973,7 +973,7 @@ MasterReset = function() { z: 0 }, restitution: 10, - linearDamping: 0.0, + damping: 0.01, velocity: { x: 0, y: -0.01, @@ -1096,7 +1096,7 @@ MasterReset = function() { y: 0, z: 0 }, - linearDamping: 0.4, + damping: 0.4, userData: JSON.stringify({ resetMe: { resetMe: true @@ -1139,7 +1139,7 @@ MasterReset = function() { y: 0, z: 0 }, - linearDamping: 0.2, + damping: 0.2, userData: JSON.stringify({ resetMe: { resetMe: true From 46bb45cee937ef9b910b06883da61e5e773ea767 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Fri, 20 Nov 2015 11:47:49 -0800 Subject: [PATCH 05/18] Agents/Master upgrading --- examples/acScripts/playbackAgents.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index c50c727277..a84701354e 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -52,24 +52,19 @@ function getAction(channel, message, senderID) { if (command.id_key == id || command.id_key == -1) { if (command.action_key === 6) { - clip_url = command.clip_url_key; - // If the id is -1 (broadcast) and the action is 6, in the url should be the performance file - // with all the clips recorded in a session (not just the single clip url). - // It has to be computed here in order to retrieve the url for the single agent. - // Checking the id we can assign the correct url to the correct agent. + clip_url = command.clip_url_key; if (command.id_key == -1) { Assets.downloadData(clip_url, function (data) { var myJSONObject = JSON.parse(data); - var hash = myJSONObject.results[id].hashATP; + var hash = myJSONObject.avatarClips[id]; }); - Assets.downloadData(hash, function (data) { - clip_url = JSON.parse(data); - }); + clip_url = hash; } } + action = command.action_key; print("That command was for me!"); From f56d2fba7f651af6b06b22dec4a6260f6d3c499a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 20 Nov 2015 16:00:43 -0800 Subject: [PATCH 06/18] allow playbackAgents to auto-register --- assignment-client/src/Agent.cpp | 6 +++- assignment-client/src/Agent.h | 4 +++ examples/acScripts/playbackAgents.js | 46 ++++++++++++++++++++++------ examples/acScripts/playbackMaster.js | 34 +++++++++++++++++--- 4 files changed, 74 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2fdba9e256..5cdceb06ae 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -223,7 +223,6 @@ void Agent::executeScript() { AvatarData::fromFrame(frame->data, *scriptedAvatar); }); - using namespace recording; static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::AUDIO_FRAME_NAME); Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) { @@ -280,6 +279,11 @@ void Agent::executeScript() { setFinished(true); } +QUuid Agent::getSessionUUID() const { + return DependencyManager::get()->getSessionUUID(); +} + + void Agent::setIsAvatar(bool isAvatar) { _isAvatar = isAvatar; diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 6819976633..274e5f3b55 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,8 @@ class Agent : public ThreadedAssignment { Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound) Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream) Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness) + Q_PROPERTY(QUuid sessionUUID READ getSessionUUID) + public: Agent(NLPacket& packet); @@ -47,6 +50,7 @@ public: void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; } float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; } + QUuid getSessionUUID() const; virtual void aboutToFinish(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index c50c727277..66c3696fe3 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -10,7 +10,7 @@ // // Set the following variables to the values needed -var channel = "PlaybackChannel1"; +var commandChannel = "com.highfidelity.PlaybackChannel1"; var clip_url = null; var playFromCurrentLocation = true; var useDisplayName = true; @@ -18,7 +18,9 @@ var useAttachments = true; var useAvatarModel = true; // ID of the agent. Two agents can't have the same ID. -var id = 0; +var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; +var UNKNOWN_AGENT_ID = -2; +var id = UNKNOWN_AGENT_ID; // unknown until aknowledged // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -45,7 +47,6 @@ Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); function getAction(channel, message, senderID) { - if(subscribed) { var command = JSON.parse(message); print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); @@ -139,17 +140,42 @@ function getAction(channel, message, senderID) { } -function update(deltaTime) { +function update(deltaTime) { totalTime += deltaTime; - if (totalTime > WAIT_FOR_AUDIO_MIXER && !subscribed) { - Messages.subscribe(channel); - subscribed = true; - print("I'm the agent and I am ready to receive!") + if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (!subscribed) { + Messages.subscribe(commandChannel); // command channel + Messages.subscribe(announceIDChannel); // id announce channel + subscribed = true; + print("I'm the agent and I am ready to receive!"); + } + if (subscribed && id == UNKNOWN_AGENT_ID) { + print("sending ready, id:" + id); + Messages.sendMessage(announceIDChannel, "ready"); + } } + } -Script.update.connect(update); -Messages.messageReceived.connect(getAction); +Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == announceIDChannel && message != "ready") { + // If I don't yet know if my ID has been recieved, then check to see if the master has acknowledged me + if (id == UNKNOWN_AGENT_ID) { + var parts = message.split("."); + var agentID = parts[0]; + var agentIndex = parts[1]; + if (agentID == Agent.sessionUUID) { + id = agentIndex; + Messages.unsubscribe(announceIDChannel); // id announce channel + } + } + } + if (channel == commandChannel) { + getAction(channel, message, senderID); + } +}); + +Script.update.connect(update); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index e3448c0256..4703f0e4fd 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,11 +14,16 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) -var channel = "PlaybackChannel1"; +var channel = "com.highfidelity.PlaybackChannel1"; var subscribed = false; var clip_url = null; var input_text = null; +var knownAgents = new Array; // We will add our known agents here when we discover them + +// available playbackAgents will announce their sessionID here. +var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; + // Script. DO NOT MODIFY BEYOND THIS LINE. Script.include("../libraries/toolBars.js"); @@ -51,8 +56,9 @@ setupPlayback(); function setupPlayback() { ac_number = Window.prompt("Insert number of agents: ","1"); - if (ac_number === "" || ac_number === null) + if (ac_number === "" || ac_number === null) { ac_number = 1; + } Messages.subscribe(channel); subscribed = true; setupToolBars(); @@ -134,7 +140,6 @@ function setupToolBars() { } function sendCommand(id, action) { - if (action === SHOW) { toolBars[id].selectTool(onOffIcon[id], false); toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); @@ -151,8 +156,9 @@ function sendCommand(id, action) { return; } - if (id == (toolBars.length - 1)) + if (id == (toolBars.length - 1)) { id = -1; // Master command becomes broadcast. + } var message = { id_key: id, @@ -249,12 +255,30 @@ function scriptEnding() { Overlays.deleteOverlay(nameOverlays[i]); } - if(subscribed) + if (subscribed) { Messages.unsubscribe(channel); + } + Messages.unsubscribe(announceIDChannel); } Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); + + +Messages.subscribe(announceIDChannel); +Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == announceIDChannel && message == "ready") { + // check to see if we know about this agent + if (knownAgents.indexOf(senderID) < 0) { + var indexOfNewAgent = knownAgents.length; + knownAgents[indexOfNewAgent] = senderID; + var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Messages.sendMessage(announceIDChannel, acknowledgeMessage); + } + + } +}); + moveUI(); \ No newline at end of file From 985fcf7c4b0619e6414d466bb41d045fc466b0a4 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 20 Nov 2015 16:02:01 -0800 Subject: [PATCH 07/18] remove unneeded example --- examples/acScripts/acSessionID.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 examples/acScripts/acSessionID.js diff --git a/examples/acScripts/acSessionID.js b/examples/acScripts/acSessionID.js deleted file mode 100644 index d32185daa1..0000000000 --- a/examples/acScripts/acSessionID.js +++ /dev/null @@ -1 +0,0 @@ -print("sessionID:" + Agent.sessionUUID); \ No newline at end of file From 1b18d3656ffeee15c7cc5db0f91bdcbc7977b702 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Thu, 19 Nov 2015 19:36:17 -0800 Subject: [PATCH 08/18] Save clip to asset --- .../src/RecordingScriptingInterface.cpp | 56 +++++++++++++++++++ .../src/RecordingScriptingInterface.h | 9 +++ 2 files changed, 65 insertions(+) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 83e44ef173..fbabdc73af 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -18,10 +18,15 @@ #include #include +#include +#include + #include "ScriptEngineLogging.h" using namespace recording; +static const QString HFR_EXTENSION = ".hfr"; +const QString URL_SCHEME_ATP = "atp"; RecordingScriptingInterface::RecordingScriptingInterface() { _player = DependencyManager::get(); @@ -171,6 +176,57 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) { recording::Clip::toFile(filename, _lastClip); } +bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUrl) { + + if (!getClipAtpUrl.isFunction()) + return false; + + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "saveRecordingToAsset", Qt::BlockingQueuedConnection, + Q_ARG(QScriptValue, getClipAtpUrl)); + return false; + } + + if (!_lastClip) { + qWarning() << "There is no recording to save"; + return false; + } + + QString filename = "./temp.hfr"; + recording::Clip::toFile(filename, _lastClip); + + QUrl url{ filename }; + + if (auto upload = DependencyManager::get()->createUpload(url.toLocalFile())) { // Here we should use the other implementation of createUpload, but we need the QByteArray of the _lastClip + + QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { + auto filename = QFileInfo(upload->getFilename()).fileName(); + QString clip_atp_url = ""; + + if (upload->getError() == AssetUpload::NoError) { + + clip_atp_url = QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, upload->getExtension()); + upload->deleteLater(); + } else { + AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash); + } + + QScriptValueList args; + args << clip_atp_url; + getClipAtpUrl.call(QScriptValue(), args); + }); + + // start the upload now + upload->start(); + return true; + + } + + return false; + +} + + void RecordingScriptingInterface::loadLastRecording() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "loadLastRecording", Qt::BlockingQueuedConnection); diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index b39485d75c..704e10efa1 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -18,6 +18,11 @@ #include #include +#include +#include +#include +#include "../../../interface/src/ui/AssetUploadDialogFactory.h" + class RecordingScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -60,6 +65,7 @@ public slots: float recorderElapsed() const; void saveRecording(const QString& filename); + bool saveRecordingToAsset(QScriptValue getClipAtpUrl); void loadLastRecording(); protected: @@ -76,6 +82,9 @@ protected: Flag _useAttachments { false }; Flag _useSkeletonModel { false }; recording::ClipPointer _lastClip; + +private: + void clipUploadFinished(AssetUpload* upload, const QString& hash); }; #endif // hifi_RecordingScriptingInterface_h From 1db6d0e3c192b669e03a46f938b3ca5ee43c0f66 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Thu, 19 Nov 2015 22:51:36 -0800 Subject: [PATCH 09/18] Upload QByteArray --- .../src/RecordingScriptingInterface.cpp | 21 +++++++------------ .../src/RecordingScriptingInterface.h | 3 --- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index fbabdc73af..128182d2a8 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -177,8 +177,7 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) { } bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUrl) { - - if (!getClipAtpUrl.isFunction()) + if (!getClipAtpUrl.isFunction()) return false; if (QThread::currentThread() != thread()) { @@ -192,13 +191,14 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return false; } - QString filename = "./temp.hfr"; - recording::Clip::toFile(filename, _lastClip); + //QString filename = "./temp.hfr"; + //recording::Clip::toFile(filename, _lastClip); - QUrl url{ filename }; - - if (auto upload = DependencyManager::get()->createUpload(url.toLocalFile())) { // Here we should use the other implementation of createUpload, but we need the QByteArray of the _lastClip + //QUrl url{ filename }; + //if (auto upload = DependencyManager::get()->createUpload(url.toLocalFile())) { + + if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) { QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { auto filename = QFileInfo(upload->getFilename()).fileName(); QString clip_atp_url = ""; @@ -215,18 +215,13 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr args << clip_atp_url; getClipAtpUrl.call(QScriptValue(), args); }); - - // start the upload now upload->start(); return true; - - } + } return false; - } - void RecordingScriptingInterface::loadLastRecording() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "loadLastRecording", Qt::BlockingQueuedConnection); diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index 704e10efa1..21aa9b35d4 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -82,9 +82,6 @@ protected: Flag _useAttachments { false }; Flag _useSkeletonModel { false }; recording::ClipPointer _lastClip; - -private: - void clipUploadFinished(AssetUpload* upload, const QString& hash); }; #endif // hifi_RecordingScriptingInterface_h From 35365f9157f24f13a2b79ce61858d9c18b148507 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Fri, 20 Nov 2015 13:32:55 -0800 Subject: [PATCH 10/18] Fixes --- libraries/script-engine/src/RecordingScriptingInterface.cpp | 5 ++--- libraries/script-engine/src/RecordingScriptingInterface.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 128182d2a8..34114fdf2f 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -25,8 +25,7 @@ using namespace recording; -static const QString HFR_EXTENSION = ".hfr"; -const QString URL_SCHEME_ATP = "atp"; +static const QString HFR_EXTENSION = "hfr"; RecordingScriptingInterface::RecordingScriptingInterface() { _player = DependencyManager::get(); @@ -208,7 +207,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr clip_atp_url = QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, upload->getExtension()); upload->deleteLater(); } else { - AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash); + qDebug() << "Error during the Asset upload."; } QScriptValueList args; diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index 21aa9b35d4..c1287a42d7 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -21,7 +21,6 @@ #include #include #include -#include "../../../interface/src/ui/AssetUploadDialogFactory.h" class RecordingScriptingInterface : public QObject, public Dependency { Q_OBJECT From e70f6855aa355c09f3a559dc66124bb5635cc008 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Fri, 20 Nov 2015 13:36:57 -0800 Subject: [PATCH 11/18] Fixes --- .../script-engine/src/RecordingScriptingInterface.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 34114fdf2f..36ef88354e 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -190,14 +190,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return false; } - //QString filename = "./temp.hfr"; - //recording::Clip::toFile(filename, _lastClip); - - //QUrl url{ filename }; - - //if (auto upload = DependencyManager::get()->createUpload(url.toLocalFile())) { - - if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) { + if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) { QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { auto filename = QFileInfo(upload->getFilename()).fileName(); QString clip_atp_url = ""; From df2153186d6c6005137f0854cd7dad0bddd72c07 Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Fri, 20 Nov 2015 16:04:28 -0800 Subject: [PATCH 12/18] Fixes --- .../src/RecordingScriptingInterface.cpp | 19 ++++++++++++++----- .../src/RecordingScriptingInterface.h | 4 +--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 36ef88354e..1a88d6e260 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -18,6 +18,10 @@ #include #include + +#include +#include +#include #include #include @@ -176,13 +180,18 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) { } bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUrl) { - if (!getClipAtpUrl.isFunction()) + if (!getClipAtpUrl.isFunction()) { + qCWarning(scriptengine) << "The argument is not a function."; return false; + } + if (QThread::currentThread() != thread()) { + bool result{ false }; QMetaObject::invokeMethod(this, "saveRecordingToAsset", Qt::BlockingQueuedConnection, - Q_ARG(QScriptValue, getClipAtpUrl)); - return false; + Q_ARG(QScriptValue, getClipAtpUrl), + Q_RETURN_ARG(bool, result)); + return result; } if (!_lastClip) { @@ -192,7 +201,6 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr if (auto upload = DependencyManager::get()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) { QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { - auto filename = QFileInfo(upload->getFilename()).fileName(); QString clip_atp_url = ""; if (upload->getError() == AssetUpload::NoError) { @@ -200,7 +208,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr clip_atp_url = QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, upload->getExtension()); upload->deleteLater(); } else { - qDebug() << "Error during the Asset upload."; + qCWarning(scriptengine) << "Error during the Asset upload."; } QScriptValueList args; @@ -211,6 +219,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return true; } + qCWarning(scriptengine) << "Saving on asset failed."; return false; } diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index c1287a42d7..9661ee9d80 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -18,9 +18,7 @@ #include #include -#include -#include -#include +class QScriptValue; class RecordingScriptingInterface : public QObject, public Dependency { Q_OBJECT From 6e9e53bd0cb8f9485b2957dc9aa7f9c95cd655c5 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 20 Nov 2015 18:17:53 -0800 Subject: [PATCH 13/18] Clean up a bit of the playbackAgent script --- examples/acScripts/playbackAgents.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 918d8a1e1d..16dd469a89 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -53,20 +53,9 @@ function getAction(channel, message, senderID) { if (command.id_key == id || command.id_key == -1) { if (command.action_key === 6) { - clip_url = command.clip_url_key; - - if (command.id_key == -1) { - Assets.downloadData(clip_url, function (data) { - var myJSONObject = JSON.parse(data); - var hash = myJSONObject.avatarClips[id]; - }); - - clip_url = hash; - } } - - + action = command.action_key; print("That command was for me!"); print("My clip is: " + clip_url); @@ -173,4 +162,3 @@ Messages.messageReceived.connect(function (channel, message, senderID) { }); Script.update.connect(update); - From ebbed7c525c598e2e57783e3197e5a370cb9e5ee Mon Sep 17 00:00:00 2001 From: EdgarPironti Date: Fri, 20 Nov 2015 18:18:04 -0800 Subject: [PATCH 14/18] Save clip to asset - removing last fix --- .../script-engine/src/RecordingScriptingInterface.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 1a88d6e260..6f82e22b8d 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -185,13 +185,10 @@ bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUr return false; } - if (QThread::currentThread() != thread()) { - bool result{ false }; QMetaObject::invokeMethod(this, "saveRecordingToAsset", Qt::BlockingQueuedConnection, - Q_ARG(QScriptValue, getClipAtpUrl), - Q_RETURN_ARG(bool, result)); - return result; + Q_ARG(QScriptValue, getClipAtpUrl)); + return false; } if (!_lastClip) { From a306e8d5b1fe3b1d5bd9f5a17cada6398a5d20ce Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Thu, 19 Nov 2015 19:36:19 -0800 Subject: [PATCH 15/18] master can upload performance file on asset --- .../entityScripts/recordingEntityScript.js | 28 +++--- examples/entityScripts/recordingMaster.js | 86 +++++++++++++++++-- 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/examples/entityScripts/recordingEntityScript.js b/examples/entityScripts/recordingEntityScript.js index e423de9afd..dfbaf0a172 100644 --- a/examples/entityScripts/recordingEntityScript.js +++ b/examples/entityScripts/recordingEntityScript.js @@ -16,9 +16,11 @@ var _this; var isAvatarRecording = false; - var channel = "groupRecordingChannel"; - var startMessage = "RECONDING STARTED"; - var stopMessage = "RECONDING ENDED"; + var MASTER_TO_CLIENTS_CHANNEL = "startStopChannel"; + var CLIENTS_TO_MASTER_CHANNEL = "resultsChannel"; + var START_MESSAGE = "recordingStarted"; + var STOP_MESSAGE = "recordingEnded"; + var PARTICIPATING_MESSAGE = "participatingToRecording"; function recordingEntity() { _this = this; @@ -26,11 +28,13 @@ } function receivingMessage(channel, message, senderID) { - print("message received on channel:" + channel + ", message:" + message + ", senderID:" + senderID); - if(message === startMessage) { - _this.startRecording(); - } else if(message === stopMessage) { - _this.stopRecording(); + if(channel === MASTER_TO_CLIENTS_CHANNEL){ + print("CLIENT received message:" + message); + if(message === START_MESSAGE) { + _this.startRecording(); + } else if(message === STOP_MESSAGE) { + _this.stopRecording(); + } } }; @@ -50,19 +54,20 @@ enterEntity: function (entityID) { print("entering in the recording area"); - Messages.subscribe(channel); + Messages.subscribe(MASTER_TO_CLIENTS_CHANNEL); }, leaveEntity: function (entityID) { print("leaving the recording area"); _this.stopRecording(); - Messages.unsubscribe(channel); + Messages.unsubscribe(MASTER_TO_CLIENTS_CHANNEL); }, startRecording: function (entityID) { if (!isAvatarRecording) { print("RECORDING STARTED"); + Messages.sendMessage(CLIENTS_TO_MASTER_CHANNEL, PARTICIPATING_MESSAGE); //tell to master that I'm participating Recording.startRecording(); isAvatarRecording = true; } @@ -77,13 +82,14 @@ if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { Recording.saveRecording(recordingFile); } + Messages.sendMessage(CLIENTS_TO_MASTER_CHANNEL, recordingFile); //send back to the master the url } }, unload: function (entityID) { print("RECORDING ENTITY UNLOAD"); _this.stopRecording(); - Messages.unsubscribe(channel); + Messages.unsubscribe(MASTER_TO_CLIENTS_CHANNEL); Messages.messageReceived.disconnect(receivingMessage); } } diff --git a/examples/entityScripts/recordingMaster.js b/examples/entityScripts/recordingMaster.js index 27f84f44c2..c757f94300 100644 --- a/examples/entityScripts/recordingMaster.js +++ b/examples/entityScripts/recordingMaster.js @@ -22,11 +22,24 @@ var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/"; var ALPHA_ON = 1.0; var ALPHA_OFF = 0.7; var COLOR_TOOL_BAR = { red: 0, green: 0, blue: 0 }; +var MASTER_TO_CLIENTS_CHANNEL = "startStopChannel"; +var CLIENTS_TO_MASTER_CHANNEL = "resultsChannel"; +var START_MESSAGE = "recordingStarted"; +var STOP_MESSAGE = "recordingEnded"; +var PARTICIPATING_MESSAGE = "participatingToRecording"; +var TIMEOUT = 20; var toolBar = null; var recordIcon; var isRecording = false; -var channel = "groupRecordingChannel"; +var results = []; +var performanceJSON = null; +var responsesExpected = 0; +var waitingForPerformanceFile = true; +var totalWaitingTime = 0; +var extension = "txt"; + +Messages.subscribe(CLIENTS_TO_MASTER_CHANNEL); setupToolBar(); function setupToolBar() { @@ -55,22 +68,83 @@ function mousePressEvent(event) { if (recordIcon === toolBar.clicked(clickedOverlay, false)) { if (!isRecording) { print("I'm the master. I want to start recording"); - var message = "RECONDING STARTED"; - Messages.sendMessage(channel, message); + Messages.sendMessage(MASTER_TO_CLIENTS_CHANNEL, START_MESSAGE); isRecording = true; } else { print("I want to stop recording"); - var message = "RECONDING ENDED"; - Messages.sendMessage(channel, message); + waitingForPerformanceFile = true; + Script.update.connect(update); + Messages.sendMessage(MASTER_TO_CLIENTS_CHANNEL, STOP_MESSAGE); isRecording = false; } } } +function masterReceivingMessage(channel, message, senderID) { + if(channel === CLIENTS_TO_MASTER_CHANNEL) { + print("MASTER received message:" + message ); + if(message === PARTICIPATING_MESSAGE){ + //increment the counter of all the participants + responsesExpected++; + } else if(waitingForPerformanceFile) { + //I get a atp url from one participant + results[results.length] = message; + var textJSON = '{ "results" : ['; + for (var index = 0; index < results.length; index++) { + var newRecord = index === (results.length - 1) ? '{ "hashATP":"' + results[index] + '" }' : '{ "hashATP":"' + results[index] + '" },'; + textJSON += newRecord; + } + textJSON += ']}'; + performanceJSON = JSON.parse(textJSON); + } + + } + } + +function update(deltaTime) { + if(waitingForPerformanceFile) { + totalWaitingTime += deltaTime; + if(totalWaitingTime > TIMEOUT || results.length === responsesExpected) { + //I can upload the performance file on the asset + print("UPLOADING PERFORMANCE FILE"); + print(JSON.stringify(performanceJSON)); + if(performanceJSON !== null) { + //upload + Assets.uploadData(JSON.stringify(performanceJSON), extension, uploadFinished); + } + //clean things after upload performance file to asset + waitingForPerformanceFile = false; + responsesExpected = 0; + totalWaitingTime = 0; + Script.update.disconnect(update); + results = []; + performanceJSON = null; + } + } +} + +function uploadFinished(url){ + print("data uploaded to:" + url); + uploadedFile = url; + Assets.downloadData(url, function (data) { + print("data downloaded from:" + url + " the data is: "); + printPerformanceJSON(JSON.parse(data)); + }); +} + +function printPerformanceJSON(obj) { + var results = obj.results; + results.forEach(function(param) { + var hash = param.hashATP; + print("url obtained: " + hash); + }); +} + function cleanup() { toolBar.cleanup(); - Messages.unsubscribe(channel); + Messages.unsubscribe(CLIENTS_TO_MASTER_CHANNEL); } Script.scriptEnding.connect(cleanup); Controller.mousePressEvent.connect(mousePressEvent); +Messages.messageReceived.connect(masterReceivingMessage); \ No newline at end of file From 7069f7d6ab00e5e5783f573ad872086a9ca56c47 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Fri, 20 Nov 2015 15:22:18 -0800 Subject: [PATCH 16/18] added clip load to asset + clean code --- .../entityScripts/recordingEntityScript.js | 21 +++++--- examples/entityScripts/recordingMaster.js | 50 ++++++++----------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/examples/entityScripts/recordingEntityScript.js b/examples/entityScripts/recordingEntityScript.js index dfbaf0a172..8f5e9a03b9 100644 --- a/examples/entityScripts/recordingEntityScript.js +++ b/examples/entityScripts/recordingEntityScript.js @@ -25,19 +25,24 @@ function recordingEntity() { _this = this; return; - } + }; function receivingMessage(channel, message, senderID) { - if(channel === MASTER_TO_CLIENTS_CHANNEL){ + if (channel === MASTER_TO_CLIENTS_CHANNEL) { print("CLIENT received message:" + message); - if(message === START_MESSAGE) { + if (message === START_MESSAGE) { _this.startRecording(); - } else if(message === STOP_MESSAGE) { + } else if (message === STOP_MESSAGE) { _this.stopRecording(); } } }; + function getClipUrl(url) { + Messages.sendMessage(CLIENTS_TO_MASTER_CHANNEL, url); //send back the url to the master + print("clip uploaded and url sent to master"); + }; + recordingEntity.prototype = { preload: function (entityID) { @@ -55,7 +60,6 @@ enterEntity: function (entityID) { print("entering in the recording area"); Messages.subscribe(MASTER_TO_CLIENTS_CHANNEL); - }, leaveEntity: function (entityID) { @@ -78,11 +82,12 @@ print("RECORDING ENDED"); Recording.stopRecording(); isAvatarRecording = false; - recordingFile = Window.save("Save recording to file", "./groupRecording", "Recordings (*.hfr)"); + Recording.saveRecordingToAsset(getClipUrl); //save the clip to the asset and link a callback to get its url + + var recordingFile = Window.save("Save recording to file", "./groupRecording", "Recordings (*.hfr)"); if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { - Recording.saveRecording(recordingFile); + Recording.saveRecording(recordingFile); //save the clip locally } - Messages.sendMessage(CLIENTS_TO_MASTER_CHANNEL, recordingFile); //send back to the master the url } }, diff --git a/examples/entityScripts/recordingMaster.js b/examples/entityScripts/recordingMaster.js index c757f94300..cc3fa79026 100644 --- a/examples/entityScripts/recordingMaster.js +++ b/examples/entityScripts/recordingMaster.js @@ -32,13 +32,14 @@ var TIMEOUT = 20; var toolBar = null; var recordIcon; var isRecording = false; -var results = []; -var performanceJSON = null; +var avatarClips = []; +var performanceJSON = { "avatarClips" : [] }; var responsesExpected = 0; var waitingForPerformanceFile = true; var totalWaitingTime = 0; var extension = "txt"; + Messages.subscribe(CLIENTS_TO_MASTER_CHANNEL); setupToolBar(); @@ -81,35 +82,26 @@ function mousePressEvent(event) { } function masterReceivingMessage(channel, message, senderID) { - if(channel === CLIENTS_TO_MASTER_CHANNEL) { + if (channel === CLIENTS_TO_MASTER_CHANNEL) { print("MASTER received message:" + message ); - if(message === PARTICIPATING_MESSAGE){ + if (message === PARTICIPATING_MESSAGE) { //increment the counter of all the participants responsesExpected++; - } else if(waitingForPerformanceFile) { - //I get a atp url from one participant - results[results.length] = message; - var textJSON = '{ "results" : ['; - for (var index = 0; index < results.length; index++) { - var newRecord = index === (results.length - 1) ? '{ "hashATP":"' + results[index] + '" }' : '{ "hashATP":"' + results[index] + '" },'; - textJSON += newRecord; - } - textJSON += ']}'; - performanceJSON = JSON.parse(textJSON); + } else if (waitingForPerformanceFile) { + //I get an atp url from one participant + performanceJSON.avatarClips[performanceJSON.avatarClips.length] = message; } } } function update(deltaTime) { - if(waitingForPerformanceFile) { + if (waitingForPerformanceFile) { totalWaitingTime += deltaTime; - if(totalWaitingTime > TIMEOUT || results.length === responsesExpected) { - //I can upload the performance file on the asset + if (totalWaitingTime > TIMEOUT || performanceJSON.avatarClips.length === responsesExpected) { print("UPLOADING PERFORMANCE FILE"); - print(JSON.stringify(performanceJSON)); - if(performanceJSON !== null) { - //upload + if (performanceJSON.avatarClips.length !== 0) { + //I can upload the performance file on the asset Assets.uploadData(JSON.stringify(performanceJSON), extension, uploadFinished); } //clean things after upload performance file to asset @@ -117,26 +109,28 @@ function update(deltaTime) { responsesExpected = 0; totalWaitingTime = 0; Script.update.disconnect(update); - results = []; - performanceJSON = null; + avatarClips = []; + performanceJSON = { "avatarClips" : [] }; } } } function uploadFinished(url){ - print("data uploaded to:" + url); + print("some info:"); + print("performance file uploaded to: " + url); uploadedFile = url; Assets.downloadData(url, function (data) { - print("data downloaded from:" + url + " the data is: "); printPerformanceJSON(JSON.parse(data)); }); + //need to print somehow the url here //this way the master can copy the url + //Window.prompt(url); } function printPerformanceJSON(obj) { - var results = obj.results; - results.forEach(function(param) { - var hash = param.hashATP; - print("url obtained: " + hash); + print("downloaded performance file from asset and examinating its content..."); + var avatarClips = obj.avatarClips; + avatarClips.forEach(function(param) { + print("clip url obtained: " + param); }); } From a1053ee5a09af175178c2267ed904d462dacf259 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Fri, 20 Nov 2015 16:21:42 -0800 Subject: [PATCH 17/18] pop up a prompt with url --- examples/entityScripts/recordingEntityScript.js | 2 +- examples/entityScripts/recordingMaster.js | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/entityScripts/recordingEntityScript.js b/examples/entityScripts/recordingEntityScript.js index 8f5e9a03b9..132b064997 100644 --- a/examples/entityScripts/recordingEntityScript.js +++ b/examples/entityScripts/recordingEntityScript.js @@ -82,12 +82,12 @@ print("RECORDING ENDED"); Recording.stopRecording(); isAvatarRecording = false; - Recording.saveRecordingToAsset(getClipUrl); //save the clip to the asset and link a callback to get its url var recordingFile = Window.save("Save recording to file", "./groupRecording", "Recordings (*.hfr)"); if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { Recording.saveRecording(recordingFile); //save the clip locally } + Recording.saveRecordingToAsset(getClipUrl); //save the clip to the asset and link a callback to get its url } }, diff --git a/examples/entityScripts/recordingMaster.js b/examples/entityScripts/recordingMaster.js index cc3fa79026..70ae93075f 100644 --- a/examples/entityScripts/recordingMaster.js +++ b/examples/entityScripts/recordingMaster.js @@ -32,7 +32,6 @@ var TIMEOUT = 20; var toolBar = null; var recordIcon; var isRecording = false; -var avatarClips = []; var performanceJSON = { "avatarClips" : [] }; var responsesExpected = 0; var waitingForPerformanceFile = true; @@ -109,7 +108,6 @@ function update(deltaTime) { responsesExpected = 0; totalWaitingTime = 0; Script.update.disconnect(update); - avatarClips = []; performanceJSON = { "avatarClips" : [] }; } } @@ -122,8 +120,8 @@ function uploadFinished(url){ Assets.downloadData(url, function (data) { printPerformanceJSON(JSON.parse(data)); }); - //need to print somehow the url here //this way the master can copy the url - //Window.prompt(url); + //need to print somehow the url here this way the master can copy the url + Window.prompt("Performance file url: ", url); } function printPerformanceJSON(obj) { From 05d311cff31893bfb3a8e17b1fcde24ae3ef643a Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Fri, 20 Nov 2015 18:57:51 -0800 Subject: [PATCH 18/18] remove Windows.prompt cause of crash --- examples/entityScripts/recordingMaster.js | 27 ++++++++++------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/examples/entityScripts/recordingMaster.js b/examples/entityScripts/recordingMaster.js index 70ae93075f..732521cff7 100644 --- a/examples/entityScripts/recordingMaster.js +++ b/examples/entityScripts/recordingMaster.js @@ -81,18 +81,17 @@ function mousePressEvent(event) { } function masterReceivingMessage(channel, message, senderID) { - if (channel === CLIENTS_TO_MASTER_CHANNEL) { - print("MASTER received message:" + message ); - if (message === PARTICIPATING_MESSAGE) { - //increment the counter of all the participants - responsesExpected++; - } else if (waitingForPerformanceFile) { - //I get an atp url from one participant - performanceJSON.avatarClips[performanceJSON.avatarClips.length] = message; - } - + if (channel === CLIENTS_TO_MASTER_CHANNEL) { + print("MASTER received message:" + message ); + if (message === PARTICIPATING_MESSAGE) { + //increment the counter of all the participants + responsesExpected++; + } else if (waitingForPerformanceFile) { + //I get an atp url from one participant + performanceJSON.avatarClips[performanceJSON.avatarClips.length] = message; } } +} function update(deltaTime) { if (waitingForPerformanceFile) { @@ -114,17 +113,15 @@ function update(deltaTime) { } function uploadFinished(url){ - print("some info:"); - print("performance file uploaded to: " + url); - uploadedFile = url; + //need to print somehow the url here this way the master can copy the url + print("PERFORMANCE FILE URL: " + url); Assets.downloadData(url, function (data) { printPerformanceJSON(JSON.parse(data)); }); - //need to print somehow the url here this way the master can copy the url - Window.prompt("Performance file url: ", url); } function printPerformanceJSON(obj) { + print("some info:"); print("downloaded performance file from asset and examinating its content..."); var avatarClips = obj.avatarClips; avatarClips.forEach(function(param) {