From bba5bf7a21012302a49269bda3efa5051f4b8bb1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 24 Nov 2015 11:28:00 -0800 Subject: [PATCH 01/12] Trying to get the Agent to Mater more reliable --- examples/acScripts/playbackAgents.js | 48 ++++++++--- examples/acScripts/playbackMaster.js | 120 +++++++++++++++++++++------ 2 files changed, 132 insertions(+), 36 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 16dd469a89..864e821175 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -11,7 +11,6 @@ // Set the following variables to the values needed var commandChannel = "com.highfidelity.PlaybackChannel1"; -var clip_url = null; var playFromCurrentLocation = true; var useDisplayName = true; var useAttachments = true; @@ -22,6 +21,12 @@ var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; var UNKNOWN_AGENT_ID = -2; var id = UNKNOWN_AGENT_ID; // unknown until aknowledged +// The time between alive messages on the command channel +var timeSinceLastAlive = 0; +var ALIVE_PERIOD = 5; +var NUM_CYCLES_BEFORE_RESET = 5; +var notifyAlive = false; + // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); @@ -32,6 +37,7 @@ var subscribed = false; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. +var ALIVE = -1; var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -48,17 +54,14 @@ 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); if (command.id_key == id || command.id_key == -1) { - if (command.action_key === 6) { - clip_url = command.clip_url_key; - } action = command.action_key; - print("That command was for me!"); - print("My clip is: " + clip_url); + print("That command was for me! Agent with id: " + id); } else { action = DO_NOTHING; } @@ -104,11 +107,21 @@ function getAction(channel, message, senderID) { Agent.isAvatar = false; break; case LOAD: - print("Load"); - if(clip_url !== null) { - Recording.loadRecording(clip_url); + print("Load"); + if (!Agent.isAvatar) { + Agent.isAvatar = true; + } + if(command.clip_url_key !== null) { + print("Agent #" + id + " loading clip URL: " + command.clip_url_key); + Recording.loadRecording(command.clip_url_key); + } else { + print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; + case ALIVE: + print("Alive"); + notifyAlive = true; + break; case DO_NOTHING: break; default: @@ -136,11 +149,26 @@ function update(deltaTime) { 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"); } } + if (subscribed && id != UNKNOWN_AGENT_ID) { + timeSinceLastAlive += deltaTime; + if (notifyAlive) { + timeSinceLastAlive = 0; + notifyAlive = false; + print("Master Alive"); + } else if (timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { + print("Master Lost, reseting Agent"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + Agent.isAvatar = false; + id = UNKNOWN_AGENT_ID; + } + } } Messages.messageReceived.connect(function (channel, message, senderID) { diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 4703f0e4fd..2c9d4f77eb 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,9 +14,8 @@ 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 = "com.highfidelity.PlaybackChannel1"; +var commandChannel = "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 @@ -24,9 +23,15 @@ var knownAgents = new Array; // We will add our known agents here when we discov // 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"); +// The time between alive messages on the command channel +var timeSinceLastAlive = 0; +var ALIVE_PERIOD = 5; +// Script. DO NOT MODIFY BEYOND THIS LINE. +//Script.include("../libraries/toolBars.js"); +Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); + +var ALIVE = -1; var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -52,6 +57,9 @@ var playLoopIcon = new Array(); var stopIcon = new Array(); var loadIcon = new Array(); +var performanceJSON = null; +var performanceLoadedNeedUpdate = false; + setupPlayback(); function setupPlayback() { @@ -59,7 +67,7 @@ function setupPlayback() { if (ac_number === "" || ac_number === null) { ac_number = 1; } - Messages.subscribe(channel); + Messages.subscribe(commandChannel); subscribed = true; setupToolBars(); } @@ -139,7 +147,27 @@ function setupToolBars() { } } -function sendCommand(id, action) { +function loadAvatarClipsFromPerformanceJSON(performanceJSON) { + if (performanceJSON.avatarClips) { + var numClips = performanceJSON.avatarClips.length; + print("Performance file contains:" + JSON.stringify(performanceJSON)); + print("Number of clips in the performance file is: " + numClips + " Number of agents is: " + knownAgents.length); + + if (numClips > knownAgents.length) { + numClips = knownAgents.length; + } + + for (i = 0; i < numClips; i++) { + var clipURL = performanceJSON.avatarClips[i]; + print("Loading clip " + clipURL + " to Agent #" + i); + sendCommand(i, LOAD, clipURL); + } + } else { + print("Performance file cannot be interpreted:" + JSON.stringify(performanceJSON)); + } +} + +function sendCommand(id, action, argument) { if (action === SHOW) { toolBars[id].selectTool(onOffIcon[id], false); toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); @@ -152,24 +180,48 @@ function sendCommand(id, action) { toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); + } else if (action == ALIVE) { } else if (toolBars[id].toolSelected(onOffIcon[id])) { return; } if (id == (toolBars.length - 1)) { - id = -1; // Master command becomes broadcast. - } - - var message = { - id_key: id, - action_key: action, - clip_url_key: clip_url - }; - - if(subscribed){ - Messages.sendMessage(channel, JSON.stringify(message)); - print("Message sent!"); - clip_url = null; + + if (action == LOAD) { + if (performanceLoadedNeedUpdate == false) { + Assets.downloadData(argument, function (data) { + performanceJSON = JSON.parse(data); + performanceLoadedNeedUpdate = true; + // print("Performance file contains:" + JSON.stringify(performanceJSON)); + }); + return; + } + } else { + id = -1; + + var message = { + id_key: id, + action_key: action, + clip_url_key: argument + }; + + if(subscribed){ + Messages.sendMessage(commandChannel, JSON.stringify(message)); + print("Message sent!"); + } + } + } else { + + var message = { + id_key: id, + action_key: action, + clip_url_key: argument + }; + + if(subscribed){ + Messages.sendMessage(commandChannel, JSON.stringify(message)); + print("Message sent!"); + } } } @@ -193,8 +245,7 @@ function mousePressEvent(event) { } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - clip_url = input_text; - sendCommand(i, LOAD); + sendCommand(i, LOAD, input_text); } } else { // Check individual controls @@ -214,8 +265,7 @@ function mousePressEvent(event) { } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - clip_url = input_text; - sendCommand(i, LOAD); + sendCommand(i, LOAD, input_text); } } else { @@ -240,13 +290,25 @@ function moveUI() { } } -function update() { +function update(deltaTime) { var newDimensions = Controller.getViewportDimensions(); if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) { windowDimensions = newDimensions; moveUI(); } + + if (performanceLoadedNeedUpdate) { + loadAvatarClipsFromPerformanceJSON(performanceJSON); + performanceLoadedNeedUpdate = false; + } + + timeSinceLastAlive += deltaTime; + if (timeSinceLastAlive > ALIVE_PERIOD) { + timeSinceLastAlive = 0; + print("ping alive"); + sendCommand((toolBars.length - 1), ALIVE); + } } function scriptEnding() { @@ -256,7 +318,7 @@ function scriptEnding() { } if (subscribed) { - Messages.unsubscribe(channel); + Messages.unsubscribe(commandChannel); } Messages.unsubscribe(announceIDChannel); } @@ -272,13 +334,19 @@ 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) { + print("New agent to be hired " + senderID); var indexOfNewAgent = knownAgents.length; knownAgents[indexOfNewAgent] = senderID; var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Overlays.editOverlay(nameOverlays[indexOfNewAgent], { backgroundColor: { red: 0, green: 255, blue: 0 }, text: "Agent-Hired" } ); + print("Hired new Agent " + senderID + " #" + indexOfNewAgent); Messages.sendMessage(announceIDChannel, acknowledgeMessage); + } else { + + print("New agent still sending ready ? " + senderID); } } }); -moveUI(); \ No newline at end of file +moveUI(); From bad01d02f82d148f343d68ea449a60b31d2b577b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 24 Nov 2015 18:31:28 -0800 Subject: [PATCH 02/12] building the master/agent api --- examples/acScripts/AgentPoolControler.js | 214 +++++++++++++++++++++++ examples/acScripts/playbackAgents.js | 42 +++-- examples/acScripts/playbackMaster.js | 43 ++--- 3 files changed, 258 insertions(+), 41 deletions(-) create mode 100644 examples/acScripts/AgentPoolControler.js diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js new file mode 100644 index 0000000000..353480e2cf --- /dev/null +++ b/examples/acScripts/AgentPoolControler.js @@ -0,0 +1,214 @@ +// +// AgentPoolController.js +// acScripts +// +// Created by Sam Gateau on 11/23/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; +var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + +// The time between alive messages on the command channel +var ALIVE_PERIOD = 1; + +var NUM_CYCLES_BEFORE_RESET = 5; + +// Service Actions +var AGENT_READY = "ready"; +var INVALID_ACTOR = -2; + +var MASTER_INDEX = -1; + +var MASTER_ALIVE = -1; + +function printDebug(message) { + print(message); +} + +(function() { + + var makeMessage = function(id, action, argument) { + var message = { + id_key: id, + action_key: action, + argument_key: argument + }; + return message; + }; + + var unpackMessage = function(message) { + return JSON.parse(message); + }; + + // master side + var MasterController = function() { + this.timeSinceLastAlive = 0; + this.knownAgents = new Array; + this.subscribed = false; + }; + + MasterController.prototype.reset = function() { + if (this.subscribed) { + this.timeSinceLastAlive = 0; + + } + + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + + this.timeSinceLastAlive = 0; + + var localThis = this; + + Messages.messageReceived.connect(function (channel, message, senderID) { + printDebug("Agent received"); + if (channel == ANNOUNCE_CHANNEL) { + printDebug("Agent received"); + // localThis._processAgentMessage(message, senderID); + } + }); + + // ready to roll, enable + this.subscribed = true; + }; + + MasterController.prototype._processAgentMessage = function(message, senderID) { + if (message == AGENT_READY) { + + // check to see if we know about this agent + if (this.knownAgents.indexOf(senderID) < 0) { + + var indexOfNewAgent = this.knownAgents.length; + this.knownAgents[indexOfNewAgent] = senderID; + printDebug("New agent available to be hired " + senderID); + + var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); + } else { + + printDebug("New agent still sending ready ? " + senderID); + } + } + }; + + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.timeSinceLastAlive = 0; + this.subscribed = true; + } + }; + + MasterController.prototype.sendCommand = function(target, action, argument) { + if (this.subscribed) { + var messageJSON = JSON.stringify(makeMessage(target, action, argument)); + Messages.sendMessage(COMMAND_CHANNEL, messageJSON); + printDebug("Master sent message: " + messageJSON); + } + }; + + MasterController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + this.timeSinceLastAlive = 0; + printDebug("Master ping alive"); + this.sendCommand(MASTER_INDEX, MASTER_ALIVE); + } + }; + + + this.MasterController = MasterController; + + // agent side + var AgentController = function() { + this.timeSinceLastAlive = 0; + this.subscribed = false; + this.actorIndex = INVALID_ACTOR; + this.notifyAlive = false; + }; + + AgentController.prototype.reset = function() { + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + } + + this.timeSinceLastAlive = 0; + + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + if (message != AGENT_READY) { + // this may be a message to hire me if i m not already + if (id == INVALID_ACTOR) { + var parts = message.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + if (agentID == Agent.sessionUUID) { + // localThis.actorIndex = agentIndex; + Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + } + } + } + return; + } + if (channel == COMMAND_CHANNEL) { + var command = unpackMessage(message); + printDebug("Received command = " == command); + + if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { + if (command.action_key == MASTER_ALIVE) { + // localThis.notifyAlive = true; + } else { + // localThis._processMasterMessage(command, senderID); + } + } else { + // ignored + } + return; + } + }); + + // ready to roll, enable + this.subscribed = true; + printDebug("In Reset"); + }; + + AgentController.prototype._processMasterMessage = function(command, senderID) { + printDebug("True action received = " + JSON.stringify(command) + senderID); + }; + + AgentController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.subscribed) { + printDebug("In update of client"); + if (this.actorIndex == INVALID_ACTOR) { + Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); + printDebug("Client Ready"); + } else { + if (this.notifyAlive) { + this.notifyAlive = false; + printDebug("Master Alive"); + } else if (this.timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { + printDebug("Master Lost, reseting Agent"); + this.actorIndex = UNKNOWN_AGENT_ID; + } + } + } + + this.timeSinceLastAlive = 0; + } + }; + + + this.AgentController = AgentController; +})(); + + + diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 864e821175..96502a7816 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -8,24 +8,27 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Agent.isAvatar = true; +Script.include("./AgentPoolControler.js"); // Set the following variables to the values needed -var commandChannel = "com.highfidelity.PlaybackChannel1"; var playFromCurrentLocation = true; var useDisplayName = true; var useAttachments = true; var useAvatarModel = true; +var agentController = new AgentController(); + // ID of the agent. Two agents can't have the same ID. -var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; -var UNKNOWN_AGENT_ID = -2; -var id = UNKNOWN_AGENT_ID; // unknown until aknowledged +//var UNKNOWN_AGENT_ID = -2; +//var id = UNKNOWN_AGENT_ID; // unknown until aknowledged // The time between alive messages on the command channel -var timeSinceLastAlive = 0; +/*var timeSinceLastAlive = 0; var ALIVE_PERIOD = 5; var NUM_CYCLES_BEFORE_RESET = 5; var notifyAlive = false; +*/ // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -118,7 +121,7 @@ function getAction(channel, message, senderID) { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case ALIVE: + case MASTER_ALIVE: print("Alive"); notifyAlive = true; break; @@ -138,10 +141,16 @@ function getAction(channel, message, senderID) { function update(deltaTime) { - + totalTime += deltaTime; + if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (!agentController.subscribed) { + agentController.reset(); + } + } + /* + totalTime += deltaTime; - - if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!subscribed) { Messages.subscribe(commandChannel); // command channel Messages.subscribe(announceIDChannel); // id announce channel @@ -168,9 +177,11 @@ function update(deltaTime) { Agent.isAvatar = false; id = UNKNOWN_AGENT_ID; } - } -} + }*/ + agentController.update(deltaTime); +} +/* 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 @@ -187,6 +198,13 @@ Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == commandChannel) { getAction(channel, message, senderID); } -}); +});*/ + +function scriptEnding() { + + agentController.destroy(); +} + Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 2c9d4f77eb..eb7f86518f 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -8,30 +8,22 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("./AgentPoolControler.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var masterController = new MasterController(); 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 commandChannel = "com.highfidelity.PlaybackChannel1"; -var subscribed = false; 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"; - -// The time between alive messages on the command channel -var timeSinceLastAlive = 0; -var ALIVE_PERIOD = 5; // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); -var ALIVE = -1; + var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -67,9 +59,8 @@ function setupPlayback() { if (ac_number === "" || ac_number === null) { ac_number = 1; } - Messages.subscribe(commandChannel); - subscribed = true; setupToolBars(); + masterController.reset(); } function setupToolBars() { @@ -180,7 +171,6 @@ function sendCommand(id, action, argument) { toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); - } else if (action == ALIVE) { } else if (toolBars[id].toolSelected(onOffIcon[id])) { return; } @@ -199,6 +189,8 @@ function sendCommand(id, action, argument) { } else { id = -1; + masterController.sendMessage(id, action, argument); + /* var message = { id_key: id, action_key: action, @@ -208,10 +200,11 @@ function sendCommand(id, action, argument) { if(subscribed){ Messages.sendMessage(commandChannel, JSON.stringify(message)); print("Message sent!"); - } + }*/ } } else { - + masterController.sendMessage(id, action, argument); + /* var message = { id_key: id, action_key: action, @@ -221,7 +214,7 @@ function sendCommand(id, action, argument) { if(subscribed){ Messages.sendMessage(commandChannel, JSON.stringify(message)); print("Message sent!"); - } + }*/ } } @@ -303,12 +296,7 @@ function update(deltaTime) { performanceLoadedNeedUpdate = false; } - timeSinceLastAlive += deltaTime; - if (timeSinceLastAlive > ALIVE_PERIOD) { - timeSinceLastAlive = 0; - print("ping alive"); - sendCommand((toolBars.length - 1), ALIVE); - } + masterController.update(deltaTime); } function scriptEnding() { @@ -317,10 +305,7 @@ function scriptEnding() { Overlays.deleteOverlay(nameOverlays[i]); } - if (subscribed) { - Messages.unsubscribe(commandChannel); - } - Messages.unsubscribe(announceIDChannel); + masterController.destroy(); } Controller.mousePressEvent.connect(mousePressEvent); @@ -328,7 +313,7 @@ Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); - +/* Messages.subscribe(announceIDChannel); Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message == "ready") { @@ -348,5 +333,5 @@ Messages.messageReceived.connect(function (channel, message, senderID) { } }); - +*/ moveUI(); From 574eb3dc99d2e8115dbccac953ab1d3ea0333d23 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Wed, 25 Nov 2015 02:50:12 -0800 Subject: [PATCH 03/12] Improving the Master/Agent api --- examples/acScripts/AgentPoolControler.js | 221 +++++++++++++---------- examples/acScripts/playbackAgents.js | 95 +++------- examples/acScripts/playbackMaster.js | 44 ----- 3 files changed, 147 insertions(+), 213 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 353480e2cf..60b906381a 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -9,27 +9,26 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; -var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; - -// The time between alive messages on the command channel -var ALIVE_PERIOD = 1; - -var NUM_CYCLES_BEFORE_RESET = 5; - -// Service Actions -var AGENT_READY = "ready"; -var INVALID_ACTOR = -2; - -var MASTER_INDEX = -1; - -var MASTER_ALIVE = -1; - function printDebug(message) { print(message); } (function() { + var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; + var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + + // The time between alive messages on the command channel + var ALIVE_PERIOD = 3; + var NUM_CYCLES_BEFORE_RESET = 5; + + // Service Actions + var AGENT_READY = "ready"; + var INVALID_ACTOR = -2; + + var MASTER_INDEX = -1; + + var MASTER_ALIVE = -1; + var MASTER_FIRE_AGENT = -2; var makeMessage = function(id, action, argument) { var message = { @@ -45,38 +44,41 @@ function printDebug(message) { }; // master side + //--------------------------------- var MasterController = function() { this.timeSinceLastAlive = 0; this.knownAgents = new Array; this.subscribed = false; }; - MasterController.prototype.reset = function() { - if (this.subscribed) { - this.timeSinceLastAlive = 0; - + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; } + }; - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - - this.timeSinceLastAlive = 0; - - var localThis = this; - - Messages.messageReceived.connect(function (channel, message, senderID) { - printDebug("Agent received"); - if (channel == ANNOUNCE_CHANNEL) { - printDebug("Agent received"); - // localThis._processAgentMessage(message, senderID); - } - }); + MasterController.prototype.reset = function() { + this.timeSinceLastAlive = 0; + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + }); + } // ready to roll, enable this.subscribed = true; + printDebug("Master Started"); }; - MasterController.prototype._processAgentMessage = function(message, senderID) { + MasterController.prototype._processAnnounceMessage = function(message, senderID) { if (message == AGENT_READY) { // check to see if we know about this agent @@ -89,20 +91,10 @@ function printDebug(message) { var acknowledgeMessage = senderID + "." + indexOfNewAgent; Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); } else { - printDebug("New agent still sending ready ? " + senderID); } } }; - - MasterController.prototype.destroy = function() { - if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.timeSinceLastAlive = 0; - this.subscribed = true; - } - }; MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { @@ -121,83 +113,109 @@ function printDebug(message) { } }; - this.MasterController = MasterController; // agent side + //--------------------------------- var AgentController = function() { + this.subscribed = false; + this.timeSinceLastAlive = 0; - this.subscribed = false; + this.numCyclesWithoutAlive = 0; this.actorIndex = INVALID_ACTOR; this.notifyAlive = false; + + this.onHired = function() {}; + this.onCommand = function(command) {}; + this.onFired = function() {}; }; + AgentController.prototype.destroy = function() { + if (this.subscribed) { + this.fire(); + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; + AgentController.prototype.reset = function() { + // If already hired, fire + this.fired(); + if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); Messages.subscribe(ANNOUNCE_CHANNEL); - } - - this.timeSinceLastAlive = 0; - - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - if (message != AGENT_READY) { - // this may be a message to hire me if i m not already - if (id == INVALID_ACTOR) { - var parts = message.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; - if (agentID == Agent.sessionUUID) { - // localThis.actorIndex = agentIndex; - Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - } - } - } - return; - } - if (channel == COMMAND_CHANNEL) { - var command = unpackMessage(message); - printDebug("Received command = " == command); - - if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { - if (command.action_key == MASTER_ALIVE) { - // localThis.notifyAlive = true; - } else { - // localThis._processMasterMessage(command, senderID); - } - } else { - // ignored + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; } - return; - } - }); - - // ready to roll, enable + if (channel == COMMAND_CHANNEL) { + localThis._processCommandMessage(message, senderID); + return; + } + }); + } this.subscribed = true; - printDebug("In Reset"); + printDebug("Client Started"); }; - AgentController.prototype._processMasterMessage = function(command, senderID) { - printDebug("True action received = " + JSON.stringify(command) + senderID); + AgentController.prototype._processAnnounceMessage = function(message, senderID) { + //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); + if (message != AGENT_READY) { + // this may be a message to hire me if i m not already + if (this.actorIndex == INVALID_ACTOR) { + var parts = message.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); + if (agentID == Agent.sessionUUID) { + this.actorIndex = actorIndex; + printDebug("Client " + this.actorIndex + " Hired!"); + this.onHired(); + // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + } + } + } + } + + AgentController.prototype._processCommandMessage = function(message, senderID) { + var command = unpackMessage(message); + //printDebug("Received command = " + JSON.stringify(command)); + + if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { + if (command.action_key == MASTER_ALIVE) { + this.notifyAlive = true; + } else if (command.action_key == MASTER_FIRE_AGENT) { + printDebug("Master firing Agent"); + this.fire(); + } else { + printDebug("True action received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } + } else { + // ignored + } }; AgentController.prototype.update = function(deltaTime) { this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.timeSinceLastAlive > ALIVE_PERIOD) { if (this.subscribed) { - printDebug("In update of client"); if (this.actorIndex == INVALID_ACTOR) { Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); - printDebug("Client Ready"); + //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); } else { - if (this.notifyAlive) { + this.numCyclesWithoutAlive++; + if (this.notifyAlive) { this.notifyAlive = false; + this.numCyclesWithoutAlive = 0; printDebug("Master Alive"); - } else if (this.timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { - printDebug("Master Lost, reseting Agent"); - this.actorIndex = UNKNOWN_AGENT_ID; + } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, firing Agent"); + this.fired(); } } } @@ -206,6 +224,19 @@ function printDebug(message) { } }; + AgentController.prototype.fired = function() { + // clear the state first + var wasHired = (this.actorIndex != INVALID_ACTOR); + this.actorIndex= INVALID_ACTOR; + this.notifyAlive = false; + this.timeSinceLastAlive = 0; + this.numCyclesWithoutAlive = 0; + // then custom fire if was hired + if (wasHired) { + this.onFired(); + } + } + this.AgentController = AgentController; })(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 96502a7816..f7630cad48 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -10,6 +10,7 @@ // Agent.isAvatar = true; Script.include("./AgentPoolControler.js"); +var agentController = new AgentController(); // Set the following variables to the values needed var playFromCurrentLocation = true; @@ -17,18 +18,6 @@ var useDisplayName = true; var useAttachments = true; var useAvatarModel = true; -var agentController = new AgentController(); - -// ID of the agent. Two agents can't have the same ID. -//var UNKNOWN_AGENT_ID = -2; -//var id = UNKNOWN_AGENT_ID; // unknown until aknowledged - -// The time between alive messages on the command channel -/*var timeSinceLastAlive = 0; -var ALIVE_PERIOD = 5; -var NUM_CYCLES_BEFORE_RESET = 5; -var notifyAlive = false; -*/ // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -36,7 +25,6 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; var totalTime = 0; -var subscribed = false; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. @@ -55,10 +43,10 @@ Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); -function getAction(channel, message, senderID) { - if(subscribed) { +function getAction(command) { + if(true) { - var command = JSON.parse(message); + // 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); if (command.id_key == id || command.id_key == -1) { @@ -114,17 +102,13 @@ function getAction(channel, message, senderID) { if (!Agent.isAvatar) { Agent.isAvatar = true; } - if(command.clip_url_key !== null) { - print("Agent #" + id + " loading clip URL: " + command.clip_url_key); - Recording.loadRecording(command.clip_url_key); + if(command.argument_key !== null) { + print("Agent #" + id + " loading clip URL: " + command.argument_key); + Recording.loadRecording(command.argument_key); } else { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case MASTER_ALIVE: - print("Alive"); - notifyAlive = true; - break; case DO_NOTHING: break; default: @@ -139,66 +123,29 @@ function getAction(channel, message, senderID) { } } +function agentHired() { + print("Agent Hired from playbackAgents.js"); +} + +function agentFired() { + print("Agent Fired from playbackAgents.js"); +} + function update(deltaTime) { - totalTime += deltaTime; - if (totalTime > WAIT_FOR_AUDIO_MIXER) { + totalTime += deltaTime; + if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!agentController.subscribed) { agentController.reset(); + agentController.onCommand = getAction; + agentController.onHired = agentHired; + agentController.onFired = agentFired; } } - /* - - totalTime += deltaTime; - 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) { - - Messages.sendMessage(announceIDChannel, "ready"); - } - } - - if (subscribed && id != UNKNOWN_AGENT_ID) { - timeSinceLastAlive += deltaTime; - if (notifyAlive) { - timeSinceLastAlive = 0; - notifyAlive = false; - print("Master Alive"); - } else if (timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { - print("Master Lost, reseting Agent"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } - Agent.isAvatar = false; - id = UNKNOWN_AGENT_ID; - } - }*/ agentController.update(deltaTime); } -/* -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); - } -});*/ + function scriptEnding() { diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index eb7f86518f..1444ae3cf1 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -190,31 +190,9 @@ function sendCommand(id, action, argument) { id = -1; masterController.sendMessage(id, action, argument); - /* - var message = { - id_key: id, - action_key: action, - clip_url_key: argument - }; - - if(subscribed){ - Messages.sendMessage(commandChannel, JSON.stringify(message)); - print("Message sent!"); - }*/ } } else { masterController.sendMessage(id, action, argument); - /* - var message = { - id_key: id, - action_key: action, - clip_url_key: argument - }; - - if(subscribed){ - Messages.sendMessage(commandChannel, JSON.stringify(message)); - print("Message sent!"); - }*/ } } @@ -312,26 +290,4 @@ 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) { - print("New agent to be hired " + senderID); - var indexOfNewAgent = knownAgents.length; - knownAgents[indexOfNewAgent] = senderID; - var acknowledgeMessage = senderID + "." + indexOfNewAgent; - Overlays.editOverlay(nameOverlays[indexOfNewAgent], { backgroundColor: { red: 0, green: 255, blue: 0 }, text: "Agent-Hired" } ); - print("Hired new Agent " + senderID + " #" + indexOfNewAgent); - Messages.sendMessage(announceIDChannel, acknowledgeMessage); - } else { - - print("New agent still sending ready ? " + senderID); - } - - } -}); -*/ moveUI(); From 3273fbcad42f8e4dafc2b117758669d02d89783c Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Nov 2015 17:10:38 -0800 Subject: [PATCH 04/12] Creating the master / agent hiring system --- examples/acScripts/AgentPoolControler.js | 448 +++++++++++++---------- examples/acScripts/playbackMaster.js | 56 +-- 2 files changed, 292 insertions(+), 212 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 60b906381a..ec0fdf4b87 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -10,235 +10,305 @@ // function printDebug(message) { - print(message); + print(message); } (function() { - var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; - var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; + var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; - // The time between alive messages on the command channel - var ALIVE_PERIOD = 3; - var NUM_CYCLES_BEFORE_RESET = 5; + // The time between alive messages on the command channel + var ALIVE_PERIOD = 3; + var NUM_CYCLES_BEFORE_RESET = 8; - // Service Actions - var AGENT_READY = "ready"; - var INVALID_ACTOR = -2; + // Service Actions + var MASTER_ID = -1; + var AGENT_READY = "ready"; + var AGENT_LOST = "agentLost"; - var MASTER_INDEX = -1; + var INVALID_ACTOR = -2; - var MASTER_ALIVE = -1; - var MASTER_FIRE_AGENT = -2; - var makeMessage = function(id, action, argument) { - var message = { + var AGENTS_BROADCAST = -1; + var MASTER_ALIVE = -1; + var MASTER_FIRE_AGENT = -2; + + var makeUniqueUUID = function(SEUUID) { + //return SEUUID + Math.random(); + // forget complexity, just give me a four digit pin + return (Math.random() * 10000).toFixed(0); + } + + var packAnnounceMessage = function(dest, command, src) { + var message = { + dest: dest, + command: command, + src: src + }; + return JSON.stringify(message); + }; + + var unpackAnnounceMessage = function(message) { + return JSON.parse(message); + }; + + var packCommandMessage = function(id, action, argument) { + var message = { id_key: id, action_key: action, argument_key: argument - }; - return message; - }; - - var unpackMessage = function(message) { - return JSON.parse(message); - }; - - // master side - //--------------------------------- - var MasterController = function() { - this.timeSinceLastAlive = 0; - this.knownAgents = new Array; - this.subscribed = false; + }; + return JSON.stringify(message); }; - MasterController.prototype.destroy = function() { - if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.subscribed = true; - } - }; + var unpackCommandMessage = function(message) { + return JSON.parse(message); + }; + + // master side + //--------------------------------- + var MasterController = function() { + this.timeSinceLastAlive = 0; + this.knownAgents = new Array; + this.hiringAgentsQueue = new Array; + this.subscribed = false; + }; - MasterController.prototype.reset = function() { - this.timeSinceLastAlive = 0; + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; - if (!this.subscribed) { - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); - return; - } - }); - } - // ready to roll, enable - this.subscribed = true; - printDebug("Master Started"); + MasterController.prototype.reset = function() { + this.timeSinceLastAlive = 0; + + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + }); + } + // ready to roll, enable + this.subscribed = true; + printDebug("Master Started"); }; MasterController.prototype._processAnnounceMessage = function(message, senderID) { - if (message == AGENT_READY) { - - // check to see if we know about this agent - if (this.knownAgents.indexOf(senderID) < 0) { - - var indexOfNewAgent = this.knownAgents.length; - this.knownAgents[indexOfNewAgent] = senderID; - printDebug("New agent available to be hired " + senderID); - - var acknowledgeMessage = senderID + "." + indexOfNewAgent; - Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); - } else { - printDebug("New agent still sending ready ? " + senderID); - } - } + var message = unpackAnnounceMessage(message); + if (message.dest == MASTER_ID) { + if (message.command == AGENT_READY) { + // check to see if we know about this agent + var agentIndex = this.knownAgents.indexOf(message.src); + if (agentIndex < 0) { + if (this.hiringAgentsQueue.length > 0) { + var hiringHandler = this.hiringAgentsQueue.pop(); + hiringHandler(message.src); + } else { + //No hiring in queue so bail + return; + } + } else { + // Master think the agent is hired but not the other way around, forget about it + printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); + this.knownAgents[agentIndex] = INVALID_ACTOR; + } + } else if (message.command == AGENT_LOST) { + // check to see if we know about this agent + var agentIndex = this.knownAgents.indexOf(message.src); + if (agentIndex < 0) { + printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); + this.knownAgents[agentIndex] = INVALID_ACTOR; + } + } + } }; MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { - var messageJSON = JSON.stringify(makeMessage(target, action, argument)); + var messageJSON = packCommandMessage(target, action, argument); Messages.sendMessage(COMMAND_CHANNEL, messageJSON); - printDebug("Master sent message: " + messageJSON); } - }; - - MasterController.prototype.update = function(deltaTime) { - this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { - this.timeSinceLastAlive = 0; - printDebug("Master ping alive"); - this.sendCommand(MASTER_INDEX, MASTER_ALIVE); - } - }; - - this.MasterController = MasterController; - - // agent side - //--------------------------------- - var AgentController = function() { - this.subscribed = false; - - this.timeSinceLastAlive = 0; - this.numCyclesWithoutAlive = 0; - this.actorIndex = INVALID_ACTOR; - this.notifyAlive = false; - - this.onHired = function() {}; - this.onCommand = function(command) {}; - this.onFired = function() {}; }; - AgentController.prototype.destroy = function() { - if (this.subscribed) { - this.fire(); - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.subscribed = true; - } - }; - - AgentController.prototype.reset = function() { - // If already hired, fire - this.fired(); - - if (!this.subscribed) { - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); - return; - } - if (channel == COMMAND_CHANNEL) { - localThis._processCommandMessage(message, senderID); - return; - } - }); - } - this.subscribed = true; - printDebug("Client Started"); + MasterController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + this.timeSinceLastAlive = 0; + this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE); + } }; - AgentController.prototype._processAnnounceMessage = function(message, senderID) { - //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); - if (message != AGENT_READY) { - // this may be a message to hire me if i m not already - if (this.actorIndex == INVALID_ACTOR) { - var parts = message.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; - //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); - if (agentID == Agent.sessionUUID) { - this.actorIndex = actorIndex; - printDebug("Client " + this.actorIndex + " Hired!"); - this.onHired(); - // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - } - } - } - } - AgentController.prototype._processCommandMessage = function(message, senderID) { - var command = unpackMessage(message); - //printDebug("Received command = " + JSON.stringify(command)); + MasterController.prototype.hireAgent = function(onHired) { + var localThis = this; + this.hiringAgentsQueue.unshift(function(agentID) { + printDebug("hiring callback with agent " + agentID); + + var indexOfNewAgent = localThis.knownAgents.length; + localThis.knownAgents[indexOfNewAgent] = agentID; + + printDebug("New agent available to be hired " + agentID + " " + index); + var hireMessage = "HIRE." + index; + var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); + Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); - if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { - if (command.action_key == MASTER_ALIVE) { - this.notifyAlive = true; - } else if (command.action_key == MASTER_FIRE_AGENT) { - printDebug("Master firing Agent"); - this.fire(); - } else { - printDebug("True action received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } - } else { - // ignored - } + if (onHired != null) { + onHired(index); + } + }) }; - AgentController.prototype.update = function(deltaTime) { - this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { - if (this.subscribed) { - if (this.actorIndex == INVALID_ACTOR) { - Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); - //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); - } else { - this.numCyclesWithoutAlive++; - if (this.notifyAlive) { - this.notifyAlive = false; - this.numCyclesWithoutAlive = 0; - printDebug("Master Alive"); - } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Master Lost, firing Agent"); - this.fired(); - } - } - } + this.MasterController = MasterController; - this.timeSinceLastAlive = 0; - } - }; + // agent side + //--------------------------------- + var AgentController = function() { + this.subscribed = false; + + this._init(); - AgentController.prototype.fired = function() { - // clear the state first - var wasHired = (this.actorIndex != INVALID_ACTOR); - this.actorIndex= INVALID_ACTOR; + this.onHired = function() {}; + this.onCommand = function(command) {}; + this.onFired = function() {}; + }; + + AgentController.prototype._init = function() { + this.actorIndex= INVALID_ACTOR; this.notifyAlive = false; this.timeSinceLastAlive = 0; this.numCyclesWithoutAlive = 0; + this.actorUUID = makeUniqueUUID(Agent.sessionUUID); + printDebug("this.actorUUID = " + this.actorUUID); + } + + AgentController.prototype.destroy = function() { + if (this.subscribed) { + this.fire(); + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; + + AgentController.prototype.reset = function() { + // If already hired, fire + this.fired(); + + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + if (channel == COMMAND_CHANNEL) { + localThis._processCommandMessage(message, senderID); + return; + } + }); + } + this.subscribed = true; + printDebug("Client Started"); + }; + + AgentController.prototype._processAnnounceMessage = function(message, senderID) { + var announce = unpackCommandMessage(message); + //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); + if (announce.dest == this.actorUUID) { + if (announce.command != AGENT_READY) { + // this may be a message to hire me if i m not already + if (this.actorIndex == INVALID_ACTOR) { + printDebug(announce.command); + + var parts = announce.command.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); + // if (agentID == Agent.sessionUUID) { + this.actorIndex = actorIndex; + printDebug("Client " + this.actorIndex + " Hired!"); + this.onHired(); + // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + // } + } + } + } + } + + AgentController.prototype._processCommandMessage = function(message, senderID) { + var command = unpackCommandMessage(message); + //printDebug("Received command = " + JSON.stringify(command)); + + if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) { + if (command.action_key == MASTER_ALIVE) { + this.notifyAlive = true; + } else if (command.action_key == MASTER_FIRE_AGENT) { + printDebug("Master firing Agent"); + this.fire(); + } else { + printDebug("True action received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } + } else { + // ignored + } + }; + + + AgentController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.subscribed) { + if (this.actorIndex == INVALID_ACTOR) { + Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID)); + //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); + } else { + this.numCyclesWithoutAlive++; + if (this.notifyAlive) { + this.notifyAlive = false; + this.numCyclesWithoutAlive = 0; + printDebug("Master Alive"); + } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, firing Agent"); + this.fired(); + } + } + } + + this.timeSinceLastAlive = 0; + } + }; + + AgentController.prototype.fired = function() { + // clear the state first + var wasHired = (this.actorIndex != INVALID_ACTOR); + + // Post a last message to master in case it still listen to warn that this agent is losing it + if (wasHired) { + Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID)); + } + + // reset + this._init(); + // then custom fire if was hired - if (wasHired) { - this.onFired(); - } - } + if (wasHired) { + this.onFired(); + } + } - this.AgentController = AgentController; + this.AgentController = AgentController; })(); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 1444ae3cf1..929f384514 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -54,13 +54,23 @@ var performanceLoadedNeedUpdate = false; setupPlayback(); +function onHiring(agentID, index) { + print("agent hired from playbackMaster! " + agentID + " " + index) +} + function setupPlayback() { ac_number = Window.prompt("Insert number of agents: ","1"); if (ac_number === "" || ac_number === null) { ac_number = 1; - } - setupToolBars(); + } masterController.reset(); + + for (var i = 0; i < ac_number; i++) { + masterController.hireAgent(onHiring); + } + + setupToolBars(); + } function setupToolBars() { @@ -96,13 +106,13 @@ function setupToolBars() { var playLoopWidthFactor = 1.65; playLoopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFactor * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); stopIcon[i] = toolBars[i].addTool({ imageURL: TOOL_ICON_URL + "recording-stop.svg", @@ -121,20 +131,20 @@ function setupToolBars() { }, false); nameOverlays.push(Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 0, blue: 0 }, - font: { size: TEXT_HEIGHT }, - text: (i == ac_number) ? "Master" : i + ". " + - ((i < names.length) ? names[i] : - "AC" + i), - x: 0, y: 0, - width: toolBars[i].width + ToolBar.SPACING, - height: TEXT_HEIGHT + TEXT_MARGIN, - leftMargin: TEXT_MARGIN, - topMargin: TEXT_MARGIN, - alpha: ALPHA_OFF, - backgroundAlpha: ALPHA_OFF, - visible: true - })); + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: (i == ac_number) ? "Master" : i + ". " + + ((i < names.length) ? names[i] : + "AC" + i), + x: 0, y: 0, + width: toolBars[i].width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + })); } } From 37d3083e079ae183c63c27a9d383ccfb009e712a Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Thu, 26 Nov 2015 00:41:46 -0800 Subject: [PATCH 05/12] Getting the Actor class starting to work and usable for the playback master! --- examples/acScripts/AgentPoolControler.js | 40 ++++++++++++++++++------ examples/acScripts/playbackMaster.js | 19 ++++++++--- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index ec0fdf4b87..d528fc70fe 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -65,11 +65,22 @@ function printDebug(message) { return JSON.parse(message); }; + // Actor + //--------------------------------- + var Actor = function() { + this.agentID = INVALID_ACTOR; + this.onHired = function(actor) {}; + this.onLost = function(actor) {}; + }; + + this.Actor = Actor; + // master side //--------------------------------- var MasterController = function() { this.timeSinceLastAlive = 0; this.knownAgents = new Array; + this.hiredActors = new Array; this.hiringAgentsQueue = new Array; this.subscribed = false; }; @@ -126,6 +137,10 @@ function printDebug(message) { if (agentIndex < 0) { printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); this.knownAgents[agentIndex] = INVALID_ACTOR; + var lostActor = this.hiredActors[agentIndex]; + this.hiredActors[agentIndex] = null; + lostActor.agentID = INVALID_ACTOR; + lostActor.onLost(lostActor); } } } @@ -147,22 +162,27 @@ function printDebug(message) { }; - MasterController.prototype.hireAgent = function(onHired) { + MasterController.prototype.hireAgent = function(actor) { + if (actor == null) { + printDebug("trying to hire an agent with a null actor, abort"); + return; + } var localThis = this; this.hiringAgentsQueue.unshift(function(agentID) { - printDebug("hiring callback with agent " + agentID); - - var indexOfNewAgent = localThis.knownAgents.length; - localThis.knownAgents[indexOfNewAgent] = agentID; + printDebug("hiring callback with agent " + agentID+ " " + JSON.stringify(localThis) ); + + var indexOfNewAgent = localThis.knownAgents.push(agentID) + actor.agentID = agentID; + localThis.hiredActors.push(actor); - printDebug("New agent available to be hired " + agentID + " " + index); - var hireMessage = "HIRE." + index; + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + var hireMessage = "HIRE." + indexOfNewAgent; var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); + + printDebug("message sent calling the actor" + JSON.stringify(actor) ); - if (onHired != null) { - onHired(index); - } + actor.onHired(actor); }) }; diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 929f384514..3e60fc7a0e 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -17,7 +17,7 @@ var masterController = new MasterController(); 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 input_text = null; - +var actors = new Array(); // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); @@ -54,8 +54,14 @@ var performanceLoadedNeedUpdate = false; setupPlayback(); -function onHiring(agentID, index) { - print("agent hired from playbackMaster! " + agentID + " " + index) +function onActorHired(actor) { + print("agent hired from playbackMaster! " + actor.agentID + " " + actor.index) +} + +function onActorLost(actor) { + print("agent lost from playbackMaster! " + actor.agentID + " " + actor.index) + + actors[actor.index] = null; } function setupPlayback() { @@ -66,7 +72,12 @@ function setupPlayback() { masterController.reset(); for (var i = 0; i < ac_number; i++) { - masterController.hireAgent(onHiring); + var newActor = new Actor(); + newActor.index = i; + newActor.onHired = onActorHired; + newActor.onLost = onActorLost; + masterController.hireAgent(newActor); + actors.push(newActor); } setupToolBars(); From 3f43fde4592b5a964823b2bb048868764772262b Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 30 Nov 2015 04:11:17 -0800 Subject: [PATCH 06/12] AFter 3 days on that piece of shit i just give up, js is just too hard to debug, i m very sad --- examples/acScripts/AgentPoolControler.js | 67 ++- examples/acScripts/playbackAgents.js | 48 +-- examples/acScripts/playbackMaster.js | 514 +++++++++++++---------- 3 files changed, 354 insertions(+), 275 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index d528fc70fe..8965defe9c 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -52,9 +52,9 @@ function printDebug(message) { return JSON.parse(message); }; - var packCommandMessage = function(id, action, argument) { + var packCommandMessage = function(dest, action, argument) { var message = { - id_key: id, + dest_key: dest, action_key: action, argument_key: argument }; @@ -73,6 +73,10 @@ function printDebug(message) { this.onLost = function(actor) {}; }; + Actor.prototype.isConnected = function () { + return (this.agentID != INVALID_ACTOR); + } + this.Actor = Actor; // master side @@ -129,18 +133,19 @@ function printDebug(message) { } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this.knownAgents[agentIndex] = INVALID_ACTOR; + lostActor.agentID = INVALID_ACTOR; + lostActor.onLost(lostActor); + _clearAgent(agentIndex); } } else if (message.command == AGENT_LOST) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); - if (agentIndex < 0) { - printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); - this.knownAgents[agentIndex] = INVALID_ACTOR; - var lostActor = this.hiredActors[agentIndex]; - this.hiredActors[agentIndex] = null; + if (agentIndex >= 0) { lostActor.agentID = INVALID_ACTOR; lostActor.onLost(lostActor); + _clearAgent(agentIndex); + } else { + return; } } } @@ -186,6 +191,38 @@ function printDebug(message) { }) }; + MasterController.prototype.fireAgent = function(actor) { + // check to see if we know about this agent + printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + var actorIndex = this.knownAgents.indexOf(actor.agentID); + if (actorIndex >= 0) { + printDebug("fired actor found #" + actorIndex); + + var currentAgentID = actor.agentID; + this._clearAgent(actorIndex); + printDebug("fired actor found #" + actorIndex); + + if (currentAgentID != INVALID_ACTOR) { + printDebug("fired actor is still connected, send fire command"); + this.sendCommand(currentAgentID, MASTER_FIRE_AGENT); + } + } + } + + MasterController.prototype._clearAgent = function(actorIndex) { + // check to see if we know about this agent + if (actorIndex >= 0) { + printDebug("before _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + this.knownAgents.splice(actorIndex, 1); + var lostActor = this.hiredActors[actorIndex]; + this.hiredActors.splice(actorIndex, 1); + lostActor.agentID = INVALID_ACTOR; + printDebug("Clearing agent " + actorIndex + " Forgeting about it"); + printDebug("after _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + + } + } + this.MasterController = MasterController; // agent side @@ -211,7 +248,7 @@ function printDebug(message) { AgentController.prototype.destroy = function() { if (this.subscribed) { - this.fire(); + this.fired(); Messages.unsubscribe(ANNOUNCE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; @@ -242,7 +279,7 @@ function printDebug(message) { }; AgentController.prototype._processAnnounceMessage = function(message, senderID) { - var announce = unpackCommandMessage(message); + var announce = unpackAnnounceMessage(message); //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); if (announce.dest == this.actorUUID) { if (announce.command != AGENT_READY) { @@ -251,11 +288,11 @@ function printDebug(message) { printDebug(announce.command); var parts = announce.command.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; + var commandPart0 = parts[0]; + var commandPart1 = parts[1]; //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); // if (agentID == Agent.sessionUUID) { - this.actorIndex = actorIndex; + this.actorIndex = commandPart1; printDebug("Client " + this.actorIndex + " Hired!"); this.onHired(); // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel @@ -269,12 +306,12 @@ function printDebug(message) { var command = unpackCommandMessage(message); //printDebug("Received command = " + JSON.stringify(command)); - if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) { + if ((command.dest_key == this.actorUUID) || (command.dest_key == AGENTS_BROADCAST)) { if (command.action_key == MASTER_ALIVE) { this.notifyAlive = true; } else if (command.action_key == MASTER_FIRE_AGENT) { printDebug("Master firing Agent"); - this.fire(); + this.fired(); } else { printDebug("True action received = " + JSON.stringify(command) + senderID); this.onCommand(command); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index f7630cad48..ec704e35e9 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -8,7 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +// Agent is an avatar Agent.isAvatar = true; + Script.include("./AgentPoolControler.js"); var agentController = new AgentController(); @@ -29,7 +32,6 @@ var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. var ALIVE = -1; -var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -47,22 +49,11 @@ function getAction(command) { if(true) { // 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); - - if (command.id_key == id || command.id_key == -1) { - - action = command.action_key; - print("That command was for me! Agent with id: " + id); - } else { - action = DO_NOTHING; - } - - switch(action) { + print("I'm the agent " + this.actorUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); + + switch(command.action_key) { case PLAY: print("Play"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if (!Recording.isPlaying()) { Recording.startPlaying(); } @@ -70,9 +61,6 @@ function getAction(command) { break; case PLAY_LOOP: print("Play loop"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if (!Recording.isPlaying()) { Recording.startPlaying(); } @@ -86,22 +74,15 @@ function getAction(command) { break; case SHOW: print("Show"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } break; case HIDE: - print("Hide"); + print("Hide"); if (Recording.isPlaying()) { Recording.stopPlaying(); } - Agent.isAvatar = false; break; case LOAD: print("Load"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if(command.argument_key !== null) { print("Agent #" + id + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); @@ -109,26 +90,27 @@ function getAction(command) { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case DO_NOTHING: - break; default: - print("Unknown action: " + action); + print("Unknown action: " + command.action_key); break; } - - if (Recording.isPlaying()) { - Recording.play(); - } } } function agentHired() { print("Agent Hired from playbackAgents.js"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + Recording.setPlayerLoop(false); } function agentFired() { print("Agent Fired from playbackAgents.js"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 3e60fc7a0e..3cf24a6071 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,15 +14,14 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var masterController = new MasterController(); -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 input_text = null; -var actors = new Array(); // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); - +// We want small icons +Tool.IMAGE_HEIGHT /= 2; +Tool.IMAGE_WIDTH /= 2; var DO_NOTHING = 0; var PLAY = 1; @@ -41,245 +40,315 @@ var COLOR_MASTER = { red: 0, green: 0, blue: 0 }; var TEXT_HEIGHT = 12; var TEXT_MARGIN = 3; -var toolBars = new Array(); -var nameOverlays = new Array(); -var onOffIcon = new Array(); -var playIcon = new Array(); -var playLoopIcon = new Array(); -var stopIcon = new Array(); -var loadIcon = new Array(); +// Add new features to Actor class: +Actor.prototype.destroy = function() { + print("Actor.prototype.destroy"); -var performanceJSON = null; -var performanceLoadedNeedUpdate = false; - -setupPlayback(); - -function onActorHired(actor) { - print("agent hired from playbackMaster! " + actor.agentID + " " + actor.index) -} - -function onActorLost(actor) { - print("agent lost from playbackMaster! " + actor.agentID + " " + actor.index) - - actors[actor.index] = null; -} - -function setupPlayback() { - ac_number = Window.prompt("Insert number of agents: ","1"); - if (ac_number === "" || ac_number === null) { - ac_number = 1; - } - masterController.reset(); - - for (var i = 0; i < ac_number; i++) { - var newActor = new Actor(); - newActor.index = i; - newActor.onHired = onActorHired; - newActor.onLost = onActorLost; - masterController.hireAgent(newActor); - actors.push(newActor); - } - - setupToolBars(); + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); + print("Need to fire myself" + this.agentID); + masterController.fireAgent(this); } -function setupToolBars() { - if (toolBars.length > 0) { - print("Multiple calls to Recorder.js:setupToolBars()"); - return; - } - Tool.IMAGE_HEIGHT /= 2; - Tool.IMAGE_WIDTH /= 2; - - for (i = 0; i <= ac_number; i++) { - toolBars.push(new ToolBar(0, 0, ToolBar.HORIZONTAL)); - toolBars[i].setBack((i == ac_number) ? COLOR_MASTER : COLOR_TOOL_BAR, ALPHA_OFF); - - onOffIcon.push(toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "ac-on-off.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - x: 0, y: 0, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_ON, - visible: true - }, true, true)); - - playIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - var playLoopWidthFactor = 1.65; - playLoopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - stopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "recording-stop.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - loadIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "recording-upload.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - nameOverlays.push(Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 0, blue: 0 }, - font: { size: TEXT_HEIGHT }, - text: (i == ac_number) ? "Master" : i + ". " + - ((i < names.length) ? names[i] : - "AC" + i), - x: 0, y: 0, - width: toolBars[i].width + ToolBar.SPACING, - height: TEXT_HEIGHT + TEXT_MARGIN, - leftMargin: TEXT_MARGIN, - topMargin: TEXT_MARGIN, - alpha: ALPHA_OFF, - backgroundAlpha: ALPHA_OFF, - visible: true - })); + +Actor.prototype.resetClip = function(clipURL, onLoadClip) { + this.clipURL = clipURL; + this.onLoadClip = onLoadClip; + if (this.isConnected()) { + this.onLoadClip(this); } } -function loadAvatarClipsFromPerformanceJSON(performanceJSON) { - if (performanceJSON.avatarClips) { - var numClips = performanceJSON.avatarClips.length; - print("Performance file contains:" + JSON.stringify(performanceJSON)); - print("Number of clips in the performance file is: " + numClips + " Number of agents is: " + knownAgents.length); - if (numClips > knownAgents.length) { - numClips = knownAgents.length; - } - - for (i = 0; i < numClips; i++) { - var clipURL = performanceJSON.avatarClips[i]; - print("Loading clip " + clipURL + " to Agent #" + i); - sendCommand(i, LOAD, clipURL); - } +Actor.prototype.onMousePressEvent = function(clickedOverlay) { + if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, PLAY); + } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, PLAY_LOOP); + } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, STOP); } else { - print("Performance file cannot be interpreted:" + JSON.stringify(performanceJSON)); + return false; } + + return true; } -function sendCommand(id, action, argument) { - if (action === SHOW) { - toolBars[id].selectTool(onOffIcon[id], false); - toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, playLoopIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, stopIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, loadIcon[id]); - } else if (action === HIDE) { - toolBars[id].selectTool(onOffIcon[id], true); - toolBars[id].setAlpha(ALPHA_OFF, playIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); - } else if (toolBars[id].toolSelected(onOffIcon[id])) { - return; - } +Actor.prototype._buildUI = function() { + print("Actor.prototype._buildUI = " + JSON.stringify(this)); - if (id == (toolBars.length - 1)) { + this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - if (action == LOAD) { - if (performanceLoadedNeedUpdate == false) { - Assets.downloadData(argument, function (data) { - performanceJSON = JSON.parse(data); - performanceLoadedNeedUpdate = true; - // print("Performance file contains:" + JSON.stringify(performanceJSON)); - }); - return; - } - } else { - id = -1; - - masterController.sendMessage(id, action, argument); - } - } else { - masterController.sendMessage(id, action, argument); - } + this.toolbar.setBack(COLOR_TOOL_BAR, ALPHA_OFF); + + this.playIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + var playLoopWidthFthis = 1.65; + this.playLoopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFthis * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.stopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-stop.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.nameOverlay = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: "AC offline", + x: 0, y: 0, + width: this.toolbar.width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + }); } -function mousePressEvent(event) { - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); +Actor.prototype.moveUI = function(pos) { + var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; + this.toolbar.move(pos.x, pos.y); + + Overlays.editOverlay(this.nameOverlay, { + x: this.toolbar.x - ToolBar.SPACING, + y: this.toolbar.y - textSize + }); +} + +Director = function() { + this.actors = new Array(); + this.toolbar = null; + this._buildUI(); +}; + +Director.prototype.destroy = function () { + print("Director.prototype.destroy") + this.clearActors(); + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); +} + +Director.prototype.clearActors = function () { + print("Director.prototype.clearActors") + for (var i = 0; i < this.actors.length; i++) { + print("Destroy actor #" + i) + this.actors[i].destroy(); + } + this.actors = new Array();// Brand new actors +} + +Director.prototype._buildUI = function () { + this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - // Check master control - var i = toolBars.length - 1; - if (onOffIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - if (toolBars[i].toolSelected(onOffIcon[i])) { - sendCommand(i, SHOW); - } else { - sendCommand(i, HIDE); - } - } else if (playIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY); - } else if (playLoopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY_LOOP); - } else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, STOP); - } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { + this.toolbar.setBack(COLOR_MASTER, ALPHA_OFF); + + this.onOffIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "ac-on-off.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + x: 0, y: 0, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_ON, + visible: true + }, true, true); + + this.playIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + var playLoopWidthFthis = 1.65; + this.playLoopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFthis * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.stopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-stop.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.loadIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-upload.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.nameOverlay = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: "Master", + x: 0, y: 0, + width: this.toolbar.width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + }); +} + +Director.prototype.onMousePressEvent = function(clickedOverlay) { + if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { + this.clearActors(); + return true; + } else if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, PLAY); + } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, PLAY_LOOP); + } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, STOP); + } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - sendCommand(i, LOAD, input_text); - } + print("Performance file ready to be loaded url = " + input_text); + + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(data); }); + } } else { // Check individual controls - for (i = 0; i < ac_number; i++) { - if (onOffIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - if (toolBars[i].toolSelected(onOffIcon[i], false)) { - sendCommand(i, SHOW); - } else { - sendCommand(i, HIDE); - } - } else if (playIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY); - } else if (playLoopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY_LOOP); - } else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, STOP); - } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - input_text = Window.prompt("Insert the url of the clip: ",""); - if (!(input_text === "" || input_text === null)) { - sendCommand(i, LOAD, input_text); - } - } else { - + for (var i = 0; i < this.actors.length; i++) { + if (this.actors[i].onMousePressEvent(clickedOverlay)) { + return true; } } + + return false; // nothing clicked from our known overlays } + + return true; +} + +Director.prototype.moveUI = function(pos) { + var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; + var relative = { x: pos.x, y: pos.y + (this.actors.length + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; + + this.toolbar.move(relative.x, windowDimensions.y - relative.y); + Overlays.editOverlay(this.nameOverlay, { + x: this.toolbar.x - ToolBar.SPACING, + y: this.toolbar.y - textSize + }); + + for (var i = 0; i < this.actors.length; i++) { + this.actors[i].moveUI({x: relative.x, y: windowDimensions.y - relative.y + + (i + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)}); + } +} + +Director.prototype.onPerformanceLoaded = function(performanceData) { + var performanceJSON = JSON.parse(performanceData); + print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); + if (performanceJSON.avatarClips != null) { + var numClips = performanceJSON.avatarClips.length; + print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); + + for (var i = 0; i < numClips; i++) { + if (i < this.actors.length) { + // load correct clip to actor + } else { + this.hireActor(performanceJSON.avatarClips[i]); + } + } + + } +} + + +Director.prototype.hireActor = function(clipURL) { + print("new actor = " + this.actors.length ); + var newActor = new Actor(); + newActor.clipURL = null; + newActor.onLoadClip = function(clip) {}; + + var localThis = this; + newActor.onHired = function(actor) { + print("agent hired from Director! " + actor.agentID) + Overlays.editOverlay(actor.nameOverlay, { + text: "AC " + actor.agentID, + backgroundColor: { red: 0, green: 255, blue: 0 } + }); + + if (actor.clipURL != null) { + print("agent hired, calling load clip for url " + actor.clipURL); + actor.onLoadClip(actor); + } + }; + + newActor.onLost = function(actor) { + print("agent lost from playbackMaster! " + actor.agentID); + var index = localThis.actors.indexOf(actor); + if (index >= 0) { + localThis.actors.splice(index, 1); + } + actor.destroy(); + } + + newActor.resetClip(clipURL, function(actor) { + print("Load clip for agent" + actor.agentID + " calling load clip for url " + actor.clipURL); + masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); + }); + + masterController.hireAgent(newActor); + newActor._buildUI(); + + this.actors.push(newActor); + + moveUI(); +} + + +masterController.reset(); +var director = new Director(); + +moveUI(); + + +function mousePressEvent(event) { + print("mousePressEvent"); + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + + // Check director and actors + director.onMousePressEvent(clickedOverlay); } function moveUI() { - var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; - var relative = { x: 70, y: 75 + (ac_number) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; - - for (i = 0; i <= ac_number; i++) { - toolBars[i].move(relative.x, - windowDimensions.y - relative.y + - i * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)); - - Overlays.editOverlay(nameOverlays[i], { - x: toolBars[i].x - ToolBar.SPACING, - y: toolBars[i].y - textSize - }); - } + director.moveUI({ x: 70, y: 75}); + } function update(deltaTime) { @@ -290,20 +359,12 @@ function update(deltaTime) { moveUI(); } - if (performanceLoadedNeedUpdate) { - loadAvatarClipsFromPerformanceJSON(performanceJSON); - performanceLoadedNeedUpdate = false; - } - masterController.update(deltaTime); } function scriptEnding() { - for (i = 0; i <= ac_number; i++) { - toolBars[i].cleanup(); - Overlays.deleteOverlay(nameOverlays[i]); - } - + print("cleanup") + director.destroy(); masterController.destroy(); } @@ -311,4 +372,3 @@ Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); -moveUI(); From 1b197987ecd9a0a1241455243cc3a66e650fb14e Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 30 Nov 2015 18:34:40 -0800 Subject: [PATCH 07/12] MOnday spent on improving the Agent/Clint coordination, but still bugs --- examples/acScripts/AgentPoolControler.js | 285 +++++++++++++---------- examples/acScripts/playbackAgents.js | 25 +- examples/acScripts/playbackMaster.js | 61 +++-- 3 files changed, 217 insertions(+), 154 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 8965defe9c..c7ecd70ad1 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -14,8 +14,8 @@ function printDebug(message) { } (function() { - var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; - var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + var SERVICE_CHANNEL = "com.highfidelity.playback.service"; + var COMMAND_CHANNEL = "com.highfidelity.playback.command"; // The time between alive messages on the command channel var ALIVE_PERIOD = 3; @@ -23,15 +23,15 @@ function printDebug(message) { // Service Actions var MASTER_ID = -1; - var AGENT_READY = "ready"; - var AGENT_LOST = "agentLost"; + var INVALID_AGENT = -2; - var INVALID_ACTOR = -2; + var BROADCAST_AGENTS = -3; - - var AGENTS_BROADCAST = -1; - var MASTER_ALIVE = -1; - var MASTER_FIRE_AGENT = -2; + var MASTER_ALIVE = "MASTER_ALIVE"; + var AGENT_ALIVE = "AGENT_ALIVE"; + var AGENT_READY = "READY"; + var MASTER_HIRE_AGENT = "HIRE" + var MASTER_FIRE_AGENT = "FIRE"; var makeUniqueUUID = function(SEUUID) { //return SEUUID + Math.random(); @@ -39,7 +39,7 @@ function printDebug(message) { return (Math.random() * 10000).toFixed(0); } - var packAnnounceMessage = function(dest, command, src) { + var packServiceMessage = function(dest, command, src) { var message = { dest: dest, command: command, @@ -48,7 +48,7 @@ function printDebug(message) { return JSON.stringify(message); }; - var unpackAnnounceMessage = function(message) { + var unpackServiceMessage = function(message) { return JSON.parse(message); }; @@ -68,13 +68,27 @@ function printDebug(message) { // Actor //--------------------------------- var Actor = function() { - this.agentID = INVALID_ACTOR; + this.agentID = INVALID_AGENT; + this.lastAliveCycle = 0; this.onHired = function(actor) {}; - this.onLost = function(actor) {}; + this.onFired = function(actor) {}; }; Actor.prototype.isConnected = function () { - return (this.agentID != INVALID_ACTOR); + return (this.agentID != INVALID_AGENT); + } + + Actor.prototype.alive = function () { + printDebug("Agent UUID =" + this.agentID + " Alive was " + this.lastAliveCycle); + this.lastAliveCycle = 0; + } + Actor.prototype.incrementAliveCycle = function () { + printDebug("Actor.prototype.incrementAliveCycle UUID =" + this.agentID + " Alive pre increment " + this.lastAliveCycle); + if (this.isConnected()) { + this.lastAliveCycle++; + printDebug("Agent UUID =" + this.agentID + " Alive incremented " + this.lastAliveCycle); + } + return this.lastAliveCycle; } this.Actor = Actor; @@ -91,7 +105,7 @@ function printDebug(message) { MasterController.prototype.destroy = function() { if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(SERVICE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; } @@ -102,11 +116,11 @@ function printDebug(message) { if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); + Messages.subscribe(SERVICE_CHANNEL); var localThis = this; Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); + if (channel == SERVICE_CHANNEL) { + localThis._processServiceMessage(message, senderID); return; } }); @@ -116,45 +130,59 @@ function printDebug(message) { printDebug("Master Started"); }; - MasterController.prototype._processAnnounceMessage = function(message, senderID) { - var message = unpackAnnounceMessage(message); + MasterController.prototype._processServiceMessage = function(message, senderID) { + var message = unpackServiceMessage(message); if (message.dest == MASTER_ID) { if (message.command == AGENT_READY) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); if (agentIndex < 0) { - if (this.hiringAgentsQueue.length > 0) { - var hiringHandler = this.hiringAgentsQueue.pop(); - hiringHandler(message.src); - } else { - //No hiring in queue so bail - return; - } + this._onAgentAvailableForHiring(message.src); } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - lostActor.agentID = INVALID_ACTOR; - lostActor.onLost(lostActor); - _clearAgent(agentIndex); + this._removeAgent(agentIndex); } - } else if (message.command == AGENT_LOST) { + } else if (message.command == AGENT_ALIVE) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); if (agentIndex >= 0) { - lostActor.agentID = INVALID_ACTOR; - lostActor.onLost(lostActor); - _clearAgent(agentIndex); + // yes so reset its alive beat + this.hiredActors[agentIndex].alive(); + return; } else { return; } } } }; - - MasterController.prototype.sendCommand = function(target, action, argument) { + + MasterController.prototype._onAgentAvailableForHiring = function(agentID) { + if (this.hiringAgentsQueue.length == 0) { + printDebug("No Actor on the hiring queue"); + return; + } + + printDebug("MasterController.prototype._onAgentAvailableForHiring " + agentID); + var newActor = this.hiringAgentsQueue.pop(); + + var indexOfNewAgent = this.knownAgents.push(agentID); + newActor.alive(); + newActor.agentID = agentID; + this.hiredActors.push(newActor); + + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID)); + printDebug("message sent calling the actor" + JSON.stringify(newActor) ); + + newActor.onHired(newActor); + } + + MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { - var messageJSON = packCommandMessage(target, action, argument); - Messages.sendMessage(COMMAND_CHANNEL, messageJSON); + var command = packCommandMessage(target, action, argument); + printDebug(command); + Messages.sendMessage(COMMAND_CHANNEL, command); } }; @@ -162,7 +190,31 @@ function printDebug(message) { this.timeSinceLastAlive += deltaTime; if (this.timeSinceLastAlive > ALIVE_PERIOD) { this.timeSinceLastAlive = 0; - this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(BROADCAST_AGENTS, MASTER_ALIVE, MASTER_ID)); + + printDebug("checking the agents status"); + { + // Check for alive connected agents + var lostAgents = new Array(); + for (var i = 0; i < this.hiredActors.length; i++) { + var actor = this.hiredActors[i]; + printDebug("checking :" + JSON.stringify(actor)); + var lastAlive = actor.incrementAliveCycle() + if (lastAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Agent Lost, firing Agent"); + lostAgents.push(actor); + } + } + + // now fire gathered lost agents + if (lostAgents.length > 0) { + printDebug("Firing " + lostAgents.length + " agents" + JSON.stringify(lostAgents)); + + for (var i = 0; i < lostAgents.length; i++) { + this.fireAgent(lostAgents[l]); + } + } + } } }; @@ -172,54 +224,51 @@ function printDebug(message) { printDebug("trying to hire an agent with a null actor, abort"); return; } - var localThis = this; - this.hiringAgentsQueue.unshift(function(agentID) { - printDebug("hiring callback with agent " + agentID+ " " + JSON.stringify(localThis) ); - - var indexOfNewAgent = localThis.knownAgents.push(agentID) - actor.agentID = agentID; - localThis.hiredActors.push(actor); - - printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); - var hireMessage = "HIRE." + indexOfNewAgent; - var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); - Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); - - printDebug("message sent calling the actor" + JSON.stringify(actor) ); - - actor.onHired(actor); - }) + if (actor.isConnected()) { + printDebug("trying to hire an agent already connected, abort"); + return; + } + this.hiringAgentsQueue.unshift(actor); }; MasterController.prototype.fireAgent = function(actor) { // check to see if we know about this agent printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + + var waitingIndex = this.hiringAgentsQueue.indexOf(actor); + if (waitingIndex >= 0) { + printDebug("MasterController.prototype.fireAgent found actor on waiting queue #" + waitingIndex); + this.hiringAgentsQueue.splice(waitingIndex, 1); + } + var actorIndex = this.knownAgents.indexOf(actor.agentID); if (actorIndex >= 0) { printDebug("fired actor found #" + actorIndex); - - var currentAgentID = actor.agentID; - this._clearAgent(actorIndex); - printDebug("fired actor found #" + actorIndex); - - if (currentAgentID != INVALID_ACTOR) { - printDebug("fired actor is still connected, send fire command"); - this.sendCommand(currentAgentID, MASTER_FIRE_AGENT); - } + this._removeAgent(actorIndex); } } - MasterController.prototype._clearAgent = function(actorIndex) { + MasterController.prototype._removeAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("before _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("before _removeAgent #" + actorIndex + " " + JSON.stringify(this)) this.knownAgents.splice(actorIndex, 1); + var lostActor = this.hiredActors[actorIndex]; this.hiredActors.splice(actorIndex, 1); - lostActor.agentID = INVALID_ACTOR; - printDebug("Clearing agent " + actorIndex + " Forgeting about it"); - printDebug("after _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + var lostAgentID = lostActor.agentID; + lostActor.agentID = INVALID_AGENT; + + printDebug("Clearing agent " + actorIndex + " Forgeting about it"); + printDebug("after _removeAgent #" + actorIndex + " " + JSON.stringify(this)) + + if (lostAgentID != INVALID_AGENT) { + printDebug("fired actor is still connected, send fire command"); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(lostAgentID, MASTER_FIRE_AGENT, MASTER_ID)); + } + + lostActor.onFired(lostActor); } } @@ -238,18 +287,17 @@ function printDebug(message) { }; AgentController.prototype._init = function() { - this.actorIndex= INVALID_ACTOR; - this.notifyAlive = false; + this.isHired= false; this.timeSinceLastAlive = 0; this.numCyclesWithoutAlive = 0; - this.actorUUID = makeUniqueUUID(Agent.sessionUUID); - printDebug("this.actorUUID = " + this.actorUUID); + this.agentUUID = makeUniqueUUID(Agent.sessionUUID); + printDebug("this.agentUUID = " + this.agentUUID); } AgentController.prototype.destroy = function() { if (this.subscribed) { this.fired(); - Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(SERVICE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; } @@ -261,11 +309,11 @@ function printDebug(message) { if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); + Messages.subscribe(SERVICE_CHANNEL); var localThis = this; Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); + if (channel == SERVICE_CHANNEL) { + localThis._processServiceMessage(message, senderID); return; } if (channel == COMMAND_CHANNEL) { @@ -278,44 +326,39 @@ function printDebug(message) { printDebug("Client Started"); }; - AgentController.prototype._processAnnounceMessage = function(message, senderID) { - var announce = unpackAnnounceMessage(message); - //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); - if (announce.dest == this.actorUUID) { + AgentController.prototype._processServiceMessage = function(message, senderID) { + var announce = unpackServiceMessage(message); + //printDebug("Client " + this.agentUUID + " Received Announcement = " + message); + if (announce.dest == this.agentUUID) { if (announce.command != AGENT_READY) { - // this may be a message to hire me if i m not already - if (this.actorIndex == INVALID_ACTOR) { + var parts = announce.command.split("."); + + // this is potnetially a message to hire me if i m not already + if (!this.isHired && (parts[0] == MASTER_HIRE_AGENT)) { printDebug(announce.command); + this.isHired = true; + printDebug("Client Hired by master UUID" + senderID); + this.onHired(); + return; + } - var parts = announce.command.split("."); - var commandPart0 = parts[0]; - var commandPart1 = parts[1]; - //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); - // if (agentID == Agent.sessionUUID) { - this.actorIndex = commandPart1; - printDebug("Client " + this.actorIndex + " Hired!"); - this.onHired(); - // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - // } + if (this.isHired && (parts[0] == MASTER_FIRE_AGENT)) { + printDebug("Client Fired by master UUID" + senderID); + this.fired(); + return; } } + } else if (announce.src == MASTER_ID && announce.command == MASTER_ALIVE) { + this.numCyclesWithoutAlive = 0; + return; } } AgentController.prototype._processCommandMessage = function(message, senderID) { var command = unpackCommandMessage(message); - //printDebug("Received command = " + JSON.stringify(command)); - - if ((command.dest_key == this.actorUUID) || (command.dest_key == AGENTS_BROADCAST)) { - if (command.action_key == MASTER_ALIVE) { - this.notifyAlive = true; - } else if (command.action_key == MASTER_FIRE_AGENT) { - printDebug("Master firing Agent"); - this.fired(); - } else { - printDebug("True action received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } + if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { + printDebug("Command received = " + JSON.stringify(command) + senderID); + this.onCommand(command); } else { // ignored } @@ -326,17 +369,18 @@ function printDebug(message) { this.timeSinceLastAlive += deltaTime; if (this.timeSinceLastAlive > ALIVE_PERIOD) { if (this.subscribed) { - if (this.actorIndex == INVALID_ACTOR) { - Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID)); - //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); + if (!this.isHired) { + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_READY, this.agentUUID)); + //printDebug("Client Ready" + SERVICE_CHANNEL + AGENT_READY); } else { + + // Send alive beat + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_ALIVE, this.agentUUID)); + + // Listen for master beat this.numCyclesWithoutAlive++; - if (this.notifyAlive) { - this.notifyAlive = false; - this.numCyclesWithoutAlive = 0; - printDebug("Master Alive"); - } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Master Lost, firing Agent"); + if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, self firing Agent"); this.fired(); } } @@ -348,12 +392,7 @@ function printDebug(message) { AgentController.prototype.fired = function() { // clear the state first - var wasHired = (this.actorIndex != INVALID_ACTOR); - - // Post a last message to master in case it still listen to warn that this agent is losing it - if (wasHired) { - Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID)); - } + var wasHired = this.isHired; // reset this._init(); @@ -366,6 +405,10 @@ function printDebug(message) { this.AgentController = AgentController; + + + + this.BROADCAST_AGENTS = BROADCAST_AGENTS; })(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index ec704e35e9..67fe8c733e 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -31,7 +31,6 @@ var totalTime = 0; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. -var ALIVE = -1; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -45,11 +44,11 @@ Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); -function getAction(command) { +function agentCommand(command) { if(true) { // var command = JSON.parse(message); - print("I'm the agent " + this.actorUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); + print("I'm the agent " + this.agentUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); switch(command.action_key) { case PLAY: @@ -82,13 +81,19 @@ function getAction(command) { } break; case LOAD: - print("Load"); - if(command.argument_key !== null) { + { + print("Load" + command.argument_key); + print("Agent #" + command.dest_key + " loading clip URL: " + command.argument_key); + Recording.loadRecording(command.argument_key); + print("After Load" + command.argument_key); + + /*if(command.argument_key == null) { + print("Agent #" + id + " loading clip URL is NULL, nothing happened"); + } else *{ print("Agent #" + id + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); - } else { - print("Agent #" + id + " loading clip URL is NULL, nothing happened"); - } + }*/ + } break; default: print("Unknown action: " + command.action_key); @@ -102,7 +107,7 @@ function agentHired() { print("Agent Hired from playbackAgents.js"); if (Recording.isPlaying()) { Recording.stopPlaying(); - } + } Recording.setPlayerLoop(false); } @@ -119,7 +124,7 @@ function update(deltaTime) { if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!agentController.subscribed) { agentController.reset(); - agentController.onCommand = getAction; + agentController.onCommand = agentCommand; agentController.onHired = agentHired; agentController.onFired = agentFired; } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 3cf24a6071..7486256f07 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -23,7 +23,6 @@ Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); Tool.IMAGE_HEIGHT /= 2; Tool.IMAGE_WIDTH /= 2; -var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -149,10 +148,10 @@ Director.prototype.destroy = function () { Director.prototype.clearActors = function () { print("Director.prototype.clearActors") - for (var i = 0; i < this.actors.length; i++) { - print("Destroy actor #" + i) - this.actors[i].destroy(); + while (this.actors.length > 0) { + this.actors.pop().destroy(); } + this.actors = new Array();// Brand new actors } @@ -222,23 +221,40 @@ Director.prototype._buildUI = function () { } Director.prototype.onMousePressEvent = function(clickedOverlay) { - if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { + if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + print("master play"); + masterController.sendCommand(BROADCAST_AGENTS, PLAY); + } else if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { this.clearActors(); return true; - } else if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, PLAY); } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, PLAY_LOOP); + masterController.sendCommand(BROADCAST_AGENTS, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, STOP); - } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(BROADCAST_AGENTS, STOP); + } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); - - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(data); }); + var urlpartition = input_text.split("."); + print(urlpartition[0]); + print(urlpartition[1]); + + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } } } else { // Check individual controls @@ -270,19 +286,17 @@ Director.prototype.moveUI = function(pos) { } } -Director.prototype.onPerformanceLoaded = function(performanceData) { - var performanceJSON = JSON.parse(performanceData); +Director.prototype.onPerformanceLoaded = function(performanceJSON) { + // First fire all the current actors + this.clearActors(); + print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); if (performanceJSON.avatarClips != null) { var numClips = performanceJSON.avatarClips.length; print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); for (var i = 0; i < numClips; i++) { - if (i < this.actors.length) { - // load correct clip to actor - } else { - this.hireActor(performanceJSON.avatarClips[i]); - } + this.hireActor(performanceJSON.avatarClips[i]); } } @@ -309,13 +323,14 @@ Director.prototype.hireActor = function(clipURL) { } }; - newActor.onLost = function(actor) { - print("agent lost from playbackMaster! " + actor.agentID); + newActor.onFired = function(actor) { + print("agent fired from playbackMaster! " + actor.agentID); var index = localThis.actors.indexOf(actor); if (index >= 0) { localThis.actors.splice(index, 1); } actor.destroy(); + moveUI(); } newActor.resetClip(clipURL, function(actor) { From 921cd94c0794caace610ff3d0dcbbbf0723b19fb Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Tue, 1 Dec 2015 00:15:12 -0800 Subject: [PATCH 08/12] Finally a more stable api and playback use case --- examples/acScripts/AgentPoolControler.js | 20 ++++---------- examples/acScripts/playbackAgents.js | 35 ++++++------------------ examples/acScripts/playbackMaster.js | 15 ++++++---- 3 files changed, 23 insertions(+), 47 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index c7ecd70ad1..74ee12922a 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -192,27 +192,22 @@ function printDebug(message) { this.timeSinceLastAlive = 0; Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(BROADCAST_AGENTS, MASTER_ALIVE, MASTER_ID)); - printDebug("checking the agents status"); { // Check for alive connected agents var lostAgents = new Array(); for (var i = 0; i < this.hiredActors.length; i++) { var actor = this.hiredActors[i]; - printDebug("checking :" + JSON.stringify(actor)); var lastAlive = actor.incrementAliveCycle() if (lastAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Agent Lost, firing Agent"); - lostAgents.push(actor); + printDebug("Agent Lost, firing Agent #" + i + JSON.stringify(actor)); + lostAgents.push(i); } } - // now fire gathered lost agents - if (lostAgents.length > 0) { + // now fire gathered lost agents from end to begin + while (lostAgents.length > 0) { printDebug("Firing " + lostAgents.length + " agents" + JSON.stringify(lostAgents)); - - for (var i = 0; i < lostAgents.length; i++) { - this.fireAgent(lostAgents[l]); - } + this.fireAgent(this.hiredActors[lostAgents.pop()]); } } } @@ -251,7 +246,7 @@ function printDebug(message) { MasterController.prototype._removeAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("before _removeAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("MasterController.prototype._removeAgent #" + actorIndex + " " + JSON.stringify(this)) this.knownAgents.splice(actorIndex, 1); var lostActor = this.hiredActors[actorIndex]; @@ -259,9 +254,6 @@ function printDebug(message) { var lostAgentID = lostActor.agentID; lostActor.agentID = INVALID_AGENT; - - printDebug("Clearing agent " + actorIndex + " Forgeting about it"); - printDebug("after _removeAgent #" + actorIndex + " " + JSON.stringify(this)) if (lostAgentID != INVALID_AGENT) { printDebug("fired actor is still connected, send fire command"); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 67fe8c733e..64c25ec0a8 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -9,9 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Agent is an avatar -Agent.isAvatar = true; - Script.include("./AgentPoolControler.js"); var agentController = new AgentController(); @@ -34,8 +31,6 @@ var WAIT_FOR_AUDIO_MIXER = 1; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; -var SHOW = 4; -var HIDE = 5; var LOAD = 6; Recording.setPlayFromCurrentLocation(playFromCurrentLocation); @@ -71,28 +66,13 @@ function agentCommand(command) { Recording.stopPlaying(); } break; - case SHOW: - print("Show"); - break; - case HIDE: - print("Hide"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } - break; case LOAD: { print("Load" + command.argument_key); print("Agent #" + command.dest_key + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); print("After Load" + command.argument_key); - - /*if(command.argument_key == null) { - print("Agent #" + id + " loading clip URL is NULL, nothing happened"); - } else *{ - print("Agent #" + id + " loading clip URL: " + command.argument_key); - Recording.loadRecording(command.argument_key); - }*/ + Recording.setPlayerTime(0); } break; default: @@ -105,17 +85,18 @@ function agentCommand(command) { function agentHired() { print("Agent Hired from playbackAgents.js"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } + Agent.isAvatar = true; + Recording.stopPlaying(); Recording.setPlayerLoop(false); + Recording.setPlayerTime(0); } function agentFired() { print("Agent Fired from playbackAgents.js"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } + Recording.stopPlaying(); + Recording.setPlayerTime(0); + Recording.setPlayerLoop(false); + Agent.isAvatar = false; } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 7486256f07..d66a09d633 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -26,8 +26,6 @@ Tool.IMAGE_WIDTH /= 2; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; -var SHOW = 4; -var HIDE = 5; var LOAD = 6; var windowDimensions = Controller.getViewportDimensions(); @@ -42,10 +40,6 @@ var TEXT_MARGIN = 3; // Add new features to Actor class: Actor.prototype.destroy = function() { print("Actor.prototype.destroy"); - - this.toolbar.cleanup(); - Overlays.deleteOverlay(this.nameOverlay); - print("Need to fire myself" + this.agentID); masterController.fireAgent(this); } @@ -123,6 +117,11 @@ Actor.prototype._buildUI = function() { }); } +Actor.prototype._destroyUI = function() { + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); +} + Actor.prototype.moveUI = function(pos) { var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; this.toolbar.move(pos.x, pos.y); @@ -329,6 +328,9 @@ Director.prototype.hireActor = function(clipURL) { if (index >= 0) { localThis.actors.splice(index, 1); } + + actor._destroyUI(); + actor.destroy(); moveUI(); } @@ -338,6 +340,7 @@ Director.prototype.hireActor = function(clipURL) { masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); }); + masterController.hireAgent(newActor); newActor._buildUI(); From ff3ae852459e599dee20b69cd7ad4f83d578f9d2 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Dec 2015 12:36:49 -0800 Subject: [PATCH 09/12] Separating the ui to get the url from the actual loading to maybe avoid playbackMaster.js crash? --- examples/acScripts/AgentPoolControler.js | 22 +++++---- examples/acScripts/playbackMaster.js | 59 ++++++++++++++++-------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 74ee12922a..e5917ea93e 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -141,7 +141,7 @@ function printDebug(message) { } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this._removeAgent(agentIndex); + this._removeHiredAgent(agentIndex); } } else if (message.command == AGENT_ALIVE) { // check to see if we know about this agent @@ -199,7 +199,7 @@ function printDebug(message) { var actor = this.hiredActors[i]; var lastAlive = actor.incrementAliveCycle() if (lastAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Agent Lost, firing Agent #" + i + JSON.stringify(actor)); + printDebug("Agent Lost, firing Agent #" + i + " ID " + actor.agentID); lostAgents.push(i); } } @@ -228,25 +228,31 @@ function printDebug(message) { MasterController.prototype.fireAgent = function(actor) { // check to see if we know about this agent - printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + printDebug("MasterController.prototype.fireAgent" + actor.agentID); + // Try the waiting list first var waitingIndex = this.hiringAgentsQueue.indexOf(actor); if (waitingIndex >= 0) { - printDebug("MasterController.prototype.fireAgent found actor on waiting queue #" + waitingIndex); - this.hiringAgentsQueue.splice(waitingIndex, 1); + printDebug("fireAgent found actor on waiting queue #" + waitingIndex); + var lostActor = this.hiringAgentsQueue.splice(waitingIndex, 1); + if (lostActor.length) { + lostActor[0].onFired(lostActor[0]); + } + return; } + // then the hired agents var actorIndex = this.knownAgents.indexOf(actor.agentID); if (actorIndex >= 0) { printDebug("fired actor found #" + actorIndex); - this._removeAgent(actorIndex); + this._removeHiredAgent(actorIndex); } } - MasterController.prototype._removeAgent = function(actorIndex) { + MasterController.prototype._removeHiredAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("MasterController.prototype._removeAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("MasterController.prototype._removeHiredAgent #" + this.knownAgents[actorIndex]) this.knownAgents.splice(actorIndex, 1); var lostActor = this.hiredActors[actorIndex]; diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index d66a09d633..5115dc9871 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -61,6 +61,8 @@ Actor.prototype.onMousePressEvent = function(clickedOverlay) { masterController.sendCommand(this.agentID, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(this.agentID, STOP); + } else if (this.nameOverlay === clickedOverlay) { + print("Actor: " + JSON.stringify(this)); } else { return false; } @@ -136,6 +138,8 @@ Director = function() { this.actors = new Array(); this.toolbar = null; this._buildUI(); + this.requestPerformanceLoad = false; + this.performanceURL = ""; }; Director.prototype.destroy = function () { @@ -234,27 +238,11 @@ Director.prototype.onMousePressEvent = function(clickedOverlay) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); - var urlpartition = input_text.split("."); - print(urlpartition[0]); - print(urlpartition[1]); - - if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { - print("detected a unique clip url"); - var oneClipPerformance = new Object(); - oneClipPerformance.avatarClips = new Array(); - oneClipPerformance.avatarClips[0] = input_text; - - print(JSON.stringify(oneClipPerformance)); - - // we make a local simple performance file with a single clip and pipe in directly - this.onPerformanceLoaded(oneClipPerformance); - return true; - } else { - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); - } + this.requestPerformanceLoad = true; + this.performanceURL = input_text; } + } else if (this.nameOverlay === clickedOverlay) { + print("Director: " + JSON.stringify(this)); } else { // Check individual controls for (var i = 0; i < this.actors.length; i++) { @@ -285,6 +273,32 @@ Director.prototype.moveUI = function(pos) { } } + +Director.prototype.reloadPerformance = function() { + this.requestPerformanceLoad = false; + + var urlpartition = this.performanceURL.split("."); + print(urlpartition[0]); + print(urlpartition[1]); + + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } +} + Director.prototype.onPerformanceLoaded = function(performanceJSON) { // First fire all the current actors this.clearActors(); @@ -377,6 +391,11 @@ function update(deltaTime) { moveUI(); } + if (director.requestPerformanceLoad) { + print("reloadPerformance " + director.performanceURL); + director.reloadPerformance(); + } + masterController.update(deltaTime); } From 86af28dbab66cd3558428000d5368252035998ee Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Dec 2015 18:18:18 -0800 Subject: [PATCH 10/12] Fighting for one hour with the ready message being misunderstood by master --- examples/acScripts/AgentPoolControler.js | 67 +++++++++++++----------- examples/acScripts/playbackMaster.js | 44 +++++++++------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index e5917ea93e..830a8fe1e3 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -131,21 +131,21 @@ function printDebug(message) { }; MasterController.prototype._processServiceMessage = function(message, senderID) { - var message = unpackServiceMessage(message); - if (message.dest == MASTER_ID) { - if (message.command == AGENT_READY) { + var service = unpackServiceMessage(message); + if (service.dest == MASTER_ID) { + if (service.command == AGENT_READY) { // check to see if we know about this agent - var agentIndex = this.knownAgents.indexOf(message.src); + var agentIndex = this.knownAgents.indexOf(service.src); if (agentIndex < 0) { - this._onAgentAvailableForHiring(message.src); + this._onAgentAvailableForHiring(service.src); } else { // Master think the agent is hired but not the other way around, forget about it - printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this._removeHiredAgent(agentIndex); + printDebug("New agent still sending ready ? " + service.src + " " + agentIndex + " Forgeting about it"); + // this._removeHiredAgent(agentIndex); } - } else if (message.command == AGENT_ALIVE) { + } else if (service.command == AGENT_ALIVE) { // check to see if we know about this agent - var agentIndex = this.knownAgents.indexOf(message.src); + var agentIndex = this.knownAgents.indexOf(service.src); if (agentIndex >= 0) { // yes so reset its alive beat this.hiredActors[agentIndex].alive(); @@ -171,8 +171,10 @@ function printDebug(message) { newActor.agentID = agentID; this.hiredActors.push(newActor); - printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); - Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID)); + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + var serviceMessage = packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID); + printDebug("serviceMessage = " + serviceMessage); + Messages.sendMessage(SERVICE_CHANNEL, serviceMessage); printDebug("message sent calling the actor" + JSON.stringify(newActor) ); newActor.onHired(newActor); @@ -276,7 +278,6 @@ function printDebug(message) { //--------------------------------- var AgentController = function() { this.subscribed = false; - this._init(); this.onHired = function() {}; @@ -325,40 +326,42 @@ function printDebug(message) { }; AgentController.prototype._processServiceMessage = function(message, senderID) { - var announce = unpackServiceMessage(message); - //printDebug("Client " + this.agentUUID + " Received Announcement = " + message); - if (announce.dest == this.agentUUID) { - if (announce.command != AGENT_READY) { - var parts = announce.command.split("."); + var service = unpackServiceMessage(message); + printDebug("Client " + this.agentUUID + " Received message = " + message); + if (service.dest == this.agentUUID) { + if (service.command != AGENT_READY) { - // this is potnetially a message to hire me if i m not already - if (!this.isHired && (parts[0] == MASTER_HIRE_AGENT)) { - printDebug(announce.command); + // this is potentially a message to hire me if i m not already + if (!this.isHired && (service.command == MASTER_HIRE_AGENT)) { + printDebug(service.command); this.isHired = true; - printDebug("Client Hired by master UUID" + senderID); - this.onHired(); + printDebug("Client Hired by master UUID" + service.src); + this.onHired(); + this.alive(); return; } - if (this.isHired && (parts[0] == MASTER_FIRE_AGENT)) { + // Or maybe a message to fire me if i m not hired + if (this.isHired && (service.command == MASTER_FIRE_AGENT)) { printDebug("Client Fired by master UUID" + senderID); this.fired(); return; } } - } else if (announce.src == MASTER_ID && announce.command == MASTER_ALIVE) { + } else if ((service.src == MASTER_ID) && (service.command == MASTER_ALIVE)) { this.numCyclesWithoutAlive = 0; return; } } AgentController.prototype._processCommandMessage = function(message, senderID) { - var command = unpackCommandMessage(message); - if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { - printDebug("Command received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } else { - // ignored + // ONly work if hired + if (this.isHired) { + var command = unpackCommandMessage(message); + if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { + printDebug("Command received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } } }; @@ -370,9 +373,9 @@ function printDebug(message) { if (!this.isHired) { Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_READY, this.agentUUID)); //printDebug("Client Ready" + SERVICE_CHANNEL + AGENT_READY); - } else { - + } else { // Send alive beat + printDebug("beat !"); Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_ALIVE, this.agentUUID)); // Listen for master beat diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 5115dc9871..a88b699bf8 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -275,28 +275,34 @@ Director.prototype.moveUI = function(pos) { Director.prototype.reloadPerformance = function() { - this.requestPerformanceLoad = false; - - var urlpartition = this.performanceURL.split("."); - print(urlpartition[0]); - print(urlpartition[1]); + this.requestPerformanceLoad = false; - if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { - print("detected a unique clip url"); - var oneClipPerformance = new Object(); - oneClipPerformance.avatarClips = new Array(); - oneClipPerformance.avatarClips[0] = input_text; + if (this.performanceURL[0] == '{') { + var jsonPerformance = JSON.parse(this.performanceURL); + this.onPerformanceLoaded(jsonPerformance); + } else { - print(JSON.stringify(oneClipPerformance)); + var urlpartition = this.performanceURL.split("."); + print(urlpartition[0]); + print(urlpartition[1]); - // we make a local simple performance file with a single clip and pipe in directly - this.onPerformanceLoaded(oneClipPerformance); - return true; - } else { - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); - } + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } + } } Director.prototype.onPerformanceLoaded = function(performanceJSON) { From 586ed51436aec549d011d97c8923b0ad1dd3bfc4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 09:56:16 -0800 Subject: [PATCH 11/12] rename AgentPoolCOntroller.js --- .../acScripts/{AgentPoolControler.js => AgentPoolController.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/acScripts/{AgentPoolControler.js => AgentPoolController.js} (100%) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolController.js similarity index 100% rename from examples/acScripts/AgentPoolControler.js rename to examples/acScripts/AgentPoolController.js From 0ae70603168a54d18fd0f4b57f8abf0abc5c420b Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 10:23:31 -0800 Subject: [PATCH 12/12] the correct includes --- examples/acScripts/playbackAgents.js | 2 +- examples/acScripts/playbackMaster.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 64c25ec0a8..cf805623de 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("./AgentPoolControler.js"); +Script.include("./AgentPoolController.js"); var agentController = new AgentController(); // Set the following variables to the values needed diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index a88b699bf8..dff0b1d852 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("./AgentPoolControler.js"); +Script.include("./AgentPoolController.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";