mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 16:41:02 +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(); }
|
qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); }
|
||||||
|
|
||||||
bool isAboutToQuit() const { return _aboutToQuit; }
|
bool isAboutToQuit() const override { return _aboutToQuit; }
|
||||||
bool isPhysicsEnabled() const { return _physicsEnabled; }
|
bool isPhysicsEnabled() const { return _physicsEnabled; }
|
||||||
|
|
||||||
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
|
// 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) {
|
auto deleter = [](OffscreenQmlSurface* webSurface) {
|
||||||
AbstractViewStateInterface::instance()->postLambdaEvent([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);
|
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
||||||
|
@ -333,6 +339,7 @@ void RenderableWebEntityItem::destroyWebSurface() {
|
||||||
if (rootItem) {
|
if (rootItem) {
|
||||||
QObject* obj = rootItem->findChild<QObject*>("webEngineView");
|
QObject* obj = rootItem->findChild<QObject*>("webEngineView");
|
||||||
if (obj) {
|
if (obj) {
|
||||||
|
// stop loading
|
||||||
QMetaObject::invokeMethod(obj, "stop");
|
QMetaObject::invokeMethod(obj, "stop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,11 @@ void UserActivityLoggerScriptingInterface::toggledAway(bool isAway) {
|
||||||
logAction("toggled_away", { { "is_away", 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", {
|
logAction("tutorial_progress", {
|
||||||
|
{ "tutorial_run_id", tutorialRunID },
|
||||||
|
{ "tutorial_version", tutorialVersion },
|
||||||
{ "step", stepName },
|
{ "step", stepName },
|
||||||
{ "step_number", stepNumber },
|
{ "step_number", stepNumber },
|
||||||
{ "seconds_to_complete", secondsToComplete },
|
{ "seconds_to_complete", secondsToComplete },
|
||||||
|
|
|
@ -23,7 +23,8 @@ public:
|
||||||
Q_INVOKABLE void enabledEdit();
|
Q_INVOKABLE void enabledEdit();
|
||||||
Q_INVOKABLE void openedMarketplace();
|
Q_INVOKABLE void openedMarketplace();
|
||||||
Q_INVOKABLE void toggledAway(bool isAway);
|
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:
|
private:
|
||||||
void logAction(QString action, QJsonObject details = {});
|
void logAction(QString action, QJsonObject details = {});
|
||||||
|
|
|
@ -49,7 +49,7 @@ Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) :
|
||||||
connect(&_udpSocket, &QAbstractSocket::stateChanged, this, &Socket::handleStateChanged);
|
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
|
// 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);
|
connect(_readyReadBackupTimer, &QTimer::timeout, this, &Socket::checkForReadyReadBackup);
|
||||||
_readyReadBackupTimer->start(READY_READ_BACKUP_CHECK_MSECS);
|
_readyReadBackupTimer->start(READY_READ_BACKUP_CHECK_MSECS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,9 @@ public:
|
||||||
|
|
||||||
virtual glm::vec3 getAvatarPosition() const = 0;
|
virtual glm::vec3 getAvatarPosition() const = 0;
|
||||||
|
|
||||||
|
virtual bool isAboutToQuit() const = 0;
|
||||||
virtual void postLambdaEvent(std::function<void()> f) = 0;
|
virtual void postLambdaEvent(std::function<void()> f) = 0;
|
||||||
|
|
||||||
virtual qreal getDevicePixelRatio() = 0;
|
virtual qreal getDevicePixelRatio() = 0;
|
||||||
|
|
||||||
virtual render::ScenePointer getMain3DScene() = 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
|
// If BatchLoader is deleted before the callback is called, the subsequent "emit" call will not do
|
||||||
// anything.
|
// anything.
|
||||||
ScriptCacheSignalProxy* proxy = new ScriptCacheSignalProxy(scriptCache.data());
|
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) {
|
connect(proxy, &ScriptCacheSignalProxy::contentAvailable, this, [this](const QString& url, const QString& contents, bool isURL, bool success) {
|
||||||
if (isURL && success) {
|
if (isURL && success) {
|
||||||
|
@ -75,6 +71,11 @@ void BatchLoader::start() {
|
||||||
emit finished(_data);
|
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 void requestGarbageCollection() { collectGarbage(); }
|
||||||
|
|
||||||
|
Q_INVOKABLE QUuid generateUUID() { return QUuid::createUuid(); }
|
||||||
|
|
||||||
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
||||||
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||||
|
|
||||||
print('crowd-agent version 3');
|
print('crowd-agent version 4');
|
||||||
|
|
||||||
/* Observations:
|
/* Observations:
|
||||||
- File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development.
|
- 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) {
|
if (sound.downloaded) {
|
||||||
return callback(sound);
|
return callback(sound);
|
||||||
}
|
}
|
||||||
sound.ready.connect(function () { callback(sound); });
|
function onDownloaded() {
|
||||||
|
sound.ready.disconnect(onDownloaded);
|
||||||
|
callback(sound);
|
||||||
|
}
|
||||||
|
sound.ready.connect(onDownloaded);
|
||||||
}
|
}
|
||||||
function onFinishedPlaying() {
|
function onFinishedPlaying() {
|
||||||
messageSend({key: 'finishedSound'});
|
messageSend({key: 'finishedSound'});
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachment;
|
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;
|
var MILLISECONDS_IN_SECOND = 1000;
|
||||||
function startAgent(parameters) { // Can also be used to update.
|
function startAgent(parameters) { // Can also be used to update.
|
||||||
print('crowd-agent starting params', JSON.stringify(parameters), JSON.stringify(Agent));
|
print('crowd-agent starting params', JSON.stringify(parameters), JSON.stringify(Agent));
|
||||||
|
clearStopper();
|
||||||
|
var wasOff = !Agent.isAvatar;
|
||||||
Agent.isAvatar = true;
|
Agent.isAvatar = true;
|
||||||
Agent.isListeningToAudioStream = true; // Send silence when not chattering.
|
|
||||||
if (parameters.position) {
|
if (parameters.position) {
|
||||||
Avatar.position = parameters.position;
|
Avatar.position = parameters.position;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +93,11 @@ function startAgent(parameters) { // Can also be used to update.
|
||||||
if (parameters.skeletonModelURL) {
|
if (parameters.skeletonModelURL) {
|
||||||
Avatar.skeletonModelURL = 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) {
|
if (parameters.soundData) {
|
||||||
getSound(parameters.soundData, function (sound) {
|
getSound(parameters.soundData, function (sound) {
|
||||||
Script.setTimeout(onFinishedPlaying, sound.duration * MILLISECONDS_IN_SECOND);
|
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');
|
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) {
|
function messageHandler(channel, messageString, senderID) {
|
||||||
if (channel !== MESSAGE_CHANNEL) {
|
if (channel !== MESSAGE_CHANNEL) {
|
||||||
|
|
|
@ -21,6 +21,10 @@ var NOMINAL_LOAD_TIME = 30; // seconds
|
||||||
var MAXIMUM_LOAD_TIME = NOMINAL_LOAD_TIME * 2;
|
var MAXIMUM_LOAD_TIME = NOMINAL_LOAD_TIME * 2;
|
||||||
var MINIMUM_AVATARS = 25; // changeable by prompt
|
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 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 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.
|
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
|
"loopFlag": true
|
||||||
};
|
};
|
||||||
|
|
||||||
var version = 3;
|
var version = 4;
|
||||||
function debug() {
|
function debug() {
|
||||||
print.apply(null, [].concat.apply(['hrs fixme', version], [].map.call(arguments, JSON.stringify)));
|
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 summonedAgents = [];
|
||||||
var chattering = [];
|
var chattering = [];
|
||||||
|
var accumulatedDelay = 0;
|
||||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||||
function messageSend(message) {
|
function messageSend(message) {
|
||||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||||
|
@ -106,25 +111,29 @@ function messageHandler(channel, messageString, senderID) {
|
||||||
}
|
}
|
||||||
switch (message.key) {
|
switch (message.key) {
|
||||||
case "hello":
|
case "hello":
|
||||||
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
Script.setTimeout(function () {
|
||||||
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
||||||
debug('present', avatarIdentifiers, summonedAgents);
|
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
||||||
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS) {
|
debug('present', avatarIdentifiers, summonedAgents);
|
||||||
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS) {
|
||||||
if (chatter) {
|
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
||||||
chattering.push(senderID);
|
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);
|
}, accumulatedDelay);
|
||||||
messageSend({
|
accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together.
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "finishedSound": // Give someone else a chance.
|
case "finishedSound": // Give someone else a chance.
|
||||||
chattering = without(chattering, [senderID]);
|
chattering = without(chattering, [senderID]);
|
||||||
|
@ -147,13 +156,15 @@ Messages.subscribe(MESSAGE_CHANNEL);
|
||||||
Messages.messageReceived.connect(messageHandler);
|
Messages.messageReceived.connect(messageHandler);
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
debug('stopping agents', summonedAgents);
|
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');
|
debug('agents stopped');
|
||||||
Script.setTimeout(function () {
|
Messages.unsubscribe(MESSAGE_CHANNEL);
|
||||||
Messages.messageReceived.disconnect(messageHandler);
|
debug('unsubscribed');
|
||||||
Messages.unsubscribe(MESSAGE_CHANNEL);
|
|
||||||
debug('unsubscribed');
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var fail = false, results = "";
|
var fail = false, results = "";
|
||||||
|
@ -257,7 +268,7 @@ function doRender(continuation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config.newStats.connect(onNewStats);
|
config.newStats.connect(onNewStats);
|
||||||
startTwirl(720, 1, 15, 0.08, function () {
|
startTwirl(720, 1, 20, 0.08, function () {
|
||||||
var end = Date.now();
|
var end = Date.now();
|
||||||
config.newStats.disconnect(onNewStats);
|
config.newStats.disconnect(onNewStats);
|
||||||
addResult('frame rate', 1000 * frames / (end - start),
|
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\
|
http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=3\n\
|
||||||
on your domain server.";
|
on your domain server.";
|
||||||
} else if (total < MINIMUM_AVATARS) {
|
} 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();
|
continuation();
|
||||||
|
|
|
@ -13,19 +13,26 @@
|
||||||
//
|
//
|
||||||
// See crowd-agent.js
|
// See crowd-agent.js
|
||||||
|
|
||||||
var version = 1;
|
var version = 2;
|
||||||
var label = "summon";
|
var label = "summon";
|
||||||
function debug() {
|
function debug() {
|
||||||
print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify)));
|
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 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 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 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.
|
|
||||||
var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next
|
var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next
|
||||||
var ANIMATION_DATA = {
|
var ANIMATION_DATA = {
|
||||||
"url": "http://howard-stearns.github.io/models/resources/avatar/animations/idle.fbx",
|
"url": "http://hifi-content.s3.amazonaws.com/howard/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/walk_fwd.fbx", // alternative example
|
||||||
"startFrame": 0.0,
|
"startFrame": 0.0,
|
||||||
"endFrame": 300.0,
|
"endFrame": 300.0,
|
||||||
"timeScale": 1.0,
|
"timeScale": 1.0,
|
||||||
|
@ -45,6 +52,8 @@ function nextAfter(array, id) { // Wrapping next element in array after id.
|
||||||
|
|
||||||
var summonedAgents = [];
|
var summonedAgents = [];
|
||||||
var chattering = [];
|
var chattering = [];
|
||||||
|
var nListening = 0;
|
||||||
|
var accumulatedDelay = 0;
|
||||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||||
function messageSend(message) {
|
function messageSend(message) {
|
||||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||||
|
@ -65,25 +74,33 @@ function messageHandler(channel, messageString, senderID) {
|
||||||
}
|
}
|
||||||
switch (message.key) {
|
switch (message.key) {
|
||||||
case "hello":
|
case "hello":
|
||||||
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
Script.setTimeout(function () {
|
||||||
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
// There can be avatars we've summoned that do not yet appear in the AvatarList.
|
||||||
debug('present', avatarIdentifiers, summonedAgents);
|
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
|
||||||
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS ) {
|
debug('present', avatarIdentifiers, summonedAgents);
|
||||||
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS ) {
|
||||||
if (chatter) {
|
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
|
||||||
chattering.push(senderID);
|
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);
|
}, accumulatedDelay);
|
||||||
messageSend({
|
accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together.
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "finishedSound": // Give someone else a chance.
|
case "finishedSound": // Give someone else a chance.
|
||||||
chattering = without(chattering, [senderID]);
|
chattering = without(chattering, [senderID]);
|
||||||
|
@ -99,20 +116,22 @@ function messageHandler(channel, messageString, senderID) {
|
||||||
Window.alert("Someone else is summoning avatars.");
|
Window.alert("Someone else is summoning avatars.");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print("crowd-agent received unrecognized message:", messageString);
|
print("crowd summon.js received unrecognized message:", messageString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Messages.subscribe(MESSAGE_CHANNEL);
|
Messages.subscribe(MESSAGE_CHANNEL);
|
||||||
Messages.messageReceived.connect(messageHandler);
|
Messages.messageReceived.connect(messageHandler);
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
debug('stopping agents', summonedAgents);
|
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');
|
debug('agents stopped');
|
||||||
Script.setTimeout(function () {
|
Messages.unsubscribe(MESSAGE_CHANNEL);
|
||||||
Messages.messageReceived.disconnect(messageHandler);
|
debug('unsubscribed');
|
||||||
Messages.unsubscribe(MESSAGE_CHANNEL);
|
|
||||||
debug('unsubscribed');
|
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
messageSend({key: 'HELO'}); // Ask agents to report in now.
|
messageSend({key: 'HELO'}); // Ask agents to report in now.
|
||||||
|
@ -120,9 +139,9 @@ Script.setTimeout(function () {
|
||||||
var total = AvatarList.getAvatarIdentifiers().length;
|
var total = AvatarList.getAvatarIdentifiers().length;
|
||||||
if (0 === summonedAgents.length) {
|
if (0 === summonedAgents.length) {
|
||||||
Window.alert("No agents reported.\n\Please run " + MINIMUM_AVATARS + " instances of\n\
|
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.");
|
on your domain server.");
|
||||||
} else if (total < MINIMUM_AVATARS) {
|
} 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_HEIGHT = 3, // Display height of SVG
|
||||||
BAR_DESKTOP_2K_URL = Script.resolvePath("assets/images/progress-bar-2k.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_REPEAT = 640, // Length of repeat in bar = 2240 / 7.
|
||||||
BAR_DESKTOP_4K_HEIGHT = 6, // Display height of SVG
|
BAR_DESKTOP_4K_HEIGHT = 6, // Display height of SVG
|
||||||
BAR_DESKTOP_4K_URL = Script.resolvePath("assets/images/progress-bar-4k.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 (homeServer.state == ProcessGroupStates.STOPPED) {
|
||||||
// if the home server is already down, take down the server console now
|
// if the home server is already down, take down the server console now
|
||||||
log.debug("Quitting.");
|
log.debug("Quitting.");
|
||||||
app.quit();
|
app.exit(0);
|
||||||
} else {
|
} else {
|
||||||
// if the home server is still running, wait until we get a state change or timeout
|
// if the home server is still running, wait until we get a state change or timeout
|
||||||
// before quitting the app
|
// before quitting the app
|
||||||
log.debug("Server still shutting down. Waiting");
|
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) {
|
homeServer.on('state-update', function(processGroup) {
|
||||||
if (processGroup.state == ProcessGroupStates.STOPPED) {
|
if (processGroup.state == ProcessGroupStates.STOPPED) {
|
||||||
clearTimeout(timeoutID);
|
clearTimeout(timeoutID);
|
||||||
log.debug("Quitting.");
|
log.debug("Quitting.");
|
||||||
app.quit();
|
app.exit(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -240,7 +242,7 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory)
|
||||||
|
|
||||||
if (shouldQuit) {
|
if (shouldQuit) {
|
||||||
log.warn("Another instance of the Sandbox is already running - this instance will quit.");
|
log.warn("Another instance of the Sandbox is already running - this instance will quit.");
|
||||||
app.quit();
|
app.exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,12 +290,12 @@ function binaryMissingMessage(displayName, executableName, required) {
|
||||||
|
|
||||||
if (!dsPath) {
|
if (!dsPath) {
|
||||||
dialog.showErrorBox("Domain Server Not Found", binaryMissingMessage("domain-server", "domain-server", true));
|
dialog.showErrorBox("Domain Server Not Found", binaryMissingMessage("domain-server", "domain-server", true));
|
||||||
app.quit();
|
app.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!acPath) {
|
if (!acPath) {
|
||||||
dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true));
|
dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true));
|
||||||
app.quit();
|
app.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openFileBrowser(path) {
|
function openFileBrowser(path) {
|
||||||
|
|
|
@ -425,6 +425,7 @@ protected:
|
||||||
return vec3();
|
return vec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isAboutToQuit() const override { return false; }
|
||||||
void postLambdaEvent(std::function<void()> f) override {}
|
void postLambdaEvent(std::function<void()> f) override {}
|
||||||
|
|
||||||
qreal getDevicePixelRatio() 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 startedTutorialAt = 0;
|
||||||
var startedLastStepAt = 0;
|
var startedLastStepAt = 0;
|
||||||
|
|
||||||
|
var wentToEntryStepNum;
|
||||||
|
var VERSION = 1;
|
||||||
|
var tutorialID;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.startTutorial = function() {
|
this.startTutorial = function() {
|
||||||
currentStepNum = -1;
|
currentStepNum = -1;
|
||||||
currentStep = null;
|
currentStep = null;
|
||||||
startedTutorialAt = Date.now();
|
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 = [
|
STEPS = [
|
||||||
new stepStart("start"),
|
new stepStart("start"),
|
||||||
new stepOrient("orient"),
|
new stepOrient("orient"),
|
||||||
//new stepRaiseAboveHead("raiseHands"),
|
|
||||||
new stepNearGrab("nearGrab"),
|
new stepNearGrab("nearGrab"),
|
||||||
new stepFarGrab("farGrab"),
|
new stepFarGrab("farGrab"),
|
||||||
new stepEquip("equip"),
|
new stepEquip("equip"),
|
||||||
|
@ -1045,6 +997,7 @@ TutorialManager = function() {
|
||||||
new stepFinish("finish"),
|
new stepFinish("finish"),
|
||||||
new stepEnableControllers("enableControllers"),
|
new stepEnableControllers("enableControllers"),
|
||||||
];
|
];
|
||||||
|
wentToEntryStepNum = STEPS.length;
|
||||||
for (var i = 0; i < STEPS.length; ++i) {
|
for (var i = 0; i < STEPS.length; ++i) {
|
||||||
STEPS[i].cleanup();
|
STEPS[i].cleanup();
|
||||||
}
|
}
|
||||||
|
@ -1055,10 +1008,7 @@ TutorialManager = function() {
|
||||||
this.onFinish = function() {
|
this.onFinish = function() {
|
||||||
debug("onFinish", currentStepNum);
|
debug("onFinish", currentStepNum);
|
||||||
if (currentStep && currentStep.shouldLog !== false) {
|
if (currentStep && currentStep.shouldLog !== false) {
|
||||||
var timeToFinishStep = (Date.now() - startedLastStepAt) / 1000;
|
self.trackStep(currentStep.tag, currentStepNum);
|
||||||
var tutorialTimeElapsed = (Date.now() - startedTutorialAt) / 1000;
|
|
||||||
UserActivityLogger.tutorialProgress(
|
|
||||||
currentStep.tag, currentStepNum, timeToFinishStep, tutorialTimeElapsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.startNextStep();
|
self.startNextStep();
|
||||||
|
@ -1071,6 +1021,12 @@ TutorialManager = function() {
|
||||||
|
|
||||||
++currentStepNum;
|
++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) {
|
if (currentStepNum >= STEPS.length) {
|
||||||
// Done
|
// Done
|
||||||
info("DONE WITH TUTORIAL");
|
info("DONE WITH TUTORIAL");
|
||||||
|
@ -1080,7 +1036,6 @@ TutorialManager = function() {
|
||||||
} else {
|
} else {
|
||||||
info("Starting step", currentStepNum);
|
info("Starting step", currentStepNum);
|
||||||
currentStep = STEPS[currentStepNum];
|
currentStep = STEPS[currentStepNum];
|
||||||
startedLastStepAt = Date.now();
|
|
||||||
currentStep.start(this.onFinish);
|
currentStep.start(this.onFinish);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1102,6 +1057,21 @@ TutorialManager = function() {
|
||||||
currentStepNum = -1;
|
currentStepNum = -1;
|
||||||
currentStep = null;
|
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:
|
// 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() {
|
enterEntity: function() {
|
||||||
print("TutorialZone | ENTERED THE TUTORIAL AREA");
|
print("TutorialZone | ENTERED THE TUTORIAL AREA");
|
||||||
},
|
},
|
||||||
|
@ -125,7 +133,7 @@ if (!Function.prototype.bind) {
|
||||||
}
|
}
|
||||||
if (this.tutorialManager) {
|
if (this.tutorialManager) {
|
||||||
this.tutorialManager.stopTutorial();
|
this.tutorialManager.stopTutorial();
|
||||||
this.tutorialManager = null;
|
//this.tutorialManager = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue