mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 13:33:38 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into hdr
This commit is contained in:
commit
eea5118eab
14 changed files with 196 additions and 101 deletions
|
@ -1278,6 +1278,13 @@ void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) {
|
|||
}
|
||||
|
||||
void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
||||
if (_sendICEServerAddressToMetaverseAPIInProgress) {
|
||||
// don't have more than one of these in-flight at a time. set a flag to indicate that once the current one
|
||||
// is done, we need to do update metaverse again.
|
||||
_sendICEServerAddressToMetaverseAPIRedo = true;
|
||||
return;
|
||||
}
|
||||
_sendICEServerAddressToMetaverseAPIInProgress = true;
|
||||
const QString ICE_SERVER_ADDRESS = "ice_server_address";
|
||||
|
||||
QJsonObject domainObject;
|
||||
|
@ -1302,6 +1309,8 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
|||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.errorCallbackReceiver = this;
|
||||
callbackParameters.errorCallbackMethod = "handleFailedICEServerAddressUpdate";
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
callbackParameters.jsonCallbackMethod = "handleSuccessfulICEServerAddressUpdate";
|
||||
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Updating ice-server address in High Fidelity Metaverse API to [^ \n]+");
|
||||
|
@ -1317,13 +1326,32 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
|
|||
domainUpdateJSON.toUtf8());
|
||||
}
|
||||
|
||||
void DomainServer::handleSuccessfulICEServerAddressUpdate(QNetworkReply& requestReply) {
|
||||
_sendICEServerAddressToMetaverseAPIInProgress = false;
|
||||
if (_sendICEServerAddressToMetaverseAPIRedo) {
|
||||
qDebug() << "ice-server address updated with metaverse, but has since changed. redoing update...";
|
||||
_sendICEServerAddressToMetaverseAPIRedo = false;
|
||||
sendICEServerAddressToMetaverseAPI();
|
||||
} else {
|
||||
qDebug() << "ice-server address updated with metaverse.";
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply& requestReply) {
|
||||
const int ICE_SERVER_UPDATE_RETRY_MS = 2 * 1000;
|
||||
_sendICEServerAddressToMetaverseAPIInProgress = false;
|
||||
if (_sendICEServerAddressToMetaverseAPIRedo) {
|
||||
// if we have new data, retry right away, even though the previous attempt didn't go well.
|
||||
_sendICEServerAddressToMetaverseAPIRedo = false;
|
||||
sendICEServerAddressToMetaverseAPI();
|
||||
} else {
|
||||
const int ICE_SERVER_UPDATE_RETRY_MS = 2 * 1000;
|
||||
|
||||
qWarning() << "Failed to update ice-server address with High Fidelity Metaverse - error was" << requestReply.errorString();
|
||||
qWarning() << "\tRe-attempting in" << ICE_SERVER_UPDATE_RETRY_MS / 1000 << "seconds";
|
||||
qWarning() << "Failed to update ice-server address with High Fidelity Metaverse - error was"
|
||||
<< requestReply.errorString();
|
||||
qWarning() << "\tRe-attempting in" << ICE_SERVER_UPDATE_RETRY_MS / 1000 << "seconds";
|
||||
|
||||
QTimer::singleShot(ICE_SERVER_UPDATE_RETRY_MS, this, SLOT(sendICEServerAddressToMetaverseAPI()));
|
||||
QTimer::singleShot(ICE_SERVER_UPDATE_RETRY_MS, this, SLOT(sendICEServerAddressToMetaverseAPI()));
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::sendHeartbeatToIceServer() {
|
||||
|
|
|
@ -96,6 +96,7 @@ private slots:
|
|||
void handleICEHostInfo(const QHostInfo& hostInfo);
|
||||
|
||||
void sendICEServerAddressToMetaverseAPI();
|
||||
void handleSuccessfulICEServerAddressUpdate(QNetworkReply& requestReply);
|
||||
void handleFailedICEServerAddressUpdate(QNetworkReply& requestReply);
|
||||
|
||||
signals:
|
||||
|
@ -211,6 +212,9 @@ private:
|
|||
int _iceServerPort;
|
||||
bool _overrideDomainID { false }; // should we override the domain-id from settings?
|
||||
QUuid _overridingDomainID { QUuid() }; // what should we override it with?
|
||||
|
||||
bool _sendICEServerAddressToMetaverseAPIInProgress { false };
|
||||
bool _sendICEServerAddressToMetaverseAPIRedo { false };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,28 +1,49 @@
|
|||
{
|
||||
"name": "XBox to Standard",
|
||||
"channels": [
|
||||
{ "from": "GamePad.LY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.LY" },
|
||||
{ "from": "GamePad.LX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.LX" },
|
||||
{ "from": "GamePad.LY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateZ" },
|
||||
{ "from": "GamePad.LX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateX" },
|
||||
{ "from": "GamePad.LT", "to": "Standard.LT" },
|
||||
{ "from": "GamePad.LB", "to": "Standard.LB" },
|
||||
{ "from": "GamePad.LS", "to": "Standard.LS" },
|
||||
|
||||
{ "from": "GamePad.RY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.RY" },
|
||||
{ "from": "GamePad.RX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Standard.RX" },
|
||||
|
||||
{ "from": "GamePad.RX",
|
||||
"when": [ "Application.InHMD", "Application.SnapTurn" ],
|
||||
"to": "Actions.StepYaw",
|
||||
"filters":
|
||||
[
|
||||
{ "type": "deadZone", "min": 0.15 },
|
||||
"constrainToInteger",
|
||||
{ "type": "pulse", "interval": 0.25 },
|
||||
{ "type": "scale", "scale": 22.5 }
|
||||
]
|
||||
},
|
||||
|
||||
{ "from": "GamePad.RX", "to": "Actions.Yaw" },
|
||||
|
||||
{ "from": "GamePad.RY",
|
||||
"to": "Actions.VERTICAL_UP",
|
||||
"filters":
|
||||
[
|
||||
{ "type": "deadZone", "min": 0.95 },
|
||||
"invert"
|
||||
]
|
||||
},
|
||||
|
||||
{ "from": "GamePad.RT", "to": "Standard.RT" },
|
||||
{ "from": "GamePad.RB", "to": "Standard.RB" },
|
||||
{ "from": "GamePad.RS", "to": "Standard.RS" },
|
||||
|
||||
{ "from": "GamePad.Back", "to": "Standard.Back" },
|
||||
{ "from": "GamePad.Start", "to": "Standard.Start" },
|
||||
{ "from": "GamePad.Start", "to": "Actions.CycleCamera" },
|
||||
{ "from": "GamePad.Back", "to": "Actions.ContextMenu" },
|
||||
|
||||
{ "from": [ "GamePad.DU", "GamePad.DL", "GamePad.DR", "GamePad.DD" ], "to": "Standard.LeftPrimaryThumb", "peek": true },
|
||||
{ "from": "GamePad.DU", "to": "Standard.DU" },
|
||||
{ "from": "GamePad.DD", "to": "Standard.DD" },
|
||||
{ "from": "GamePad.DL", "to": "Standard.DL" },
|
||||
{ "from": "GamePad.DR", "to": "Standard.DR" },
|
||||
|
||||
{ "from": [ "GamePad.A", "GamePad.B", "GamePad.X", "GamePad.Y" ], "to": "Standard.RightPrimaryThumb", "peek": true },
|
||||
{ "from": [ "GamePad.Y" ], "to": "Standard.RightPrimaryThumb", "peek": true },
|
||||
{ "from": "GamePad.A", "to": "Standard.A" },
|
||||
{ "from": "GamePad.B", "to": "Standard.B" },
|
||||
{ "from": "GamePad.X", "to": "Standard.X" },
|
||||
|
|
|
@ -4625,11 +4625,15 @@ void Application::resetSensors(bool andReload) {
|
|||
|
||||
void Application::updateWindowTitle() const {
|
||||
|
||||
QString buildVersion = " (build " + applicationVersion() + ")";
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
|
||||
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
|
||||
QString buildVersion = " (build " + applicationVersion() + ")";
|
||||
|
||||
QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)";
|
||||
|
||||
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED)";
|
||||
QString username = accountManager->getAccountInfo().getUsername();
|
||||
QString currentPlaceName = DependencyManager::get<AddressManager>()->getHost();
|
||||
|
||||
if (currentPlaceName.isEmpty()) {
|
||||
|
@ -4637,7 +4641,7 @@ void Application::updateWindowTitle() const {
|
|||
}
|
||||
|
||||
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
|
||||
+ currentPlaceName + connectionStatus + buildVersion;
|
||||
+ currentPlaceName + connectionStatus + loginStatus + buildVersion;
|
||||
|
||||
#ifndef WIN32
|
||||
// crashes with vs2013/win32
|
||||
|
|
|
@ -867,6 +867,10 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
|||
|
||||
void AudioClient::handleAudioInput() {
|
||||
|
||||
if (!_inputDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
// input samples required to produce exactly NETWORK_FRAME_SAMPLES of output
|
||||
const int inputSamplesRequired = (_inputToNetworkResampler ?
|
||||
_inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) :
|
||||
|
|
|
@ -192,6 +192,11 @@ void GLBackend::resetResourceStage() {
|
|||
|
||||
void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
if (slot >= (GLuint) MAX_NUM_RESOURCE_TEXTURES) {
|
||||
// "GLBackend::do_setResourceTexture: Trying to set a resource Texture at slot #" + slot + " which doesn't exist. MaxNumResourceTextures = " + getMaxNumResourceTextures());
|
||||
return;
|
||||
}
|
||||
|
||||
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (!resourceTexture) {
|
||||
|
|
|
@ -11,10 +11,20 @@
|
|||
|
||||
#include "AssetResourceRequest.h"
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include "AssetClient.h"
|
||||
#include "AssetUtils.h"
|
||||
#include "MappingRequest.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include "NetworkLogging.h"
|
||||
|
||||
static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5;
|
||||
|
||||
AssetResourceRequest::AssetResourceRequest(const QUrl& url) :
|
||||
ResourceRequest(url)
|
||||
{
|
||||
_lastProgressDebug = p_high_resolution_clock::now() - std::chrono::seconds(DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS);
|
||||
}
|
||||
|
||||
AssetResourceRequest::~AssetResourceRequest() {
|
||||
if (_assetMappingRequest) {
|
||||
|
@ -24,10 +34,6 @@ AssetResourceRequest::~AssetResourceRequest() {
|
|||
if (_assetRequest) {
|
||||
_assetRequest->deleteLater();
|
||||
}
|
||||
|
||||
if (_sendTimer) {
|
||||
cleanupTimer();
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetResourceRequest::urlIsAssetHash() const {
|
||||
|
@ -37,24 +43,6 @@ bool AssetResourceRequest::urlIsAssetHash() const {
|
|||
return hashRegex.exactMatch(_url.toString());
|
||||
}
|
||||
|
||||
void AssetResourceRequest::setupTimer() {
|
||||
Q_ASSERT(!_sendTimer);
|
||||
static const int TIMEOUT_MS = 2000;
|
||||
|
||||
_sendTimer = new QTimer(this);
|
||||
connect(_sendTimer, &QTimer::timeout, this, &AssetResourceRequest::onTimeout);
|
||||
|
||||
_sendTimer->setSingleShot(true);
|
||||
_sendTimer->start(TIMEOUT_MS);
|
||||
}
|
||||
|
||||
void AssetResourceRequest::cleanupTimer() {
|
||||
Q_ASSERT(_sendTimer);
|
||||
disconnect(_sendTimer, 0, this, 0);
|
||||
_sendTimer->deleteLater();
|
||||
_sendTimer = nullptr;
|
||||
}
|
||||
|
||||
void AssetResourceRequest::doSend() {
|
||||
// We'll either have a hash or an ATP path to a file (that maps to a hash)
|
||||
if (urlIsAssetHash()) {
|
||||
|
@ -81,8 +69,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
|
|||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(request == _assetMappingRequest);
|
||||
|
||||
cleanupTimer();
|
||||
|
||||
switch (request->getError()) {
|
||||
case MappingRequest::NoError:
|
||||
// we have no error, we should have a resulting hash - use that to send of a request for that asset
|
||||
|
@ -118,7 +104,6 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
|
|||
_assetMappingRequest = nullptr;
|
||||
});
|
||||
|
||||
setupTimer();
|
||||
_assetMappingRequest->start();
|
||||
}
|
||||
|
||||
|
@ -133,8 +118,6 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) {
|
|||
Q_ASSERT(_state == InProgress);
|
||||
Q_ASSERT(req == _assetRequest);
|
||||
Q_ASSERT(req->getState() == AssetRequest::Finished);
|
||||
|
||||
cleanupTimer();
|
||||
|
||||
switch (req->getError()) {
|
||||
case AssetRequest::Error::NoError:
|
||||
|
@ -162,35 +145,29 @@ void AssetResourceRequest::requestHash(const AssetHash& hash) {
|
|||
_assetRequest = nullptr;
|
||||
});
|
||||
|
||||
setupTimer();
|
||||
_assetRequest->start();
|
||||
}
|
||||
|
||||
void AssetResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
||||
Q_ASSERT(_state == InProgress);
|
||||
|
||||
// We've received data, so reset the timer
|
||||
_sendTimer->start();
|
||||
|
||||
emit progress(bytesReceived, bytesTotal);
|
||||
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
// if we haven't received the full asset check if it is time to output progress to log
|
||||
// we do so every X seconds to assist with ATP download tracking
|
||||
|
||||
if (bytesReceived != bytesTotal
|
||||
&& now - _lastProgressDebug > std::chrono::seconds(DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS)) {
|
||||
|
||||
int percentage = roundf((float) bytesReceived / (float) bytesTotal * 100.0f);
|
||||
|
||||
qCDebug(networking).nospace() << "Progress for " << _url.path() << " - "
|
||||
<< bytesReceived << " of " << bytesTotal << " bytes - " << percentage << "%";
|
||||
|
||||
_lastProgressDebug = now;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AssetResourceRequest::onTimeout() {
|
||||
if (_state == InProgress) {
|
||||
qWarning() << "Asset request timed out: " << _url;
|
||||
if (_assetRequest) {
|
||||
disconnect(_assetRequest, 0, this, 0);
|
||||
_assetRequest->deleteLater();
|
||||
_assetRequest = nullptr;
|
||||
}
|
||||
if (_assetMappingRequest) {
|
||||
disconnect(_assetMappingRequest, 0, this, 0);
|
||||
_assetMappingRequest->deleteLater();
|
||||
_assetMappingRequest = nullptr;
|
||||
}
|
||||
_result = Timeout;
|
||||
_state = Finished;
|
||||
emit finished();
|
||||
}
|
||||
cleanupTimer();
|
||||
}
|
||||
|
|
|
@ -14,13 +14,15 @@
|
|||
|
||||
#include <QUrl>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include "AssetRequest.h"
|
||||
#include "ResourceRequest.h"
|
||||
|
||||
class AssetResourceRequest : public ResourceRequest {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssetResourceRequest(const QUrl& url) : ResourceRequest(url) { }
|
||||
AssetResourceRequest(const QUrl& url);
|
||||
virtual ~AssetResourceRequest() override;
|
||||
|
||||
protected:
|
||||
|
@ -28,21 +30,17 @@ protected:
|
|||
|
||||
private slots:
|
||||
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||
void onTimeout();
|
||||
|
||||
private:
|
||||
void setupTimer();
|
||||
void cleanupTimer();
|
||||
|
||||
bool urlIsAssetHash() const;
|
||||
|
||||
void requestMappingForPath(const AssetPath& path);
|
||||
void requestHash(const AssetHash& hash);
|
||||
|
||||
QTimer* _sendTimer { nullptr };
|
||||
|
||||
GetMappingRequest* _assetMappingRequest { nullptr };
|
||||
AssetRequest* _assetRequest { nullptr };
|
||||
|
||||
p_high_resolution_clock::time_point _lastProgressDebug;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,7 +54,7 @@ void ReceivedMessage::appendPacket(NLPacket& packet) {
|
|||
"We should not be appending to a complete message");
|
||||
|
||||
// Limit progress signal to every X packets
|
||||
const int EMIT_PROGRESS_EVERY_X_PACKETS = 100;
|
||||
const int EMIT_PROGRESS_EVERY_X_PACKETS = 50;
|
||||
|
||||
++_numPackets;
|
||||
|
||||
|
|
|
@ -633,6 +633,8 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
|
|||
// Setup the global directional pass pipeline
|
||||
{
|
||||
if (deferredLightingEffect->_shadowMapEnabled) {
|
||||
// If the keylight has an ambient Map then use the Skybox version of the pass
|
||||
// otherwise use the ambient sphere version
|
||||
if (keyLight->getAmbientMap()) {
|
||||
program = deferredLightingEffect->_directionalSkyboxLightShadow;
|
||||
locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations;
|
||||
|
@ -641,11 +643,11 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
|
|||
locations = deferredLightingEffect->_directionalAmbientSphereLightShadowLocations;
|
||||
}
|
||||
} else {
|
||||
// If the keylight has an ambient Map then use the Skybox version of the pass
|
||||
// otherwise use the ambient sphere version
|
||||
if (keyLight->getAmbientMap()) {
|
||||
program = deferredLightingEffect->_directionalAmbientSphereLight;
|
||||
locations = deferredLightingEffect->_directionalAmbientSphereLightLocations;
|
||||
//program = deferredLightingEffect->_directionalSkyboxLight;
|
||||
//locations = deferredLightingEffect->_directionalSkyboxLightLocations;
|
||||
program = deferredLightingEffect->_directionalSkyboxLight;
|
||||
locations = deferredLightingEffect->_directionalSkyboxLightLocations;
|
||||
} else {
|
||||
program = deferredLightingEffect->_directionalAmbientSphereLight;
|
||||
locations = deferredLightingEffect->_directionalAmbientSphereLightLocations;
|
||||
|
|
|
@ -63,7 +63,6 @@ void OculusBaseDisplayPlugin::customizeContext() {
|
|||
|
||||
void OculusBaseDisplayPlugin::uncustomizeContext() {
|
||||
Parent::uncustomizeContext();
|
||||
internalPresent();
|
||||
}
|
||||
|
||||
bool OculusBaseDisplayPlugin::internalActivate() {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||
|
||||
print('crowd-agent version 1');
|
||||
print('crowd-agent version 2');
|
||||
|
||||
/* Observations:
|
||||
- File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development.
|
||||
|
@ -24,9 +24,26 @@ print('crowd-agent version 1');
|
|||
- JSON.stringify(Avatar) silently fails (even when Agent.isAvatar)
|
||||
*/
|
||||
|
||||
function messageSend(message) {
|
||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||
}
|
||||
|
||||
function getSound(data, callback) { // callback(sound) when downloaded (which may be immediate).
|
||||
var sound = SoundCache.getSound(data.url);
|
||||
if (sound.downloaded) {
|
||||
return callback(sound);
|
||||
}
|
||||
sound.ready.connect(function () { callback(sound); });
|
||||
}
|
||||
function onFinishedPlaying() {
|
||||
messageSend({key: 'finishedSound'});
|
||||
}
|
||||
|
||||
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));
|
||||
Agent.isAvatar = true;
|
||||
Agent.isListeningToAudioStream = true; // Send silence when not chattering.
|
||||
if (parameters.position) {
|
||||
Avatar.position = parameters.position;
|
||||
}
|
||||
|
@ -36,6 +53,12 @@ function startAgent(parameters) { // Can also be used to update.
|
|||
if (parameters.skeletonModelURL) {
|
||||
Avatar.skeletonModelURL = parameters.skeletonModelURL;
|
||||
}
|
||||
if (parameters.soundData) {
|
||||
getSound(parameters.soundData, function (sound) {
|
||||
Script.setTimeout(onFinishedPlaying, sound.duration * MILLISECONDS_IN_SECOND);
|
||||
Agent.playAvatarSound(sound);
|
||||
});
|
||||
}
|
||||
if (parameters.animationData) {
|
||||
data = parameters.animationData;
|
||||
Avatar.startAnimation(data.url, data.fps || 30, 1.0, (data.loopFlag === undefined) ? true : data.loopFlag, false, data.startFrame || 0, data.endFrame);
|
||||
|
@ -47,9 +70,6 @@ function stopAgent(parameters) {
|
|||
print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent));
|
||||
}
|
||||
|
||||
function messageSend(message) {
|
||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||
}
|
||||
function messageHandler(channel, messageString, senderID) {
|
||||
if (channel !== MESSAGE_CHANNEL) {
|
||||
return;
|
||||
|
|
|
@ -18,15 +18,25 @@ var label = "summon";
|
|||
function debug() {
|
||||
print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify)));
|
||||
}
|
||||
var MINIMUM_AVATARS = 25;
|
||||
var MINIMUM_AVATARS = 25; // We will summon agents to produce this many total. (Of course, there might not be enough agents.)
|
||||
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 NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next
|
||||
|
||||
var spread = Math.sqrt(MINIMUM_AVATARS * DENSITY); // meters
|
||||
var turnSpread = 90; // How many degrees should turn from front range over.
|
||||
|
||||
function coord() { return (Math.random() * spread) - (spread / 2); } // randomly distribute a coordinate zero += spread/2.
|
||||
|
||||
function contains(array, item) { return array.indexOf(item) >= 0; }
|
||||
function without(array, itemsToRemove) { return array.filter(function (item) { return !contains(itemsToRemove, item); }); }
|
||||
function nextAfter(array, id) { // Wrapping next element in array after id.
|
||||
var index = array.indexOf(id) + 1;
|
||||
return array[(index >= array.length) ? 0 : index];
|
||||
}
|
||||
|
||||
var summonedAgents = [];
|
||||
var chattering = [];
|
||||
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
|
||||
function messageSend(message) {
|
||||
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
|
||||
|
@ -48,15 +58,20 @@ 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 = AvatarList.getAvatarIdentifiers().filter(function (id) { return summonedAgents.indexOf(id) === -1; });
|
||||
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)/*,
|
||||
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
|
||||
soundData: chatter && SOUND_DATA/*
|
||||
// No need to specify skeletonModelURL
|
||||
//skeletonModelURL: "file:///c:/Program Files/High Fidelity Release/resources/meshes/being_of_light/being_of_light.fbx",
|
||||
//skeletonModelURL: "file:///c:/Program Files/High Fidelity Release/resources/meshes/defaultAvatar_full.fst"/,
|
||||
|
@ -71,6 +86,16 @@ function messageHandler(channel, messageString, senderID) {
|
|||
});
|
||||
}
|
||||
break;
|
||||
case "finishedSound": // Give someone else a chance.
|
||||
chattering = without(chattering, [senderID]);
|
||||
Script.setTimeout(function () {
|
||||
messageSend({
|
||||
key: 'SUMMON',
|
||||
rcpt: nextAfter(without(summonedAgents, chattering), senderID),
|
||||
soundData: SOUND_DATA
|
||||
});
|
||||
}, Math.random() * NEXT_SOUND_SPREAD);
|
||||
break;
|
||||
case "HELO":
|
||||
Window.alert("Someone else is summoning avatars.");
|
||||
break;
|
||||
|
@ -93,11 +118,12 @@ Script.scriptEnding.connect(function () {
|
|||
|
||||
messageSend({key: 'HELO'}); // Ask agents to report in now.
|
||||
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\
|
||||
on your domain server.");
|
||||
} else if (summonedAgents.length < MINIMUM_AVATARS) {
|
||||
Window.alert("Only " + summonedAgents.length + " of the expected " + MINIMUM_AVATARS + " agents reported in.");
|
||||
} else if (total < MINIMUM_AVATARS) {
|
||||
Window.alert("Only " + summonedAgents.length + " of the expected " + (MINIMUM_AVATARS - total) + " agents reported in.");
|
||||
}
|
||||
}, 5000);
|
||||
|
|
|
@ -469,7 +469,7 @@ var usersWindow = (function () {
|
|||
|
||||
Overlays.editOverlay(minimizeButton, {
|
||||
x: windowLeft + WINDOW_WIDTH - WINDOW_MARGIN / 2 - MIN_MAX_BUTTON_WIDTH,
|
||||
y: windowTop + WINDOW_MARGIN / 2
|
||||
y: windowTop + WINDOW_MARGIN
|
||||
});
|
||||
|
||||
scrollbarBackgroundPosition.x = windowLeft + WINDOW_WIDTH - 0.5 * WINDOW_MARGIN - SCROLLBAR_BACKGROUND_WIDTH;
|
||||
|
@ -559,34 +559,34 @@ var usersWindow = (function () {
|
|||
});
|
||||
|
||||
Overlays.editOverlay(windowHeading, {
|
||||
text: linesOfUsers.length > 0 ? "Users online" : "No users online"
|
||||
text: isLoggedIn ? (linesOfUsers.length > 0 ? "Users online" : "No users online") : "Users online - log in to view"
|
||||
});
|
||||
}
|
||||
|
||||
function updateOverlayVisibility() {
|
||||
Overlays.editOverlay(windowBorder, {
|
||||
visible: isLoggedIn && isVisible && isBorderVisible
|
||||
visible: isVisible && isBorderVisible
|
||||
});
|
||||
Overlays.editOverlay(windowPane, {
|
||||
visible: isLoggedIn && isVisible
|
||||
visible: isVisible
|
||||
});
|
||||
Overlays.editOverlay(windowHeading, {
|
||||
visible: isLoggedIn && isVisible
|
||||
visible: isVisible
|
||||
});
|
||||
Overlays.editOverlay(minimizeButton, {
|
||||
visible: isLoggedIn && isVisible
|
||||
});
|
||||
Overlays.editOverlay(scrollbarBackground, {
|
||||
visible: isLoggedIn && isVisible && isUsingScrollbars && !isMinimized
|
||||
visible: isVisible && isUsingScrollbars && !isMinimized
|
||||
});
|
||||
Overlays.editOverlay(scrollbarBar, {
|
||||
visible: isLoggedIn && isVisible && isUsingScrollbars && !isMinimized
|
||||
visible: isVisible && isUsingScrollbars && !isMinimized
|
||||
});
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
visible: isLoggedIn && isVisible && !isMinimized
|
||||
visible: isVisible && !isMinimized
|
||||
});
|
||||
displayControl.setVisible(isLoggedIn && isVisible && !isMinimized);
|
||||
visibilityControl.setVisible(isLoggedIn && isVisible && !isMinimized);
|
||||
displayControl.setVisible(isVisible && !isMinimized);
|
||||
visibilityControl.setVisible(isVisible && !isMinimized);
|
||||
}
|
||||
|
||||
function checkLoggedIn() {
|
||||
|
@ -594,6 +594,13 @@ var usersWindow = (function () {
|
|||
|
||||
isLoggedIn = Account.isLoggedIn();
|
||||
if (isLoggedIn !== wasLoggedIn) {
|
||||
if (wasLoggedIn) {
|
||||
setMinimized(true);
|
||||
calculateWindowHeight();
|
||||
updateOverlayPositions();
|
||||
updateUsersDisplay();
|
||||
}
|
||||
|
||||
updateOverlayVisibility();
|
||||
}
|
||||
}
|
||||
|
@ -1021,7 +1028,7 @@ var usersWindow = (function () {
|
|||
color: WINDOW_HEADING_COLOR,
|
||||
alpha: WINDOW_HEADING_ALPHA,
|
||||
backgroundAlpha: 0.0,
|
||||
text: "No users online",
|
||||
text: "Users online",
|
||||
font: WINDOW_FONT,
|
||||
visible: false
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue