mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 04:53:28 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into possible-fix-for-2068
This commit is contained in:
commit
3ad748cfe2
18 changed files with 210 additions and 149 deletions
Binary file not shown.
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
@ -229,7 +229,7 @@ public:
|
|||
|
||||
qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); }
|
||||
|
||||
bool isAboutToQuit() const { return _aboutToQuit; }
|
||||
bool isAboutToQuit() const override { return _aboutToQuit; }
|
||||
bool isPhysicsEnabled() const { return _physicsEnabled; }
|
||||
|
||||
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
|
||||
|
|
|
@ -95,7 +95,13 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer>
|
|||
|
||||
auto deleter = [](OffscreenQmlSurface* webSurface) {
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
|
||||
webSurface->deleteLater();
|
||||
if (AbstractViewStateInterface::instance()->isAboutToQuit()) {
|
||||
// WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
|
||||
// if the application has already stopped its event loop, delete must be explicit
|
||||
delete webSurface;
|
||||
} else {
|
||||
webSurface->deleteLater();
|
||||
}
|
||||
});
|
||||
};
|
||||
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
||||
|
@ -333,6 +339,7 @@ void RenderableWebEntityItem::destroyWebSurface() {
|
|||
if (rootItem) {
|
||||
QObject* obj = rootItem->findChild<QObject*>("webEngineView");
|
||||
if (obj) {
|
||||
// stop loading
|
||||
QMetaObject::invokeMethod(obj, "stop");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,11 @@ void UserActivityLoggerScriptingInterface::toggledAway(bool isAway) {
|
|||
logAction("toggled_away", { { "is_away", isAway } });
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::tutorialProgress(QString stepName, int stepNumber, float secondsToComplete, float tutorialElapsedTime) {
|
||||
void UserActivityLoggerScriptingInterface::tutorialProgress( QString stepName, int stepNumber, float secondsToComplete,
|
||||
float tutorialElapsedTime, QString tutorialRunID, int tutorialVersion) {
|
||||
logAction("tutorial_progress", {
|
||||
{ "tutorial_run_id", tutorialRunID },
|
||||
{ "tutorial_version", tutorialVersion },
|
||||
{ "step", stepName },
|
||||
{ "step_number", stepNumber },
|
||||
{ "seconds_to_complete", secondsToComplete },
|
||||
|
|
|
@ -23,7 +23,8 @@ public:
|
|||
Q_INVOKABLE void enabledEdit();
|
||||
Q_INVOKABLE void openedMarketplace();
|
||||
Q_INVOKABLE void toggledAway(bool isAway);
|
||||
Q_INVOKABLE void tutorialProgress(QString stepName, int stepNumber, float secondsToComplete, float tutorialElapsedTime);
|
||||
Q_INVOKABLE void tutorialProgress(QString stepName, int stepNumber, float secondsToComplete,
|
||||
float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0);
|
||||
|
||||
private:
|
||||
void logAction(QString action, QJsonObject details = {});
|
||||
|
|
|
@ -49,7 +49,7 @@ Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) :
|
|||
connect(&_udpSocket, &QAbstractSocket::stateChanged, this, &Socket::handleStateChanged);
|
||||
|
||||
// in order to help track down the zombie server bug, add a timer to check if we missed a readyRead
|
||||
const int READY_READ_BACKUP_CHECK_MSECS = 10 * 1000;
|
||||
const int READY_READ_BACKUP_CHECK_MSECS = 2 * 1000;
|
||||
connect(_readyReadBackupTimer, &QTimer::timeout, this, &Socket::checkForReadyReadBackup);
|
||||
_readyReadBackupTimer->start(READY_READ_BACKUP_CHECK_MSECS);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,9 @@ public:
|
|||
|
||||
virtual glm::vec3 getAvatarPosition() const = 0;
|
||||
|
||||
virtual bool isAboutToQuit() const = 0;
|
||||
virtual void postLambdaEvent(std::function<void()> f) = 0;
|
||||
|
||||
virtual qreal getDevicePixelRatio() = 0;
|
||||
|
||||
virtual render::ScenePointer getMain3DScene() = 0;
|
||||
|
|
|
@ -56,10 +56,6 @@ void BatchLoader::start() {
|
|||
// If BatchLoader is deleted before the callback is called, the subsequent "emit" call will not do
|
||||
// anything.
|
||||
ScriptCacheSignalProxy* proxy = new ScriptCacheSignalProxy(scriptCache.data());
|
||||
scriptCache->getScriptContents(url.toString(), [proxy](const QString& url, const QString& contents, bool isURL, bool success) {
|
||||
proxy->receivedContent(url, contents, isURL, success);
|
||||
proxy->deleteLater();
|
||||
}, false);
|
||||
|
||||
connect(proxy, &ScriptCacheSignalProxy::contentAvailable, this, [this](const QString& url, const QString& contents, bool isURL, bool success) {
|
||||
if (isURL && success) {
|
||||
|
@ -75,6 +71,11 @@ void BatchLoader::start() {
|
|||
emit finished(_data);
|
||||
}
|
||||
});
|
||||
|
||||
scriptCache->getScriptContents(url.toString(), [proxy](const QString& url, const QString& contents, bool isURL, bool success) {
|
||||
proxy->receivedContent(url, contents, isURL, success);
|
||||
proxy->deleteLater();
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -146,6 +146,8 @@ public:
|
|||
|
||||
Q_INVOKABLE void requestGarbageCollection() { collectGarbage(); }
|
||||
|
||||
Q_INVOKABLE QUuid generateUUID() { return QUuid::createUuid(); }
|
||||
|
||||
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
||||
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||
|
||||
print('crowd-agent version 3');
|
||||
print('crowd-agent version 4');
|
||||
|
||||
/* Observations:
|
||||
- File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development.
|
||||
|
@ -34,19 +34,56 @@ function getSound(data, callback) { // callback(sound) when downloaded (which ma
|
|||
if (sound.downloaded) {
|
||||
return callback(sound);
|
||||
}
|
||||
sound.ready.connect(function () { callback(sound); });
|
||||
function onDownloaded() {
|
||||
sound.ready.disconnect(onDownloaded);
|
||||
callback(sound);
|
||||
}
|
||||
sound.ready.connect(onDownloaded);
|
||||
}
|
||||
function onFinishedPlaying() {
|
||||
messageSend({key: 'finishedSound'});
|
||||
}
|
||||
|
||||
var attachment;
|
||||
var stopper;
|
||||
function clearStopper() {
|
||||
if (!stopper) {
|
||||
return;
|
||||
}
|
||||
Script.clearTimeout(stopper);
|
||||
stopper = null;
|
||||
}
|
||||
function stopAgent(parameters) {
|
||||
function stop() {
|
||||
clearStopper();
|
||||
if (attachment) {
|
||||
Avatar.detachOne(attachment.modelURL, attachment.jointName);
|
||||
attachment = undefined;
|
||||
}
|
||||
Agent.isListeningToAudioStream = false;
|
||||
Agent.isAvatar = false;
|
||||
print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent));
|
||||
}
|
||||
// Shutting down lots of agents at once can be hard on other parts of the system. (See fogbugz 2095.)
|
||||
// For now, accept a parameter to delay for the given number of milliseconds before stopping.
|
||||
// (We cannot count on summoning scripts to spread out the STOP messages, because they might be doing so
|
||||
// on scriptEnding, in which case they are not allowed to create new delays.)
|
||||
if (parameters.delay) {
|
||||
if (!stopper) { // Let the first stopper do the deed.
|
||||
stopper = Script.setTimeout(stop, parameters.delay);
|
||||
}
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var MILLISECONDS_IN_SECOND = 1000;
|
||||
function startAgent(parameters) { // Can also be used to update.
|
||||
print('crowd-agent starting params', JSON.stringify(parameters), JSON.stringify(Agent));
|
||||
clearStopper();
|
||||
var wasOff = !Agent.isAvatar;
|
||||
Agent.isAvatar = true;
|
||||
Agent.isListeningToAudioStream = true; // Send silence when not chattering.
|
||||
if (parameters.position) {
|
||||
Avatar.position = parameters.position;
|
||||
}
|
||||
|
@ -56,6 +93,11 @@ function startAgent(parameters) { // Can also be used to update.
|
|||
if (parameters.skeletonModelURL) {
|
||||
Avatar.skeletonModelURL = parameters.skeletonModelURL;
|
||||
}
|
||||
if (parameters.listen != undefined) {
|
||||
Agent.isListeningToAudioStream = parameters.listen; // Send silence when not chattering.
|
||||
} else if (wasOff) {
|
||||
Agent.isListeningToAudioStream = true;
|
||||
}
|
||||
if (parameters.soundData) {
|
||||
getSound(parameters.soundData, function (sound) {
|
||||
Script.setTimeout(onFinishedPlaying, sound.duration * MILLISECONDS_IN_SECOND);
|
||||
|
@ -74,14 +116,6 @@ function startAgent(parameters) { // Can also be used to update.
|
|||
}
|
||||
print('crowd-agent avatars started');
|
||||
}
|
||||
function stopAgent(parameters) {
|
||||
if (attachment) {
|
||||
Avatar.detachOne(attachment.modelURL, attachment.jointName);
|
||||
attachment = undefined;
|
||||
}
|
||||
Agent.isAvatar = false;
|
||||
print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent));
|
||||
}
|
||||
|
||||
function messageHandler(channel, messageString, senderID) {
|
||||
if (channel !== MESSAGE_CHANNEL) {
|
||||
|
|
|
@ -21,6 +21,10 @@ var NOMINAL_LOAD_TIME = 30; // seconds
|
|||
var MAXIMUM_LOAD_TIME = NOMINAL_LOAD_TIME * 2;
|
||||
var MINIMUM_AVATARS = 25; // changeable by prompt
|
||||
|
||||
// If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095).
|
||||
// For now, spread them out this timing apart.
|
||||
var SPREAD_TIME_MS = 500;
|
||||
|
||||
var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's length (0.9m^2), 4.5 is crowd (0.4m^2), 2.5 is mosh pit (0.2m^2).
|
||||
var SOUND_DATA = {url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"};
|
||||
var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND at once.
|
||||
|
@ -34,7 +38,7 @@ var ANIMATION_DATA = {
|
|||
"loopFlag": true
|
||||
};
|
||||
|
||||
var version = 3;
|
||||
var version = 4;
|
||||
function debug() {
|
||||
print.apply(null, [].concat.apply(['hrs fixme', version], [].map.call(arguments, JSON.stringify)));
|
||||
}
|
||||
|
@ -86,6 +90,7 @@ function nextAfter(array, id) { // Wrapping next element in array after id.
|
|||
|
||||
var summonedAgents = [];
|
||||
var chattering = [];
|
||||
var accumulatedDelay = 0;
|
||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||
function messageSend(message) {
|
||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||
|
@ -106,25 +111,29 @@ function messageHandler(channel, messageString, senderID) {
|
|||
}
|
||||
switch (message.key) {
|
||||
case "hello":
|
||||
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
||||
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
||||
debug('present', avatarIdentifiers, summonedAgents);
|
||||
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS) {
|
||||
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
||||
if (chatter) {
|
||||
chattering.push(senderID);
|
||||
Script.setTimeout(function () {
|
||||
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
||||
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
||||
debug('present', avatarIdentifiers, summonedAgents);
|
||||
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS) {
|
||||
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
||||
if (chatter) {
|
||||
chattering.push(senderID);
|
||||
}
|
||||
summonedAgents.push(senderID);
|
||||
messageSend({
|
||||
key: 'SUMMON',
|
||||
rcpt: senderID,
|
||||
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
|
||||
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
|
||||
soundData: chatter && SOUND_DATA,
|
||||
listen: true,
|
||||
skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst",
|
||||
animationData: ANIMATION_DATA
|
||||
});
|
||||
}
|
||||
summonedAgents.push(senderID);
|
||||
messageSend({
|
||||
key: 'SUMMON',
|
||||
rcpt: senderID,
|
||||
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
|
||||
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
|
||||
soundData: chatter && SOUND_DATA,
|
||||
skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst",
|
||||
animationData: ANIMATION_DATA
|
||||
});
|
||||
}
|
||||
}, accumulatedDelay);
|
||||
accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together.
|
||||
break;
|
||||
case "finishedSound": // Give someone else a chance.
|
||||
chattering = without(chattering, [senderID]);
|
||||
|
@ -147,13 +156,15 @@ Messages.subscribe(MESSAGE_CHANNEL);
|
|||
Messages.messageReceived.connect(messageHandler);
|
||||
Script.scriptEnding.connect(function () {
|
||||
debug('stopping agents', summonedAgents);
|
||||
summonedAgents.forEach(function (id) { messageSend({key: 'STOP', rcpt: id}); });
|
||||
Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown
|
||||
accumulatedDelay = 0;
|
||||
summonedAgents.forEach(function (id) {
|
||||
messageSend({key: 'STOP', rcpt: id, delay: accumulatedDelay});
|
||||
accumulatedDelay += SPREAD_TIME_MS;
|
||||
});
|
||||
debug('agents stopped');
|
||||
Script.setTimeout(function () {
|
||||
Messages.messageReceived.disconnect(messageHandler);
|
||||
Messages.unsubscribe(MESSAGE_CHANNEL);
|
||||
debug('unsubscribed');
|
||||
}, 500);
|
||||
Messages.unsubscribe(MESSAGE_CHANNEL);
|
||||
debug('unsubscribed');
|
||||
});
|
||||
|
||||
var fail = false, results = "";
|
||||
|
@ -257,7 +268,7 @@ function doRender(continuation) {
|
|||
}
|
||||
|
||||
config.newStats.connect(onNewStats);
|
||||
startTwirl(720, 1, 15, 0.08, function () {
|
||||
startTwirl(720, 1, 20, 0.08, function () {
|
||||
var end = Date.now();
|
||||
config.newStats.disconnect(onNewStats);
|
||||
addResult('frame rate', 1000 * frames / (end - start),
|
||||
|
@ -270,7 +281,7 @@ function doRender(continuation) {
|
|||
http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=3\n\
|
||||
on your domain server.";
|
||||
} else if (total < MINIMUM_AVATARS) {
|
||||
fail = "FAIL: Only " + summonedAgents.length + " avatars reported. Missing " + (MINIMUM_AVATARS - total) + ".";
|
||||
fail = "FAIL: Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total.";
|
||||
}
|
||||
}
|
||||
continuation();
|
||||
|
|
|
@ -13,19 +13,26 @@
|
|||
//
|
||||
// See crowd-agent.js
|
||||
|
||||
var version = 1;
|
||||
var version = 2;
|
||||
var label = "summon";
|
||||
function debug() {
|
||||
print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify)));
|
||||
}
|
||||
|
||||
var MINIMUM_AVATARS = 25; // We will summon agents to produce this many total. (Of course, there might not be enough agents.)
|
||||
var N_LISTENING = MINIMUM_AVATARS - 1;
|
||||
var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND_DATA at once.
|
||||
|
||||
// If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095).
|
||||
// For now, spread them out this timing apart.
|
||||
var SPREAD_TIME_MS = 500;
|
||||
|
||||
var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's length (0.9m^2), 4.5 is crowd (0.4m^2), 2.5 is mosh pit (0.2m^2).
|
||||
var SOUND_DATA = {url: "http://howard-stearns.github.io/models/sounds/piano1.wav"};
|
||||
var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND at once.
|
||||
var SOUND_DATA = {url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"};
|
||||
var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next
|
||||
var ANIMATION_DATA = {
|
||||
"url": "http://howard-stearns.github.io/models/resources/avatar/animations/idle.fbx",
|
||||
// "url": "http://howard-stearns.github.io/models/resources/avatar/animations/walk_fwd.fbx", // alternative example
|
||||
"url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/idle.fbx",
|
||||
// "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/walk_fwd.fbx", // alternative example
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 300.0,
|
||||
"timeScale": 1.0,
|
||||
|
@ -45,6 +52,8 @@ function nextAfter(array, id) { // Wrapping next element in array after id.
|
|||
|
||||
var summonedAgents = [];
|
||||
var chattering = [];
|
||||
var nListening = 0;
|
||||
var accumulatedDelay = 0;
|
||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||
function messageSend(message) {
|
||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||
|
@ -65,25 +74,33 @@ function messageHandler(channel, messageString, senderID) {
|
|||
}
|
||||
switch (message.key) {
|
||||
case "hello":
|
||||
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
||||
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
||||
debug('present', avatarIdentifiers, summonedAgents);
|
||||
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS ) {
|
||||
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
||||
if (chatter) {
|
||||
chattering.push(senderID);
|
||||
Script.setTimeout(function () {
|
||||
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
||||
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
||||
debug('present', avatarIdentifiers, summonedAgents);
|
||||
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS ) {
|
||||
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
||||
var listen = nListening < N_LISTENING;
|
||||
if (chatter) {
|
||||
chattering.push(senderID);
|
||||
}
|
||||
if (listen) {
|
||||
nListening++;
|
||||
}
|
||||
summonedAgents.push(senderID);
|
||||
messageSend({
|
||||
key: 'SUMMON',
|
||||
rcpt: senderID,
|
||||
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
|
||||
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
|
||||
soundData: chatter && SOUND_DATA,
|
||||
listen: listen,
|
||||
skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst",
|
||||
animationData: ANIMATION_DATA
|
||||
});
|
||||
}
|
||||
summonedAgents.push(senderID);
|
||||
messageSend({
|
||||
key: 'SUMMON',
|
||||
rcpt: senderID,
|
||||
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
|
||||
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
|
||||
soundData: chatter && SOUND_DATA,
|
||||
skeletonModelURL: "http://howard-stearns.github.io/models/resources/meshes/defaultAvatar_full.fst",
|
||||
animationData: ANIMATION_DATA
|
||||
});
|
||||
}
|
||||
}, accumulatedDelay);
|
||||
accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together.
|
||||
break;
|
||||
case "finishedSound": // Give someone else a chance.
|
||||
chattering = without(chattering, [senderID]);
|
||||
|
@ -99,20 +116,22 @@ function messageHandler(channel, messageString, senderID) {
|
|||
Window.alert("Someone else is summoning avatars.");
|
||||
break;
|
||||
default:
|
||||
print("crowd-agent received unrecognized message:", messageString);
|
||||
print("crowd summon.js received unrecognized message:", messageString);
|
||||
}
|
||||
}
|
||||
Messages.subscribe(MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.connect(messageHandler);
|
||||
Script.scriptEnding.connect(function () {
|
||||
debug('stopping agents', summonedAgents);
|
||||
summonedAgents.forEach(function (id) { messageSend({key: 'STOP', rcpt: id}); });
|
||||
Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown
|
||||
accumulatedDelay = 0;
|
||||
summonedAgents.forEach(function (id) {
|
||||
messageSend({key: 'STOP', rcpt: id, delay: accumulatedDelay});
|
||||
accumulatedDelay += SPREAD_TIME_MS;
|
||||
});
|
||||
debug('agents stopped');
|
||||
Script.setTimeout(function () {
|
||||
Messages.messageReceived.disconnect(messageHandler);
|
||||
Messages.unsubscribe(MESSAGE_CHANNEL);
|
||||
debug('unsubscribed');
|
||||
}, 500);
|
||||
Messages.unsubscribe(MESSAGE_CHANNEL);
|
||||
debug('unsubscribed');
|
||||
});
|
||||
|
||||
messageSend({key: 'HELO'}); // Ask agents to report in now.
|
||||
|
@ -120,9 +139,9 @@ Script.setTimeout(function () {
|
|||
var total = AvatarList.getAvatarIdentifiers().length;
|
||||
if (0 === summonedAgents.length) {
|
||||
Window.alert("No agents reported.\n\Please run " + MINIMUM_AVATARS + " instances of\n\
|
||||
http://cdn.highfidelity.com/davidkelly/production/scripts/tests/performance/crowd-agent.js\n\
|
||||
http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js\n\
|
||||
on your domain server.");
|
||||
} else if (total < MINIMUM_AVATARS) {
|
||||
Window.alert("Only " + summonedAgents.length + " of the expected " + (MINIMUM_AVATARS - total) + " agents reported in.");
|
||||
Window.alert("Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total.");
|
||||
}
|
||||
}, 5000);
|
||||
}, MINIMUM_AVATARS * SPREAD_TIME_MS )
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
BAR_DESKTOP_2K_HEIGHT = 3, // Display height of SVG
|
||||
BAR_DESKTOP_2K_URL = Script.resolvePath("assets/images/progress-bar-2k.svg"),
|
||||
|
||||
BAR_DESKTOP_4K_WIDTH = 4480, // Width of SVG image in pixels. Sized for 1920 x 1080 display with 6 visible repeats.
|
||||
BAR_DESKTOP_4K_WIDTH = 4480, // Width of SVG image in pixels. Sized for 4096 x 1920 display with 6 visible repeats.
|
||||
BAR_DESKTOP_4K_REPEAT = 640, // Length of repeat in bar = 2240 / 7.
|
||||
BAR_DESKTOP_4K_HEIGHT = 6, // Display height of SVG
|
||||
BAR_DESKTOP_4K_URL = Script.resolvePath("assets/images/progress-bar-4k.svg"),
|
||||
|
|
|
@ -163,17 +163,19 @@ function shutdownCallback(idx) {
|
|||
if (homeServer.state == ProcessGroupStates.STOPPED) {
|
||||
// if the home server is already down, take down the server console now
|
||||
log.debug("Quitting.");
|
||||
app.quit();
|
||||
app.exit(0);
|
||||
} else {
|
||||
// if the home server is still running, wait until we get a state change or timeout
|
||||
// before quitting the app
|
||||
log.debug("Server still shutting down. Waiting");
|
||||
var timeoutID = setTimeout(app.quit, 5000);
|
||||
var timeoutID = setTimeout(function() {
|
||||
app.exit(0);
|
||||
}, 5000);
|
||||
homeServer.on('state-update', function(processGroup) {
|
||||
if (processGroup.state == ProcessGroupStates.STOPPED) {
|
||||
clearTimeout(timeoutID);
|
||||
log.debug("Quitting.");
|
||||
app.quit();
|
||||
app.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -240,7 +242,7 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory)
|
|||
|
||||
if (shouldQuit) {
|
||||
log.warn("Another instance of the Sandbox is already running - this instance will quit.");
|
||||
app.quit();
|
||||
app.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -288,12 +290,12 @@ function binaryMissingMessage(displayName, executableName, required) {
|
|||
|
||||
if (!dsPath) {
|
||||
dialog.showErrorBox("Domain Server Not Found", binaryMissingMessage("domain-server", "domain-server", true));
|
||||
app.quit();
|
||||
app.exit(0);
|
||||
}
|
||||
|
||||
if (!acPath) {
|
||||
dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true));
|
||||
app.quit();
|
||||
app.exit(0);
|
||||
}
|
||||
|
||||
function openFileBrowser(path) {
|
||||
|
|
|
@ -425,6 +425,7 @@ protected:
|
|||
return vec3();
|
||||
}
|
||||
|
||||
bool isAboutToQuit() const override { return false; }
|
||||
void postLambdaEvent(std::function<void()> f) override {}
|
||||
|
||||
qreal getDevicePixelRatio() override {
|
||||
|
|
|
@ -391,61 +391,6 @@ stepOrient.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// STEP: Raise hands above head //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepRaiseAboveHead = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
}
|
||||
stepRaiseAboveHead.prototype = {
|
||||
start: function(onFinish) {
|
||||
var tag = this.tag;
|
||||
|
||||
var STATE_START = 0;
|
||||
var STATE_HANDS_DOWN = 1;
|
||||
var STATE_HANDS_UP = 2;
|
||||
this.state = STATE_START;
|
||||
|
||||
editEntitiesWithTag(this.tag, { visible: true });
|
||||
|
||||
// Wait 2 seconds before starting to check for hands
|
||||
this.checkIntervalID = null;
|
||||
function checkForHandsAboveHead() {
|
||||
debug("RaiseAboveHead | Checking hands");
|
||||
if (this.state == STATE_START) {
|
||||
if (MyAvatar.getLeftPalmPosition().y < (MyAvatar.getHeadPosition().y - 0.1)) {
|
||||
this.state = STATE_HANDS_DOWN;
|
||||
}
|
||||
} else if (this.state == STATE_HANDS_DOWN) {
|
||||
if (MyAvatar.getLeftPalmPosition().y > (MyAvatar.getHeadPosition().y + 0.1)) {
|
||||
this.state = STATE_HANDS_UP;
|
||||
Script.clearInterval(this.checkIntervalID);
|
||||
this.checkIntervalID = null;
|
||||
playSuccessSound();
|
||||
onFinish();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.checkIntervalID = Script.setInterval(checkForHandsAboveHead.bind(this), 500);
|
||||
},
|
||||
cleanup: function() {
|
||||
debug("RaiseAboveHead | Cleanup");
|
||||
if (this.checkIntervalID) {
|
||||
Script.clearInterval(this.checkIntervalID);
|
||||
this.checkIntervalID = null
|
||||
}
|
||||
if (this.waitTimeoutID) {
|
||||
Script.clearTimeout(this.waitTimeoutID);
|
||||
this.waitTimeoutID = null;
|
||||
}
|
||||
editEntitiesWithTag(this.tag, { visible: false, collisionless: 1 });
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1027,16 +972,23 @@ TutorialManager = function() {
|
|||
var startedTutorialAt = 0;
|
||||
var startedLastStepAt = 0;
|
||||
|
||||
var wentToEntryStepNum;
|
||||
var VERSION = 1;
|
||||
var tutorialID;
|
||||
|
||||
var self = this;
|
||||
|
||||
this.startTutorial = function() {
|
||||
currentStepNum = -1;
|
||||
currentStep = null;
|
||||
startedTutorialAt = Date.now();
|
||||
|
||||
// Old versions of interface do not have the Script.generateUUID function.
|
||||
// If Script.generateUUID is not available, default to an empty string.
|
||||
tutorialID = Script.generateUUID ? Script.generateUUID() : "";
|
||||
STEPS = [
|
||||
new stepStart("start"),
|
||||
new stepOrient("orient"),
|
||||
//new stepRaiseAboveHead("raiseHands"),
|
||||
new stepNearGrab("nearGrab"),
|
||||
new stepFarGrab("farGrab"),
|
||||
new stepEquip("equip"),
|
||||
|
@ -1045,6 +997,7 @@ TutorialManager = function() {
|
|||
new stepFinish("finish"),
|
||||
new stepEnableControllers("enableControllers"),
|
||||
];
|
||||
wentToEntryStepNum = STEPS.length;
|
||||
for (var i = 0; i < STEPS.length; ++i) {
|
||||
STEPS[i].cleanup();
|
||||
}
|
||||
|
@ -1055,10 +1008,7 @@ TutorialManager = function() {
|
|||
this.onFinish = function() {
|
||||
debug("onFinish", currentStepNum);
|
||||
if (currentStep && currentStep.shouldLog !== false) {
|
||||
var timeToFinishStep = (Date.now() - startedLastStepAt) / 1000;
|
||||
var tutorialTimeElapsed = (Date.now() - startedTutorialAt) / 1000;
|
||||
UserActivityLogger.tutorialProgress(
|
||||
currentStep.tag, currentStepNum, timeToFinishStep, tutorialTimeElapsed);
|
||||
self.trackStep(currentStep.tag, currentStepNum);
|
||||
}
|
||||
|
||||
self.startNextStep();
|
||||
|
@ -1071,6 +1021,12 @@ TutorialManager = function() {
|
|||
|
||||
++currentStepNum;
|
||||
|
||||
// This always needs to be set because we use this value when
|
||||
// tracking that the user has gone through the entry portal. When the
|
||||
// tutorial finishes, there is a last "pseudo" step that the user
|
||||
// finishes when stepping into the portal.
|
||||
startedLastStepAt = Date.now();
|
||||
|
||||
if (currentStepNum >= STEPS.length) {
|
||||
// Done
|
||||
info("DONE WITH TUTORIAL");
|
||||
|
@ -1080,7 +1036,6 @@ TutorialManager = function() {
|
|||
} else {
|
||||
info("Starting step", currentStepNum);
|
||||
currentStep = STEPS[currentStepNum];
|
||||
startedLastStepAt = Date.now();
|
||||
currentStep.start(this.onFinish);
|
||||
return true;
|
||||
}
|
||||
|
@ -1102,6 +1057,21 @@ TutorialManager = function() {
|
|||
currentStepNum = -1;
|
||||
currentStep = null;
|
||||
}
|
||||
|
||||
this.trackStep = function(name, stepNum) {
|
||||
var timeToFinishStep = (Date.now() - startedLastStepAt) / 1000;
|
||||
var tutorialTimeElapsed = (Date.now() - startedTutorialAt) / 1000;
|
||||
UserActivityLogger.tutorialProgress(
|
||||
name, stepNum, timeToFinishStep, tutorialTimeElapsed,
|
||||
tutorialID, VERSION);
|
||||
}
|
||||
|
||||
// This is a message sent from the "entry" portal in the courtyard,
|
||||
// after the tutorial has finished.
|
||||
this.enteredEntryPortal = function() {
|
||||
info("Got enteredEntryPortal, tracking");
|
||||
this.trackStep("wentToEntry", wentToEntryStepNum);
|
||||
}
|
||||
}
|
||||
|
||||
// To run the tutorial:
|
||||
|
|
|
@ -113,6 +113,14 @@ if (!Function.prototype.bind) {
|
|||
}
|
||||
},
|
||||
|
||||
onEnteredEntryPortal: function() {
|
||||
print("TutorialZone | Got onEnteredEntryPortal");
|
||||
if (this.tutorialManager) {
|
||||
print("TutorialZone | Calling enteredEntryPortal");
|
||||
this.tutorialManager.enteredEntryPortal();
|
||||
}
|
||||
},
|
||||
|
||||
enterEntity: function() {
|
||||
print("TutorialZone | ENTERED THE TUTORIAL AREA");
|
||||
},
|
||||
|
@ -125,7 +133,7 @@ if (!Function.prototype.bind) {
|
|||
}
|
||||
if (this.tutorialManager) {
|
||||
this.tutorialManager.stopTutorial();
|
||||
this.tutorialManager = null;
|
||||
//this.tutorialManager = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue