diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index f2690e0a7d..7bf6f05d9f 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -41,6 +41,9 @@ if (APPLE) elseif (WIN32) set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/quazip5.lib CACHE FILEPATH "Location of QuaZip release library") set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/quazip5d.lib CACHE FILEPATH "Location of QuaZip release library") +elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5d.so CACHE FILEPATH "Location of QuaZip release library") else () set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libquazip5.so CACHE FILEPATH "Location of QuaZip release library") diff --git a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml index b1b6de4644..aadd7c88ae 100644 --- a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml @@ -254,7 +254,7 @@ ModalWindow { text: root.warning; wrapMode: Text.WordWrap; font.italic: true; - maximumLineCount: 2; + maximumLineCount: 3; } HiFiGlyphs { diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 008ed5b860..0c86b93c4b 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -254,7 +254,7 @@ ModalWindow { text: root.warning; wrapMode: Text.WordWrap; font.italic: true; - maximumLineCount: 2; + maximumLineCount: 3; } HiFiGlyphs { diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index 623388e9b3..81a2c5c1e0 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -282,7 +282,7 @@ TabletModalWindow { text: root.warning; wrapMode: Text.WordWrap; font.italic: true; - maximumLineCount: 2; + maximumLineCount: 3; } HiFiGlyphs { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 08e3e7a552..6b48f8d51d 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -124,6 +124,14 @@ Rectangle { root.numUpdatesAvailable = result.data.updates.length; } } + + onAppInstalled: { + root.installedApps = Commerce.getInstalledApps(); + } + + onAppUninstalled: { + root.installedApps = Commerce.getInstalledApps(); + } } Timer { @@ -249,6 +257,145 @@ Rectangle { Commerce.getWalletStatus(); } } + + Item { + id: installedAppsContainer; + z: 998; + visible: false; + anchors.top: titleBarContainer.bottom; + anchors.topMargin: -titleBarContainer.additionalDropdownHeight; + anchors.left: parent.left; + anchors.bottom: parent.bottom; + width: parent.width; + + RalewayRegular { + id: installedAppsHeader; + anchors.top: parent.top; + anchors.topMargin: 10; + anchors.left: parent.left; + anchors.leftMargin: 12; + height: 80; + width: paintedWidth; + text: "All Installed Marketplace Apps"; + color: hifi.colors.black; + size: 22; + } + + ListView { + id: installedAppsList; + clip: true; + model: installedAppsModel; + snapMode: ListView.SnapToItem; + // Anchors + anchors.top: installedAppsHeader.bottom; + anchors.left: parent.left; + anchors.bottom: sideloadAppButton.top; + width: parent.width; + delegate: Item { + width: parent.width; + height: 40; + + RalewayRegular { + text: model.appUrl; + // Text size + size: 16; + // Anchors + anchors.left: parent.left; + anchors.leftMargin: 12; + height: parent.height; + anchors.right: sideloadAppOpenButton.left; + anchors.rightMargin: 8; + elide: Text.ElideRight; + // Style + color: hifi.colors.black; + // Alignment + verticalAlignment: Text.AlignVCenter; + + MouseArea { + anchors.fill: parent; + onClicked: { + Window.copyToClipboard((model.appUrl).slice(0, -9)); + } + } + } + + HifiControlsUit.Button { + id: sideloadAppOpenButton; + text: "OPEN"; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; + anchors.top: parent.top; + anchors.topMargin: 2; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 2; + anchors.right: uninstallGlyph.left; + anchors.rightMargin: 8; + width: 80; + onClicked: { + Commerce.openApp(model.appUrl); + } + } + + HiFiGlyphs { + id: uninstallGlyph; + text: hifi.glyphs.close; + color: hifi.colors.black; + size: 22; + anchors.top: parent.top; + anchors.right: parent.right; + anchors.rightMargin: 6; + width: 35; + height: parent.height; + horizontalAlignment: Text.AlignHCenter; + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + onEntered: { + parent.text = hifi.glyphs.closeInverted; + } + onExited: { + parent.text = hifi.glyphs.close; + } + onClicked: { + Commerce.uninstallApp(model.appUrl); + } + } + } + } + } + HifiControlsUit.Button { + id: sideloadAppButton; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 8; + anchors.left: parent.left; + anchors.leftMargin: 8; + anchors.right: closeAppListButton.left; + anchors.rightMargin: 8; + height: 40; + text: "SIDELOAD APP FROM LOCAL DISK"; + onClicked: { + Window.browseChanged.connect(onFileOpenChanged); + Window.browseAsync("Locate your app's .app.json file", "", "*.app.json"); + } + } + HifiControlsUit.Button { + id: closeAppListButton; + color: hifi.buttons.white; + colorScheme: hifi.colorSchemes.dark; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 8; + anchors.right: parent.right; + anchors.rightMargin: 8; + width: 100; + height: 40; + text: "BACK"; + onClicked: { + installedAppsContainer.visible = false; + } + } + } HifiWallet.NeedsLogIn { id: needsLogIn; @@ -317,7 +464,7 @@ Rectangle { // Item { id: purchasesContentsContainer; - visible: root.activeView === "purchasesMain"; + visible: root.activeView === "purchasesMain" && !installedAppsList.visible; // Anchors anchors.left: parent.left; anchors.right: parent.right; @@ -959,6 +1106,39 @@ Rectangle { } } + Keys.onPressed: { + if ((event.key == Qt.Key_F) && (event.modifiers & Qt.ControlModifier)) { + installedAppsContainer.visible = !installedAppsContainer.visible; + console.log("User changed visibility of installedAppsContainer to " + installedAppsContainer.visible); + } + } + function onFileOpenChanged(filename) { + // disconnect the event, otherwise the requests will stack up + try { // Not all calls to onFileOpenChanged() connect an event. + Window.browseChanged.disconnect(onFileOpenChanged); + } catch (e) { + console.log('Purchases.qml ignoring', e); + } + if (filename) { + Commerce.installApp(filename); + } + } + ListModel { + id: installedAppsModel; + } + onInstalledAppsChanged: { + installedAppsModel.clear(); + var installedAppsArray = root.installedApps.split(","); + var installedAppsObject = []; + // "- 1" because the last app string ends with "," + for (var i = 0; i < installedAppsArray.length - 1; i++) { + installedAppsObject[i] = { + "appUrl": installedAppsArray[i] + } + } + installedAppsModel.append(installedAppsObject); + } + // // Function Name: fromScript() // diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d801c9cb05..cd4562da54 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1070,6 +1070,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (steamClient) { qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID(); } + setCrashAnnotation("steam", property(hifi::properties::STEAM).toBool() ? "1" : "0"); + qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; qCDebug(interfaceapp) << "[VERSION] VERSION:" << BuildInfo::VERSION; @@ -1155,6 +1157,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); + connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){ + setCrashAnnotation("domain", domainURL.toString().toStdString()); + }); connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); @@ -1200,6 +1205,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto dialogsManager = DependencyManager::get(); connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); + connect(accountManager.data(), &AccountManager::usernameChanged, [](QString username){ + setCrashAnnotation("username", username.toStdString()); + }); // set the account manager's root URL and trigger a login request if we don't have the access token accountManager->setIsAgent(true); @@ -1217,6 +1225,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); connect(this, &Application::activeDisplayPluginChanged, this, [](){ qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); + auto displayPlugin = qApp->getActiveDisplayPlugin(); + setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); + setCrashAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0"); }); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); @@ -1224,6 +1235,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(myAvatar.get(), &MyAvatar::positionGoneTo, DependencyManager::get().data(), &AddressManager::storeCurrentAddress); + connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){ + QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL(); + setCrashAnnotation("avatar", avatarURL.toString().toStdString()); + }); + + // Inititalize sample before registering _sampleSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); @@ -1388,6 +1405,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo userActivityLogger.disable(false); } + QString machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + if (userActivityLogger.isEnabled()) { // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. @@ -1437,11 +1456,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo properties["first_run"] = firstRun.get(); // add the user's machine ID to the launch event - properties["machine_fingerprint"] = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + properties["machine_fingerprint"] = machineFingerPrint; userActivityLogger.logAction("launch", properties); } + setCrashAnnotation("machine_fingerprint", machineFingerPrint.toStdString()); + _entityEditSender.setMyAvatar(myAvatar.get()); // The entity octree will have to know about MyAvatar for the parentJointName import diff --git a/interface/src/Crashpad.cpp b/interface/src/Crashpad.cpp index ae2f341337..e39cd42d81 100644 --- a/interface/src/Crashpad.cpp +++ b/interface/src/Crashpad.cpp @@ -15,6 +15,8 @@ #if HAS_CRASHPAD +#include + #include #include @@ -23,8 +25,8 @@ #include #include #include -// #include -// #include +#include +#include using namespace crashpad; @@ -35,7 +37,8 @@ static std::wstring gIPCPipe; extern QString qAppFileName(); -// crashpad::AnnotationList* crashpadAnnotations { nullptr }; +std::mutex annotationMutex; +crashpad::SimpleStringDictionary* crashpadAnnotations { nullptr }; #include @@ -102,12 +105,14 @@ bool startCrashHandler() { } void setCrashAnnotation(std::string name, std::string value) { - // if (!crashpadAnnotations) { - // crashpadAnnotations = new crashpad::AnnotationList(); // don't free this, let it leak - // crashpad::CrashpadInfo* crashpad_info = crashpad::GetCrashpadInfo(); - // crashpad_info->set_simple_annotations(crashpadAnnotations); - // } - // crashpadAnnotations->SetKeyValue(name, value); + std::lock_guard guard(annotationMutex); + if (!crashpadAnnotations) { + crashpadAnnotations = new crashpad::SimpleStringDictionary(); // don't free this, let it leak + crashpad::CrashpadInfo* crashpad_info = crashpad::CrashpadInfo::GetCrashpadInfo(); + crashpad_info->set_simple_annotations(crashpadAnnotations); + } + std::replace(value.begin(), value.end(), ',', ';'); + crashpadAnnotations->SetKeyValue(name, value); } #else diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 33cfc481d7..b3c059de7f 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -20,6 +20,7 @@ #include #include +#include "Crashpad.h" #include "DiscoverabilityManager.h" #include "Menu.h" @@ -127,10 +128,12 @@ void DiscoverabilityManager::updateLocation() { QNetworkAccessManager::PutOperation, callbackParameters); } - // Update Steam + // Update Steam and crash logger + QUrl currentAddress = addressManager->currentFacingPublicAddress(); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { - steamClient->updateLocation(domainHandler.getHostname(), addressManager->currentFacingPublicAddress()); + steamClient->updateLocation(domainHandler.getHostname(), currentAddress); } + setCrashAnnotation("address", currentAddress.toString().toStdString()); } void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 889fff3153..8f88da63a8 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -9,14 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/**jsdoc - * The LODManager API manages your Level of Detail functions within interface. - * @namespace LODManager - * - * @hifi-interface - * @hifi-client-entity - */ - #ifndef hifi_LODManager_h #define hifi_LODManager_h @@ -42,10 +34,36 @@ const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.04f; class AABox; +/**jsdoc + * The LOD class manages your Level of Detail functions within Interface. + * @namespace LODManager + * + * @hifi-interface + * @hifi-client-entity + * + * @property {number} presentTime Read-only. + * @property {number} engineRunTime Read-only. + * @property {number} gpuTime Read-only. + * @property {number} avgRenderTime Read-only. + * @property {number} fps Read-only. + * @property {number} lodLevel Read-only. + * @property {number} lodDecreaseFPS Read-only. + * @property {number} lodIncreaseFPS Read-only. + */ + class LODManager : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY + Q_PROPERTY(float presentTime READ getPresentTime) + Q_PROPERTY(float engineRunTime READ getEngineRunTime) + Q_PROPERTY(float gpuTime READ getGPUTime) + Q_PROPERTY(float avgRenderTime READ getAverageRenderTime) + Q_PROPERTY(float fps READ getMaxTheoreticalFPS) + Q_PROPERTY(float lodLevel READ getLODLevel) + Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) + Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS) + public: /**jsdoc @@ -141,28 +159,6 @@ public: */ Q_INVOKABLE float getLODIncreaseFPS() const; - /**jsdoc - * @namespace LODManager - * @property {number} presentTime Read-only. - * @property {number} engineRunTime Read-only. - * @property {number} gpuTime Read-only. - * @property {number} avgRenderTime Read-only. - * @property {number} fps Read-only. - * @property {number} lodLevel Read-only. - * @property {number} lodDecreaseFPS Read-only. - * @property {number} lodIncreaseFPS Read-only. - */ - - Q_PROPERTY(float presentTime READ getPresentTime) - Q_PROPERTY(float engineRunTime READ getEngineRunTime) - Q_PROPERTY(float gpuTime READ getGPUTime) - Q_PROPERTY(float avgRenderTime READ getAverageRenderTime) - Q_PROPERTY(float fps READ getMaxTheoreticalFPS) - Q_PROPERTY(float lodLevel READ getLODLevel) - - Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) - Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS) - float getPresentTime() const { return _presentTime; } float getEngineRunTime() const { return _engineRunTime; } float getGPUTime() const { return _gpuTime; } diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 3e0e4adf18..35e6ca1c92 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -615,9 +615,15 @@ void Wallet::updateImageProvider() { securityImageProvider->setSecurityImage(_securityImage); // inform tablet security image provider - QQmlEngine* tabletEngine = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")->getTabletSurface()->getSurfaceContext()->engine(); - securityImageProvider = reinterpret_cast(tabletEngine->imageProvider(SecurityImageProvider::PROVIDER_NAME)); - securityImageProvider->setSecurityImage(_securityImage); + TabletProxy* tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); + if (tablet) { + OffscreenQmlSurface* tabletSurface = tablet->getTabletSurface(); + if (tabletSurface) { + QQmlEngine* tabletEngine = tabletSurface->getSurfaceContext()->engine(); + securityImageProvider = reinterpret_cast(tabletEngine->imageProvider(SecurityImageProvider::PROVIDER_NAME)); + securityImageProvider->setSecurityImage(_securityImage); + } + } } void Wallet::chooseSecurityImage(const QString& filename) { diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 42bb648abf..e16383e234 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -28,7 +28,7 @@ class ScriptEngine; /**jsdoc * The Controller API provides facilities to interact with computer and controller hardware. * - *
Functions:
+ *
Functions
* *

Properties

*
    @@ -143,6 +143,61 @@ class ScriptEngine; *
  • {@link Controller.stopInputPlayback|stopInputPlayback}
  • *
* + *
Entity Methods:
+ * + *

The default scripts implement hand controller actions that use {@link Entities.callEntityMethod} to call entity script + * methods, if present in the entity being interacted with.

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Method NameDescriptionExample
startFarTrigger
continueFarTrigger
stopFarTrigger
These methods are called when a user is more than 0.3m away from the entity, the entity is triggerable, and the + * user starts, continues, or stops squeezing the trigger.A light switch that can be toggled on and off from a distance.
startNearTrigger
continueNearTrigger
stopNearTrigger
These methods are called when a user is less than 0.3m away from the entity, the entity is triggerable, and the + * user starts, continues, or stops squeezing the trigger.A doorbell that can be rung when a user is near.
startDistanceGrab
continueDistanceGrab
These methods are called when a user is more than 0.3m away from the entity, the entity is either cloneable, or + * grabbable and not locked, and the user starts or continues to squeeze the trigger.A comet that emits icy particle trails when a user is dragging it through the sky.
startNearGrab
continueNearGrab
These methods are called when a user is less than 0.3m away from the entity, the entity is either cloneable, or + * grabbable and not locked, and the user starts or continues to squeeze the trigger.A ball that glows when it's being held close.
releaseGrabThis method is called when a user releases the trigger when having been either distance or near grabbing an + * entity.Turn off the ball glow or comet trail with the user finishes grabbing it.
startEquip
continueEquip
releaseEquip
These methods are called when a user starts, continues, or stops equipping an entity.A glass that stays in the user's hand after the trigger is clicked.
+ *

All the entity methods are called with the following two arguments:

+ *
    + *
  • The entity ID.
  • + *
  • A string, "hand,userID" — where "hand" is "left" or "right", and "userID" + * is the user's {@link MyAvatar|MyAvatar.sessionUUID}.
  • + *
+ * * @namespace Controller * * @hifi-interface diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 79004a72a6..9777e9c6af 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -588,6 +588,7 @@ void AnimExpression::evalUnaryMinus(const AnimVariantMap& map, std::stack #include #include diff --git a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h index 4521c89afd..5bc7357dd7 100644 --- a/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/MappingBuilderProxy.h @@ -39,7 +39,9 @@ class UserInputMapper; * methods. *
  • Use {@link Controller.parseMapping} or {@link Controller.loadMapping} to load a {@link Controller.MappingJSON}.
  • * - *

    Enable the mapping using {@link MappingObject#enable|enable} or {@link Controller.enableMapping} for it to take effect. + * + *

    Enable the mapping using {@link MappingObject#enable|enable} or {@link Controller.enableMapping} for it to take + * effect.

    * *

    Mappings and their routes are applied according to the following rules:

    *
      diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index 3204e0502f..804709ebfa 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -29,7 +29,8 @@ class ScriptingInterface; *

      A route in a {@link MappingObject} used by the {@link Controller} API.

      * *

      Create a route using {@link MappingObject} methods and apply this object's methods to process it, terminating with - * {@link RouteObject#to} to apply it to a Standard control, action, or script function.

      + * {@link RouteObject#to} to apply it to a Standard control, action, or script function. Note: Loops are not + * permitted.

      * *

      Some methods apply to routes with number data, some apply routes with {@link Pose} data, and some apply to both route * types.

      diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 2491d4bbbd..8adb5138f2 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -396,17 +396,18 @@ public slots: /**jsdoc * Find all entities of a particular name that intersect a sphere defined by a center point and radius. * @function Entities.findEntitiesByName - * @param {Entities.EntityType} entityName - The name of the entity to search for. + * @param {string} entityName - The name of the entity to search for. * @param {Vec3} center - The point about which to search. * @param {number} radius - The radius within which to search. - * @param {boolean} caseSensitiveSearch - Choose whether to to return case sensitive results back. - * @returns {Uuid[]} An array of entity IDs of the specified type that intersect the search sphere. The array is empty if - * no entities could be found. - * @example Get back a list of entities + * @param {boolean} [caseSensitive=false] - If true then the search is case-sensitive. + * @returns {Uuid[]} An array of entity IDs that have the specified name and intersect the search sphere. The array is empty + * if no entities could be found. + * @example Report the number of entities with the name, "Light-Target". * var entityIDs = Entities.findEntitiesByName("Light-Target", MyAvatar.position, 10, false); - * print("Number of Entities with the name Light-Target " + entityIDs.length); + * print("Number of entities with the name "Light-Target": " + entityIDs.length); */ - Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, bool caseSensitiveSearch = false ) const; + Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, + bool caseSensitiveSearch = false ) const; /**jsdoc * Find the first entity intersected by a {@link PickRay}. Light and Zone entities are not diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 9a96364de2..055d94c3b3 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -333,12 +333,14 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) { return false; } +static const QString LOCALHOST = "localhost"; + bool isPossiblePlaceName(QString possiblePlaceName) { bool result { false }; int length = possiblePlaceName.length(); static const int MINIMUM_PLACENAME_LENGTH = 1; static const int MAXIMUM_PLACENAME_LENGTH = 64; - if (possiblePlaceName.toLower() != "localhost" && + if (possiblePlaceName.toLower() != LOCALHOST && length >= MINIMUM_PLACENAME_LENGTH && length <= MAXIMUM_PLACENAME_LENGTH) { const QRegExp PLACE_NAME_REGEX = QRegExp("^[0-9A-Za-z](([0-9A-Za-z]|-(?!-))*[^\\W_]$|$)"); result = PLACE_NAME_REGEX.indexIn(possiblePlaceName) == 0; @@ -358,7 +360,7 @@ void AddressManager::handleLookupString(const QString& lookupString, bool fromSu sanitizedString = sanitizedString.remove(HIFI_SCHEME_REGEX); lookupURL = QUrl(sanitizedString); - if (lookupURL.scheme().isEmpty()) { + if (lookupURL.scheme().isEmpty() || lookupURL.scheme().toLower() == LOCALHOST) { lookupURL = QUrl("hifi://" + sanitizedString); } } else { @@ -607,7 +609,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTri if (ipAddressRegex.indexIn(lookupString) != -1) { QString domainIPString = ipAddressRegex.cap(1); - quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT; + quint16 domainPort = 0; if (!ipAddressRegex.cap(2).isEmpty()) { domainPort = (quint16) ipAddressRegex.cap(2).toInt(); } @@ -629,7 +631,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString, LookupTri if (hostnameRegex.indexIn(lookupString) != -1) { QString domainHostname = hostnameRegex.cap(1); - quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT; + quint16 domainPort = 0; if (!hostnameRegex.cap(2).isEmpty()) { domainPort = (quint16)hostnameRegex.cap(2).toInt(); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index cd8064c4c0..871dc26899 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -166,7 +166,12 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) { } } - if (_domainURL != domainURL || _sockAddr.getPort() != domainURL.port()) { + auto domainPort = domainURL.port(); + if (domainPort == -1) { + domainPort = DEFAULT_DOMAIN_SERVER_PORT; + } + + if (_domainURL != domainURL || _sockAddr.getPort() != domainPort) { // re-set the domain info so that auth information is reloaded hardReset(); @@ -192,12 +197,10 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) { emit domainURLChanged(_domainURL); - if (_sockAddr.getPort() != domainURL.port()) { - qCDebug(networking) << "Updated domain port to" << domainURL.port(); + if (_sockAddr.getPort() != domainPort) { + qCDebug(networking) << "Updated domain port to" << domainPort; + _sockAddr.setPort(domainPort); } - - // grab the port by reading the string after the colon - _sockAddr.setPort(domainURL.port()); } } diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index ab7c2ec252..3ea3616b15 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -153,6 +153,8 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { // remove the objects (aka MotionStates) from physics _physicsEngine->removeSetOfObjects(_physicalObjects); + clearOwnershipData(); + // delete the MotionStates for (auto stateItr : _physicalObjects) { EntityMotionState* motionState = static_cast(&(*stateItr)); @@ -165,7 +167,6 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { _physicalObjects.clear(); // clear all other lists specific to this derived class - clearOwnershipData(); _entitiesToRemoveFromPhysics.clear(); _entitiesToAddToPhysics.clear(); _incomingChanges.clear(); diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 90424b04b2..7086b65f4c 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -16,6 +16,7 @@ #include "AbstractViewStateInterface.h" #include "RenderUtilsLogging.h" #include "DebugDraw.h" +#include "StencilMaskPass.h" #include "animdebugdraw_vert.h" #include "animdebugdraw_frag.h" @@ -70,7 +71,7 @@ public: typedef render::Payload AnimDebugDrawPayload; namespace render { - template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::opaqueShape() : ItemKey::Builder::opaqueShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); } + template <> const ItemKey payloadGetKey(const AnimDebugDrawData::Pointer& data) { return (data->_isVisible ? ItemKey::Builder::transparentShape() : ItemKey::Builder::transparentShape().withInvisible()).withTagBits(ItemKey::TAG_BITS_ALL); } template <> const Item::Bound payloadGetBound(const AnimDebugDrawData::Pointer& data) { return data->_bound; } template <> void payloadRender(const AnimDebugDrawData::Pointer& data, RenderArgs* args) { data->render(args); @@ -104,6 +105,7 @@ AnimDebugDraw::AnimDebugDraw() : state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + PrepareStencil::testMaskDrawShape(*state.get()); auto vertShader = animdebugdraw_vert::getShader(); auto fragShader = animdebugdraw_frag::getShader(); auto program = gpu::Shader::createProgram(vertShader, fragShader); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index c79ffffec7..f0a13cc62b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -2161,6 +2161,32 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& }, forceRedownload); } +/**jsdoc + * Triggered when the script starts for a user. + *

      Note: Can only be connected to via this.preload = function (...) { ... } in the entity script.

      + *
      Available in:Client Entity ScriptsServer Entity Scripts
      + * @function Entities.preload + * @param {Uuid} entityID - The ID of the entity that the script is running in. + * @returns {Signal} + * @example Get the ID of the entity that a client entity script is running in. + * var entityScript = (function () { + * this.entityID = Uuid.NULL; + * + * this.preload = function (entityID) { + * this.entityID = entityID; + * print("Entity ID: " + this.entityID); + * }; + * ); + * + * var entityID = Entities.addEntity({ + * type: "Box", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.5, y: 0.5, z: 0.5 }, + * color: { red: 255, green: 0, blue: 0 }, + * script: "(" + entityScript + ")", // Could host the script on a Web server instead. + * lifetime: 300 // Delete after 5 minutes. + * }); + */ // since all of these operations can be asynch we will always do the actual work in the response handler // for the download void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success , const QString& status) { @@ -2345,6 +2371,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co processDeferredEntityLoads(entityScript, entityID); } +/**jsdoc + * Triggered when the script terminates for a user. + *

      Note: Can only be connected to via this.unoad = function () { ... } in the entity script.

      + *
      Available in:Client Entity ScriptsServer Entity Scripts
      + * @function Entities.unload + * @returns {Signal} + */ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index b1ceab4149..c7ad4a790d 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -213,7 +213,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio int byteForSection = (BITS_IN_OCTAL * section / BITS_IN_BYTE); unsigned char* byteAt = octalCode + 1 + byteForSection; char bitInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; - char shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL; + int8_t shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL; const unsigned char UNSHIFTED_MASK = 0x07; unsigned char shiftedMask; unsigned char shiftedValue; diff --git a/scripts/system/particle_explorer/particleExplorer.js b/scripts/system/particle_explorer/particleExplorer.js index 3598f30ee0..099c4be9e3 100644 --- a/scripts/system/particle_explorer/particleExplorer.js +++ b/scripts/system/particle_explorer/particleExplorer.js @@ -321,7 +321,8 @@ { id: "alpha", name: "Alpha", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" @@ -329,7 +330,8 @@ { id: "alphaSpread", name: "Alpha Spread", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" @@ -337,7 +339,8 @@ { id: "alphaStart", name: "Alpha Start", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" @@ -345,7 +348,8 @@ { id: "alphaFinish", name: "Alpha Finish", - type: "SliderFloat" + type: "SliderFloat", + max: 1.0 }, { type: "Row" diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt index b5e866ccce..ce1c150ed4 100644 --- a/tests/controllers/CMakeLists.txt +++ b/tests/controllers/CMakeLists.txt @@ -23,5 +23,9 @@ if (WIN32) add_dependency_external_projects(wasapi) endif() +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + target_link_libraries(${TARGET_NAME} atomic) +endif() + package_libraries_for_deployment() -endif() \ No newline at end of file +endif() diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index fd4d8d88dd..d688474379 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -27,6 +27,10 @@ if (WIN32) add_dependency_external_projects(wasapi) endif() +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + target_link_libraries(${TARGET_NAME} atomic) +endif() + package_libraries_for_deployment()