diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 8ab53d3b87..4ca2439996 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -45,25 +45,67 @@ AssetServer::AssetServer(ReceivedMessage& message) : } void AssetServer::run() { + + qDebug() << "Waiting for connection to domain to request settings from domain-server."; + + // wait until we have the domain-server settings, otherwise we bail + DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); + connect(&domainHandler, &DomainHandler::settingsReceived, this, &AssetServer::completeSetup); + connect(&domainHandler, &DomainHandler::settingsReceiveFail, this, &AssetServer::domainSettingsRequestFailed); + ThreadedAssignment::commonInit(ASSET_SERVER_LOGGING_TARGET_NAME, NodeType::AssetServer); +} +void AssetServer::completeSetup() { auto nodeList = DependencyManager::get(); - nodeList->addNodeTypeToInterestSet(NodeType::Agent); - const QString RESOURCES_PATH = "assets"; + auto& domainHandler = nodeList->getDomainHandler(); + const QJsonObject& settingsObject = domainHandler.getSettingsObject(); - _resourcesDirectory = QDir(ServerPathUtils::getDataDirectory()).filePath(RESOURCES_PATH); + static const QString ASSET_SERVER_SETTINGS_KEY = "asset_server"; + + if (!settingsObject.contains(ASSET_SERVER_SETTINGS_KEY)) { + qCritical() << "Received settings from the domain-server with no asset-server section. Stopping assignment."; + setFinished(true); + return; + } + + auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY].toObject(); + + // get the path to the asset folder from the domain server settings + static const QString ASSETS_PATH_OPTION = "assets_path"; + auto assetsJSONValue = assetServerObject[ASSETS_PATH_OPTION]; + + if (!assetsJSONValue.isString()) { + qCritical() << "Received an assets path from the domain-server that could not be parsed. Stopping assignment."; + setFinished(true); + return; + } + + auto assetsPathString = assetsJSONValue.toString(); + QDir assetsPath { assetsPathString }; + QString absoluteFilePath = assetsPath.absolutePath(); + + if (assetsPath.isRelative()) { + // if the domain settings passed us a relative path, make an absolute path that is relative to the + // default data directory + absoluteFilePath = ServerPathUtils::getDataFilePath("assets/" + assetsPathString); + } + + _resourcesDirectory = QDir(absoluteFilePath); qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); - bool noExistingAssets = !_resourcesDirectory.exists() \ - || _resourcesDirectory.entryList(QDir::Files).size() == 0; + bool noExistingAssets = !_resourcesDirectory.exists() || _resourcesDirectory.entryList(QDir::Files).size() == 0; if (noExistingAssets) { - qDebug() << "Asset resources directory not found, searching for existing asset resources"; + qDebug() << "Asset resources directory empty, searching for existing asset resources to migrate"; QString oldDataDirectory = QCoreApplication::applicationDirPath(); - auto oldResourcesDirectory = QDir(oldDataDirectory).filePath("resources/" + RESOURCES_PATH); + + const QString OLD_RESOURCES_PATH = "assets"; + + auto oldResourcesDirectory = QDir(oldDataDirectory).filePath("resources/" + OLD_RESOURCES_PATH); if (QDir(oldResourcesDirectory).exists()) { @@ -111,10 +153,12 @@ void AssetServer::run() { auto hexHash = hash.toHex(); qDebug() << "\tMoving " << filename << " to " << hexHash; - + file.rename(_resourcesDirectory.absoluteFilePath(hexHash) + "." + fileInfo.suffix()); } } + + nodeList->addNodeTypeToInterestSet(NodeType::Agent); } void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index fe83ce92a6..7d6e26af08 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -29,6 +29,8 @@ public slots: void run(); private slots: + void completeSetup(); + void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index fa706eb0f6..38cb8a174f 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -157,12 +157,16 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() { while (it != _audioStreams.end()) { SharedStreamPointer stream = it->second; - static const int INJECTOR_INACTIVITY_USECS = 5 * USECS_PER_SECOND; + if (stream->popFrames(1, true) > 0) { + stream->updateLastPopOutputLoudnessAndTrailingLoudness(); + } - // if we don't have new data for an injected stream in the last INJECTOR_INACTIVITY_MSECS then + static const int INJECTOR_MAX_INACTIVE_BLOCKS = 500; + + // if we don't have new data for an injected stream in the last INJECTOR_MAX_INACTIVE_BLOCKS then // we remove the injector from our streams if (stream->getType() == PositionalAudioStream::Injector - && stream->usecsSinceLastPacket() > INJECTOR_INACTIVITY_USECS) { + && stream->getConsecutiveNotMixedCount() > INJECTOR_MAX_INACTIVE_BLOCKS) { // this is an inactive injector, pull it from our streams // first emit that it is finished so that the HRTF objects for this source can be cleaned up @@ -170,12 +174,7 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() { // erase the stream to drop our ref to the shared pointer and remove it it = _audioStreams.erase(it); - } else { - if (stream->popFrames(1, true) > 0) { - stream->updateLastPopOutputLoudnessAndTrailingLoudness(); - } - ++it; } } diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 891c586a6a..014d9f3767 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -168,7 +168,7 @@ }, { "name": "asset_server", - "label": "Asset Server", + "label": "Asset Server (ATP)", "assignment-types": [3], "settings": [ { @@ -178,6 +178,14 @@ "help": "Assigns an asset-server in your domain to serve files to clients via the ATP protocol (over UDP)", "default": true, "advanced": true + }, + { + "name": "assets_path", + "type": "string", + "label": "Assets Path", + "help": "The path to the directory assets are stored in.
If this path is relative, it will be relative to the application data directory.
If you change this path you will need to manually copy any existing assets from the previous directory.", + "default": "", + "advanced": true } ] }, @@ -377,7 +385,7 @@ { "name": "persistFilePath", "label": "Entities File Path", - "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The filename must end in .json.gz.", + "help": "The path to the file entities are stored in.
If this path is relative it will be relative to the application data directory.
The filename must end in .json.gz.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9e3b69854f..9e13c8e6fa 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -120,6 +120,14 @@ DomainServer::~DomainServer() { DependencyManager::destroy(); } +void DomainServer::queuedQuit(QString quitMessage, int exitCode) { + if (!quitMessage.isEmpty()) { + qCritical() << qPrintable(quitMessage); + } + + QCoreApplication::exit(exitCode); +} + void DomainServer::aboutToQuit() { // clear the log handler so that Qt doesn't call the destructor on LogHandler @@ -164,8 +172,11 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT; } else if (!certPath.isEmpty() || !keyPath.isEmpty()) { - qDebug() << "Missing certificate or private key. domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + static const QString MISSING_CERT_ERROR_MSG = "Missing certificate or private key. domain-server will now quit."; + static const int MISSING_CERT_ERROR_CODE = 3; + + QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_CERT_ERROR_MSG), Q_ARG(int, MISSING_CERT_ERROR_CODE)); return false; } @@ -199,8 +210,10 @@ bool DomainServer::optionallySetupOAuth() { || _hostname.isEmpty() || _oauthClientID.isEmpty() || _oauthClientSecret.isEmpty()) { - qDebug() << "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + static const QString MISSING_OAUTH_INFO_MSG = "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit."; + static const int MISSING_OAUTH_INFO_ERROR_CODE = 4; + QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_OAUTH_INFO_MSG), Q_ARG(int, MISSING_OAUTH_INFO_ERROR_CODE)); return false; } else { qDebug() << "OAuth will be used to identify clients using provider at" << _oauthProviderURL.toString(); @@ -404,9 +417,13 @@ bool DomainServer::resetAccountManagerAccessToken() { return true; } else { - qDebug() << "Missing OAuth provider URL, but a domain-server feature was required that requires authentication." << - "domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + static const QString MISSING_OAUTH_PROVIDER_MSG = + QString("Missing OAuth provider URL, but a domain-server feature was required that requires authentication.") + + QString("domain-server will now quit."); + static const int MISSING_OAUTH_PROVIDER_ERROR_CODE = 5; + QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_OAUTH_PROVIDER_MSG), + Q_ARG(int, MISSING_OAUTH_PROVIDER_ERROR_CODE)); return false; } @@ -517,11 +534,6 @@ void DomainServer::setupICEHeartbeatForFullNetworking() { } } -void DomainServer::loginFailed() { - qDebug() << "Login to data server has failed. domain-server will now quit"; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); -} - void DomainServer::parseAssignmentConfigs(QSet& excludedTypes) { // check for configs from the command line, these take precedence const QString ASSIGNMENT_CONFIG_REGEX_STRING = "config-([\\d]+)"; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index afdd7bd26e..326ca3e1a8 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -65,7 +65,6 @@ public slots: private slots: void aboutToQuit(); - void loginFailed(); void setupPendingAssignmentCredits(); void sendPendingTransactionsToServer(); @@ -77,6 +76,8 @@ private slots: void handleTempDomainSuccess(QNetworkReply& requestReply); void handleTempDomainError(QNetworkReply& requestReply); + + void queuedQuit(QString quitMessage, int exitCode); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 98bb63241e..49ae03ccd4 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -62,9 +62,14 @@ DomainServerSettingsManager::DomainServerSettingsManager() : } } - qCritical() << "Did not find settings decription in JSON at" << SETTINGS_DESCRIPTION_RELATIVE_PATH - << "- Unable to continue. domain-server will quit."; - QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); + static const QString MISSING_SETTINGS_DESC_MSG = + QString("Did not find settings decription in JSON at %1 - Unable to continue. domain-server will quit.") + .arg(SETTINGS_DESCRIPTION_RELATIVE_PATH); + static const int MISSING_SETTINGS_DESC_ERROR_CODE = 6; + + QMetaObject::invokeMethod(QCoreApplication::instance(), "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_SETTINGS_DESC_MSG), + Q_ARG(int, MISSING_SETTINGS_DESC_ERROR_CODE)); } void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer message) { diff --git a/examples/away.js b/examples/away.js index c37e588734..861c642b8d 100644 --- a/examples/away.js +++ b/examples/away.js @@ -90,6 +90,9 @@ hideOverlay(); // MAIN CONTROL var wasMuted, isAway; +var eventMappingName = "io.highfidelity.away"; // goActive on hand controller button events, too. +var eventMapping = Controller.newMapping(eventMappingName); + function goAway() { if (isAway) { return; @@ -117,8 +120,8 @@ function goActive() { stopAwayAnimation(); hideOverlay(); } -Script.scriptEnding.connect(goActive); -Controller.keyPressEvent.connect(function (event) { + +function maybeGoActive(event) { if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) return; } @@ -127,13 +130,31 @@ Controller.keyPressEvent.connect(function (event) { } else { goActive(); } -}); +} var wasHmdActive = false; -Script.update.connect(function () { +function maybeGoAway() { if (HMD.active !== wasHmdActive) { wasHmdActive = !wasHmdActive; if (wasHmdActive) { goAway(); } } +} + +Script.update.connect(maybeGoAway); +Controller.mousePressEvent.connect(goActive); +Controller.keyPressEvent.connect(maybeGoActive); +// Note peek() so as to not interfere with other mappings. +eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(goActive); +eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(goActive); +eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(goActive); +eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(goActive); +Controller.enableMapping(eventMappingName); + +Script.scriptEnding.connect(function () { + Script.update.disconnect(maybeGoAway); + goActive(); + Controller.disableMapping(eventMappingName); + Controller.mousePressEvent.disconnect(goActive); + Controller.keyPressEvent.disconnect(maybeGoActive); }); diff --git a/examples/controllers/getHUDLookAtPositionTest.js b/examples/controllers/getHUDLookAtPositionTest.js index 348b6757b8..cad9c944bf 100644 --- a/examples/controllers/getHUDLookAtPositionTest.js +++ b/examples/controllers/getHUDLookAtPositionTest.js @@ -19,18 +19,20 @@ var cubeSize = 0.03; var cube = Overlays.addOverlay("cube", { position: cubePosition, size: cubeSize, - color: { red: 255, green: 0, blue: 0}, + color: { red: 0, green: 255, blue: 0}, alpha: 1, solid: false }); -var square = Overlays.addOverlay("text", { +var SQUARE_SIZE = 20; + +var square = Overlays.addOverlay("rectangle", { x: 0, y: 0, - width: 20, - height: 20, - color: { red: 255, green: 255, blue: 0}, - backgroundColor: { red: 255, green: 255, blue: 0}, + width: SQUARE_SIZE, + height: SQUARE_SIZE, + color: { red: 0, green: 255, blue: 0}, + backgroundColor: { red: 0, green: 255, blue: 0}, alpha: 1 }); @@ -43,7 +45,7 @@ Script.update.connect(function(deltaTime) { Overlays.editOverlay(cube, { position: lookAt3D }); var lookAt2D = HMD.getHUDLookAtPosition2D(); - Overlays.editOverlay(square, { x: lookAt2D.x, y: lookAt2D.y }); + Overlays.editOverlay(square, { x: lookAt2D.x - (SQUARE_SIZE/2), y: lookAt2D.y - (SQUARE_SIZE/2)}); }); Script.scriptEnding.connect(function(){ diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 908337f643..92dc86ee02 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -14,6 +14,7 @@ Script.include("../libraries/utils.js"); + // // add lines where the hand ray picking is happening // @@ -722,6 +723,9 @@ function MyController(hand) { this.particleBeamOff(); } this.searchSphereOff(); + + Controller.setReticleVisible(true); + }; this.triggerPress = function(value) { @@ -1018,6 +1022,9 @@ function MyController(hand) { this.overlayLineOn(handPosition, searchSphereLocation, (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } + + Controller.setReticleVisible(false); + }; this.distanceGrabTimescale = function(mass, distance) { @@ -1879,7 +1886,7 @@ function cleanup() { rightController.cleanup(); leftController.cleanup(); Controller.disableMapping(MAPPING_NAME); - + Controller.setReticleVisible(true); } Script.scriptEnding.connect(cleanup); Script.update.connect(update); diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index a303e5e7b4..a27e6f2c4e 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -31,8 +31,8 @@ function moveReticleAbsolute(x, y) { var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); -mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); +mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); +mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); mapping.enable(); diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 71f2450da1..d8e5451ff8 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -308,6 +308,11 @@ allSections.push(elWebSections); var elWebSourceURL = document.getElementById("property-web-source-url"); + + var elHyperlinkHref = document.getElementById("property-hyperlink-href"); + var elHyperlinkDescription = document.getElementById("property-hyperlink-description"); + var elHyperlinkSections = document.querySelectorAll(".hyperlink-section"); + var elParticleSections = document.querySelectorAll(".particle-section"); allSections.push(elParticleSections); var elParticleIsEmitting = document.getElementById("property-particle-is-emitting"); @@ -370,9 +375,6 @@ var elYTextureURL = document.getElementById("property-y-texture-url"); var elZTextureURL = document.getElementById("property-z-texture-url"); - var elHyperlinkHref = document.getElementById("property-hyperlink-href"); - var elHyperlinkDescription = document.getElementById("property-hyperlink-description"); - var elPreviewCameraButton = document.getElementById("preview-camera-button"); if (window.EventBridge !== undefined) { @@ -492,8 +494,12 @@ for (var j = 0; j < allSections[i].length; j++) { allSections[i][j].style.display = 'none'; } + } + + for (var i = 0; i < elHyperlinkSections.length; i++) { + elHyperlinkSections[i].style.display = 'block'; } - + if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "ParticleEffect") { elColorSection.style.display = 'block'; elColorRed.value = properties.color.red; @@ -526,6 +532,9 @@ for (var i = 0; i < elWebSections.length; i++) { elWebSections[i].style.display = 'block'; } + for (var i = 0; i < elHyperlinkSections.length; i++) { + elHyperlinkSections[i].style.display = 'none'; + } elWebSourceURL.value = properties.sourceUrl; } else if (properties.type == "Text") { @@ -1158,17 +1167,17 @@ -
+ -
+ -
+