diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index d24a84c6a5..9930a9e152 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -7,6 +7,8 @@ target_bullet() set(INTERFACE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../interface") add_subdirectory("${INTERFACE_DIR}" "libraries/interface") include_directories("${INTERFACE_DIR}/src") +set(HIFI_CODEC_PLUGIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../plugins/hifiCodec") +add_subdirectory("${HIFI_CODEC_PLUGIN_DIR}" "libraries/hifiCodecPlugin") target_link_libraries(native-lib android log m interface) diff --git a/android/app/build.gradle b/android/app/build.gradle index 24c067b176..76f5acfaea 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -80,8 +80,10 @@ android { if (Os.isFamily(Os.FAMILY_UNIX)) { def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first() def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first() + def renameHifiACTask = rootProject.getTasksByName("renameHifiACTask${variant.name.capitalize()}", false).first() runDumpSymsTask.dependsOn(task) variant.assemble.dependsOn(uploadDumpSymsTask) + variant.mergeResources.dependsOn(renameHifiACTask) } } diff --git a/android/build.gradle b/android/build.gradle index aa7aa399b2..14f9e4803f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -143,11 +143,9 @@ def packages = [ includeLibs: ['libtbb.so', 'libtbbmalloc.so'], ], hifiAC: [ - file: 'libplugins_libhifiCodec.zip', - versionId: 'i31pW.qNbvFOXRxbyiJUxg3sphaFNmZU', - checksum: '9412a8e12c88a4096c1fc843bb9fe52d', - sharedLibFolder: '', - includeLibs: ['libplugins_libhifiCodec.so'] + baseUrl: 'http://s3.amazonaws.com/hifi-public/dependencies/', + file: 'codecSDK-android_armv8-2.0.zip', + checksum: '1cbef929675818fc64c4101b72f84a6a' ], etc2comp: [ file: 'etc2comp-patched-armv8-libcpp.tgz', @@ -367,7 +365,8 @@ task downloadDependencies { doLast { packages.each { entry -> def filename = entry.value['file']; - def url = baseUrl + filename; + def dependencyBaseUrl = entry.value['baseUrl'] + def url = (dependencyBaseUrl?.trim() ? dependencyBaseUrl : baseUrl) + filename; if (entry.value.containsKey('versionId')) { url = url + '?versionId=' + entry.value['versionId'] } @@ -668,6 +667,21 @@ task uploadBreakpadDumpSymsRelease(type:io.github.httpbuilderng.http.HttpTask, d } } +task renameHifiACTaskDebug() { + doLast { + def sourceFile = new File("${appDir}/build/intermediates/cmake/debug/obj/arm64-v8a/","libhifiCodec.so") + def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so") + copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } + } +} +task renameHifiACTaskRelease(type: Copy) { + doLast { + def sourceFile = new File("${appDir}/build/intermediates/cmake/release/obj/arm64-v8a/","libhifiCodec.so") + def destinationFile = new File("${appDir}/src/main/jniLibs/arm64-v8a", "libplugins_libhifiCodec.so") + copy { from sourceFile; into destinationFile.parent; rename(sourceFile.name, destinationFile.name) } + } +} + // FIXME this code is prototyping the desired functionality for doing build time binary dependency resolution. // See the comment on the qtBundle task above /* diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 187c9ed0f2..09bdfbc564 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -112,6 +112,11 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message, AvatarTraits::TraitWireSize traitSize; message.readPrimitive(&traitSize); + if (traitSize < -1 || traitSize > message.getBytesLeftToRead()) { + qWarning() << "Refusing to process simple trait of size" << traitSize << "from" << message.getSenderSockAddr(); + break; + } + if (packetTraitVersion > _lastReceivedTraitVersions[traitType]) { _avatar->processTrait(traitType, message.read(traitSize)); _lastReceivedTraitVersions[traitType] = packetTraitVersion; @@ -128,26 +133,41 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message, } else { AvatarTraits::TraitInstanceID instanceID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + if (message.getBytesLeftToRead() == 0) { + qWarning () << "Received an instanced trait with no size from" << message.getSenderSockAddr(); + break; + } + AvatarTraits::TraitWireSize traitSize; message.readPrimitive(&traitSize); - auto& instanceVersionRef = _lastReceivedTraitVersions.getInstanceValueRef(traitType, instanceID); + if (traitSize < -1 || traitSize > message.getBytesLeftToRead()) { + qWarning() << "Refusing to process instanced trait of size" << traitSize << "from" << message.getSenderSockAddr(); + break; + } - if (packetTraitVersion > instanceVersionRef) { - if (traitSize == AvatarTraits::DELETED_TRAIT_SIZE) { - _avatar->processDeletedTraitInstance(traitType, instanceID); + if (traitType == AvatarTraits::AvatarEntity) { + auto& instanceVersionRef = _lastReceivedTraitVersions.getInstanceValueRef(traitType, instanceID); - // to track a deleted instance but keep version information - // the avatar mixer uses the negative value of the sent version - instanceVersionRef = -packetTraitVersion; + if (packetTraitVersion > instanceVersionRef) { + if (traitSize == AvatarTraits::DELETED_TRAIT_SIZE) { + _avatar->processDeletedTraitInstance(traitType, instanceID); + + // to track a deleted instance but keep version information + // the avatar mixer uses the negative value of the sent version + instanceVersionRef = -packetTraitVersion; + } else { + _avatar->processTraitInstance(traitType, instanceID, message.read(traitSize)); + instanceVersionRef = packetTraitVersion; + } + + anyTraitsChanged = true; } else { - _avatar->processTraitInstance(traitType, instanceID, message.read(traitSize)); - instanceVersionRef = packetTraitVersion; + message.seek(message.getPosition() + traitSize); } - - anyTraitsChanged = true; } else { - message.seek(message.getPosition() + traitSize); + qWarning() << "Refusing to process traits packet with instanced trait of unprocessable type from" << message.getSenderSockAddr(); + break; } } } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 9c88580b99..b6ec006c39 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -152,6 +152,7 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis }); if (!isDeleted && (sentInstanceIt == sentIDValuePairs.end() || receivedVersion > sentInstanceIt->value)) { + // this instance version exists and has never been sent or is newer so we need to send it bytesWritten += sendingAvatar->packTraitInstance(traitType, instanceID, traitsPacketList, receivedVersion); @@ -161,6 +162,7 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis sentIDValuePairs.emplace_back(instanceID, receivedVersion); } } else if (isDeleted && sentInstanceIt != sentIDValuePairs.end() && absoluteReceivedVersion > sentInstanceIt->value) { + // this instance version was deleted and we haven't sent the delete to this client yet bytesWritten += AvatarTraits::packInstancedTraitDelete(traitType, instanceID, traitsPacketList, absoluteReceivedVersion); @@ -180,6 +182,7 @@ qint64 AvatarMixerSlave::addChangedTraitsToBulkPacket(AvatarMixerClientData* lis listeningNodeData->setLastOtherAvatarTraitsSendPoint(otherNodeLocalID, timeOfLastTraitsChange); } + return bytesWritten; } diff --git a/cmake/macros/TargetHifiAudioCodec.cmake b/cmake/macros/TargetHifiAudioCodec.cmake new file mode 100644 index 0000000000..98c24e684c --- /dev/null +++ b/cmake/macros/TargetHifiAudioCodec.cmake @@ -0,0 +1,22 @@ +# +# Copyright 2018 High Fidelity, Inc. +# Created by Gabriel Calero and Cristian Duarte on 2018/10/05 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_HIFIAUDIOCODEC) + if (ANDROID) + set(HIFIAC_INSTALL_DIR ${HIFI_ANDROID_PRECOMPILED}/hifiAC/codecSDK) + set(HIFIAC_LIB_DIR "${HIFIAC_INSTALL_DIR}/Release") + set(HIFIAC_INCLUDE_DIRS "${HIFIAC_INSTALL_DIR}/include" CACHE TYPE INTERNAL) + list(APPEND HIFIAC_LIBS "${HIFIAC_LIB_DIR}/libaudio.a") + set(HIFIAC_LIBRARIES ${HIFIAC_LIBS} CACHE TYPE INTERNAL) + else() + add_dependency_external_projects(hifiAudioCodec) + target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES}) + endif() + target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAC_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${HIFIAC_LIBRARIES}) +endmacro() diff --git a/interface/resources/images/interstitialPage/button.png b/interface/resources/images/interstitialPage/button.png new file mode 100644 index 0000000000..064e447581 Binary files /dev/null and b/interface/resources/images/interstitialPage/button.png differ diff --git a/interface/resources/images/interstitialPage/button_back.png b/interface/resources/images/interstitialPage/button_back.png new file mode 100644 index 0000000000..cb9c909836 Binary files /dev/null and b/interface/resources/images/interstitialPage/button_back.png differ diff --git a/interface/resources/images/interstitialPage/button_hover.png b/interface/resources/images/interstitialPage/button_hover.png new file mode 100644 index 0000000000..4ae49fabb3 Binary files /dev/null and b/interface/resources/images/interstitialPage/button_hover.png differ diff --git a/interface/resources/images/interstitialPage/button_tryAgain.png b/interface/resources/images/interstitialPage/button_tryAgain.png new file mode 100644 index 0000000000..35e9854be7 Binary files /dev/null and b/interface/resources/images/interstitialPage/button_tryAgain.png differ diff --git a/interface/resources/serverless/redirect.json b/interface/resources/serverless/redirect.json index 64cb4d8a3f..0b96bad961 100644 --- a/interface/resources/serverless/redirect.json +++ b/interface/resources/serverless/redirect.json @@ -2,53 +2,9 @@ "DataVersion": 0, "Paths": { - "/": "/4,1.4,4/0,0.49544,0,0.868645" + "/": "/2.3,0.4,2.89/0,0.49544,0,0.868645" }, "Entities": [ - { - "clientOnly": false, - "collidesWith": "static,dynamic,kinematic,otherAvatar,", - "collisionMask": 23, - "created": "2018-09-05T18:13:00Z", - "dimensions": { - "blue": 1.159199833869934, - "green": 2.8062009811401367, - "red": 1.6216505765914917, - "x": 1.6216505765914917, - "y": 2.8062009811401367, - "z": 1.159199833869934 - }, - "id": "{d0ed60b8-9174-4c56-8e78-2c5399329ae0}", - "lastEdited": 1536171372916208, - "lastEditedBy": "{151cb20e-715a-4c80-aa0d-5b58b1c8a0c9}", - "locked": true, - "name": "Try Again Zone", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue":4.015342712402344, - "green":1.649999976158142, - "red":2.00921893119812, - "x":2.00921893119812, - "y":1.649999976158142, - "z":4.015342712402344 - }, - "queryAACube": { - "scale": 3.4421300888061523, - "x": 1.6001315116882324, - "y": -0.07100248336791992, - "z": 0.14220571517944336 - }, - "rotation": { - "w": 0.9914448857307434, - "x": 0, - "y": -0.13052619993686676, - "z": 0 - }, - "script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/zoneTryAgainEntityScript.js", - "shapeType": "box", - "type": "Zone", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, { "clientOnly": false, "color": { @@ -56,7 +12,7 @@ "green": 0, "red": 255 }, - "created": "2018-09-05T00:40:03Z", + "created": "2018-09-25T18:44:28Z", "dimensions": { "blue": 8.645400047302246, "green": 0.20000000298023224, @@ -65,23 +21,23 @@ "y": 0.20000000298023224, "z": 8.645400047302246 }, - "id": "{e44fb546-b34a-4966-9b11-73556f800d21}", - "lastEdited": 1536107948776951, - "lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}", + "id": "{eac57ccf-1e81-4d74-80f1-f17f23fc2f2c}", + "lastEdited": 1537901430334573, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", "locked": true, "name": "ceiling", "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", "position": { "blue": 4.846520900726318, "green": 2.912982940673828, - "red": 5.739595890045166, - "x": 5.739595890045166, + "red": 6.00444221496582, + "x": 6.00444221496582, "y": 2.912982940673828, "z": 4.846520900726318 }, "queryAACube": { "scale": 21.812576293945312, - "x": -5.16669225692749, + "x": -4.901845932006836, "y": -7.993305206298828, "z": -6.059767246246338 }, @@ -103,53 +59,7 @@ "green": 0, "red": 0 }, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 6.9401350021362305, - "green": 0.04553089290857315, - "red": 7.004304885864258, - "x": 7.004304885864258, - "y": 0.04553089290857315, - "z": 6.9401350021362305 - }, - "id": "{8cd93fe5-16c0-44b7-b1e9-e7e06c4e9228}", - "lastEdited": 1536107948774796, - "lastEditedBy": "{4eecd88f-ef9b-4a83-bb9a-7f7496209c6b}", - "locked": true, - "name": "floor", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 3.6175529956817627, - "green": 0, - "red": 4.102385997772217, - "x": 4.102385997772217, - "y": 0, - "z": 3.6175529956817627 - }, - "queryAACube": { - "scale": 9.860417366027832, - "x": -0.8278226852416992, - "y": -4.930208683013916, - "z": -1.3126556873321533 - }, - "rotation": { - "w": 0.8660253882408142, - "x": -1.5922749298624694e-05, - "y": 0.5, - "z": -4.572480611386709e-05 - }, - "shape": "Cube", - "type": "Box", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "clientOnly": false, - "color": { - "blue": 0, - "green": 0, - "red": 0 - }, - "created": "2018-09-05T00:40:03Z", + "created": "2018-09-25T18:44:28Z", "dimensions": { "blue": 11.117486953735352, "green": 3.580313205718994, @@ -158,70 +68,23 @@ "y": 3.580313205718994, "z": 11.117486953735352 }, - "id": "{147272dc-a344-4171-9621-efc1c2095997}", - "lastEdited": 1536107948776823, - "lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}", - "locked": true, - "name": "leftWall", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 6.1806135177612305, - "green": 1.0066027641296387, - "red": 1.4690406322479248, - "x": 1.4690406322479248, - "y": 1.0066027641296387, - "z": 6.1806135177612305 - }, - "queryAACube": { - "scale": 11.681488037109375, - "x": -4.371703147888184, - "y": -4.834141254425049, - "z": 0.33986949920654297 - }, - "rotation": { - "w": 0.8637980222702026, - "x": -4.57763671875e-05, - "y": 0.5038070678710938, - "z": -1.52587890625e-05 - }, - "shape": "Cube", - "type": "Box", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}", - "visible": false - }, - { - "clientOnly": false, - "color": { - "blue": 0, - "green": 0, - "red": 0 - }, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 11.117486953735352, - "green": 3.580313205718994, - "red": 0.20000000298023224, - "x": 0.20000000298023224, - "y": 3.580313205718994, - "z": 11.117486953735352 - }, - "id": "{5f2b89b8-47e3-4915-a966-d46307a40f06}", - "lastEdited": 1536107948774605, - "lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}", + "id": "{54609e9e-f729-46fc-ac06-78d44ee6b6fe}", + "lastEdited": 1537901430334887, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", "locked": true, "name": "backWall", "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", "position": { "blue": 5.268576622009277, "green": 1.0066027641296387, - "red": 6.093774318695068, - "x": 6.093774318695068, + "red": 6.358620643615723, + "x": 6.358620643615723, "y": 1.0066027641296387, "z": 5.268576622009277 }, "queryAACube": { "scale": 11.681488037109375, - "x": 0.25303030014038086, + "x": 0.5178766250610352, "y": -4.834141254425049, "z": -0.5721673965454102 }, @@ -236,422 +99,6 @@ "userData": "{\"grabbableKey\":{\"grabbable\":false}}", "visible": false }, - { - "clientOnly": false, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 14.40000057220459, - "green": 14.40000057220459, - "red": 14.40000057220459, - "x": 14.40000057220459, - "y": 14.40000057220459, - "z": 14.40000057220459 - }, - "id": "{baf96345-8f68-4068-af4c-3c690035852a}", - "lastEdited": 1536107948775591, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "locked": true, - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 2.3440732955932617, - "green": 1.6162219047546387, - "red": 1.8748211860656738, - "x": 1.8748211860656738, - "y": 1.6162219047546387, - "z": 2.3440732955932617 - }, - "queryAACube": { - "scale": 24.9415340423584, - "x": -10.595945358276367, - "y": -10.854545593261719, - "z": -10.126693725585938 - }, - "rotation": { - "w": 0.8697794675827026, - "x": -1.52587890625e-05, - "y": 0.4933699369430542, - "z": -4.57763671875e-05 - }, - "shapeType": "box", - "skyboxMode": "enabled", - "type": "Zone", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "alpha": 0, - "alphaFinish": 0, - "alphaStart": 1, - "clientOnly": false, - "color": { - "blue": 211, - "green": 227, - "red": 104 - }, - "colorFinish": { - "blue": 0, - "green": 0, - "red": 0, - "x": 0, - "y": 0, - "z": 0 - }, - "colorStart": { - "blue": 211, - "green": 227, - "red": 104, - "x": 104, - "y": 227, - "z": 211 - }, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 2.5, - "green": 2.5, - "red": 2.5, - "x": 2.5, - "y": 2.5, - "z": 2.5 - }, - "emitAcceleration": { - "blue": 0, - "green": 0, - "red": 0, - "x": 0, - "y": 0, - "z": 0 - }, - "emitDimensions": { - "blue": 1, - "green": 1, - "red": 1, - "x": 1, - "y": 1, - "z": 1 - }, - "emitOrientation": { - "w": 0.9993909597396851, - "x": 0.034897372126579285, - "y": -1.525880907138344e-05, - "z": -1.525880907138344e-05 - }, - "emitRate": 2, - "emitSpeed": 0, - "id": "{639a51f0-8613-4e46-bc7e-fef24597df73}", - "lastEdited": 1536107948776693, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "lifespan": 10, - "locked": true, - "maxParticles": 40, - "name": "Rays", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "particleRadius": 0.75, - "polarFinish": 3.1415927410125732, - "position": { - "blue": 1.3553659915924072, - "green": 1.2890124320983887, - "red": 2.5663273334503174, - "x": 2.5663273334503174, - "y": 1.2890124320983887, - "z": 1.3553659915924072 - }, - "queryAACube": { - "scale": 4.330127239227295, - "x": 0.4012637138366699, - "y": -0.8760511875152588, - "z": -0.8096976280212402 - }, - "radiusFinish": 0.10000000149011612, - "radiusStart": 0, - "rotation": { - "w": 0.9803768396377563, - "x": -1.52587890625e-05, - "y": 0.19707024097442627, - "z": -7.62939453125e-05 - }, - "speedSpread": 0, - "spinFinish": null, - "spinStart": null, - "textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/stripe.png", - "type": "ParticleEffect", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "alpha": 0, - "alphaFinish": 0, - "alphaStart": 1, - "clientOnly": false, - "color": { - "blue": 255, - "green": 205, - "red": 3 - }, - "colorFinish": { - "blue": 0, - "green": 0, - "red": 0, - "x": 0, - "y": 0, - "z": 0 - }, - "colorStart": { - "blue": 255, - "green": 204, - "red": 0, - "x": 0, - "y": 204, - "z": 255 - }, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 2.5, - "green": 2.5, - "red": 2.5, - "x": 2.5, - "y": 2.5, - "z": 2.5 - }, - "emitAcceleration": { - "blue": 0, - "green": 0, - "red": 0, - "x": 0, - "y": 0, - "z": 0 - }, - "emitDimensions": { - "blue": 1, - "green": 1, - "red": 1, - "x": 1, - "y": 1, - "z": 1 - }, - "emitOrientation": { - "w": 0.9993909597396851, - "x": 0.034897372126579285, - "y": -1.525880907138344e-05, - "z": -1.525880907138344e-05 - }, - "emitRate": 2, - "emitSpeed": 0, - "emitterShouldTrail": true, - "id": "{e62ced49-fa18-4ae1-977f-abef5bc0f3ba}", - "lastEdited": 1536107948775366, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "lifespan": 10, - "locked": true, - "maxParticles": 40, - "name": "Rays", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "particleRadius": 0.75, - "polarFinish": 3.1415927410125732, - "position": { - "blue": 3.814434051513672, - "green": 1.2890124320983887, - "red": 1.2254328727722168, - "x": 1.2254328727722168, - "y": 1.2890124320983887, - "z": 3.814434051513672 - }, - "queryAACube": { - "scale": 4.330127239227295, - "x": -0.9396307468414307, - "y": -0.8760511875152588, - "z": 1.6493704319000244 - }, - "radiusFinish": 0.10000000149011612, - "radiusStart": 0, - "rotation": { - "w": 0.9594720602035522, - "x": -1.52587890625e-05, - "y": 0.28178834915161133, - "z": -4.57763671875e-05 - }, - "speedSpread": 0, - "spinFinish": null, - "spinStart": null, - "textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/stripe.png", - "type": "ParticleEffect", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "alpha": 0, - "alphaFinish": 0, - "alphaStart": 0.25, - "clientOnly": false, - "colorFinish": { - "blue": 0, - "green": 0, - "red": 0, - "x": 0, - "y": 0, - "z": 0 - }, - "colorStart": { - "blue": 255, - "green": 255, - "red": 255, - "x": 255, - "y": 255, - "z": 255 - }, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 13.24000072479248, - "green": 13.24000072479248, - "red": 13.24000072479248, - "x": 13.24000072479248, - "y": 13.24000072479248, - "z": 13.24000072479248 - }, - "emitAcceleration": { - "blue": 0, - "green": 0.10000000149011612, - "red": 0, - "x": 0, - "y": 0.10000000149011612, - "z": 0 - }, - "emitDimensions": { - "blue": 1, - "green": 1, - "red": 1, - "x": 1, - "y": 1, - "z": 1 - }, - "emitOrientation": { - "w": 1, - "x": -1.52587890625e-05, - "y": -1.52587890625e-05, - "z": -1.52587890625e-05 - }, - "emitRate": 6, - "emitSpeed": 0, - "id": "{298c0571-cbd8-487b-8640-64037d6a8414}", - "lastEdited": 1536107948776382, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "lifespan": 10, - "locked": true, - "maxParticles": 10, - "name": "Stars", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "particleRadius": 0.07000000029802322, - "polarFinish": 3.1415927410125732, - "position": { - "blue": 1.3712034225463867, - "green": 0.3698839843273163, - "red": 2.6216418743133545, - "x": 2.6216418743133545, - "y": 0.3698839843273163, - "z": 1.3712034225463867 - }, - "queryAACube": { - "scale": 22.932353973388672, - "x": -8.844534873962402, - "y": -11.096293449401855, - "z": -10.09497356414795 - }, - "radiusFinish": 0, - "radiusStart": 0, - "rotation": { - "w": 0.9852597713470459, - "x": -1.52587890625e-05, - "y": -0.17106890678405762, - "z": -7.62939453125e-05 - }, - "speedSpread": 0, - "spinFinish": null, - "spinStart": null, - "textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/star.png", - "type": "ParticleEffect", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "clientOnly": false, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 2.1097896099090576, - "green": 0.04847164824604988, - "red": 1.458284616470337, - "x": 1.458284616470337, - "y": 0.04847164824604988, - "z": 2.1097896099090576 - }, - "id": "{6625dbb8-ff25-458d-a92e-644b58460604}", - "lastEdited": 1536107948776195, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "locked": true, - "modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal1.fbx", - "name": "Try Again", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 3.946338653564453, - "green": 0.09449335932731628, - "red": 1.594836711883545, - "x": 1.594836711883545, - "y": 0.09449335932731628, - "z": 3.946338653564453 - }, - "queryAACube": { - "scale": 2.5651814937591553, - "x": 0.3122459650039673, - "y": -1.188097357749939, - "z": 2.663747787475586 - }, - "rotation": { - "w": 0.8220492601394653, - "x": -1.52587890625e-05, - "y": 0.5693598985671997, - "z": -0.0001068115234375 - }, - "script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/tryAgainEntityScript.js", - "shapeType": "static-mesh", - "type": "Model", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "clientOnly": false, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 0.06014331430196762, - "green": 2.582186460494995, - "red": 2.582186698913574, - "x": 2.582186698913574, - "y": 2.582186460494995, - "z": 0.06014331430196762 - }, - "id": "{dfe92dce-f09d-4e9e-b3ed-c68ecd4d476f}", - "lastEdited": 1536108160862286, - "lastEditedBy": "{4656d4a8-5e61-4230-ab34-2888d7945bd6}", - "modelURL": "", - "name": "Oops Dialog", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 1.45927095413208, - "green": 1.6763916015625, - "red": 0, - "x": 0, - "y": 1.6763916015625, - "z": 1.45927095413208 - }, - "queryAACube": { - "scale": 3.6522583961486816, - "x": -1.8261291980743408, - "y": -0.14973759651184082, - "z": -0.36685824394226074 - }, - "rotation": { - "w": 0.8684672117233276, - "x": -4.57763671875e-05, - "y": 0.4957197904586792, - "z": -7.62939453125e-05 - }, - "script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/oopsEntityScript.js", - "scriptTimestamp": 1536102551825, - "type": "Model", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, { "clientOnly": false, "color": { @@ -659,7 +106,7 @@ "green": 0, "red": 0 }, - "created": "2018-09-05T00:40:03Z", + "created": "2018-09-25T18:44:28Z", "dimensions": { "blue": 11.117486953735352, "green": 3.580313205718994, @@ -668,114 +115,23 @@ "y": 3.580313205718994, "z": 11.117486953735352 }, - "id": "{144a8cf4-b0e8-489a-9403-d74d4dc4cb3e}", - "lastEdited": 1536107948775774, - "lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}", - "locked": true, - "name": "rightWall", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 0, - "green": 1.0061144828796387, - "red": 4.965089321136475, - "x": 4.965089321136475, - "y": 1.0061144828796387, - "z": 0 - }, - "queryAACube": { - "scale": 11.681488037109375, - "x": -0.8756546974182129, - "y": -4.834629535675049, - "z": -5.8407440185546875 - }, - "rotation": { - "w": 0.8637980222702026, - "x": -4.57763671875e-05, - "y": 0.5038070678710938, - "z": -1.52587890625e-05 - }, - "shape": "Cube", - "type": "Box", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}", - "visible": false - }, - { - "clientOnly": false, - "collidesWith": "static,dynamic,kinematic,otherAvatar,", - "collisionMask": 23, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 1.159199833869934, - "green": 2.8062009811401367, - "red": 1.6216505765914917, - "x": 1.6216505765914917, - "y": 2.8062009811401367, - "z": 1.159199833869934 - }, - "id": "{37f53408-3d0c-42a5-9891-e6c40a227349}", - "lastEdited": 1536107948775010, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "locked": true, - "name": "Back Zone", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "blue": 1.8632707595825195, - "green": 1.6500625610351562, - "red": 3.3211965560913086, - "x": 3.3211965560913086, - "y": 1.6500625610351562, - "z": 1.8632707595825195 - }, - "queryAACube": { - "scale": 3.4421300888061523, - "x": 1.6001315116882324, - "y": -0.07100248336791992, - "z": 0.14220571517944336 - }, - "rotation": { - "w": 0.9304176568984985, - "x": 0, - "y": -0.36650121212005615, - "z": 0 - }, - "script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/zoneBackEntityScript.js", - "shapeType": "box", - "type": "Zone", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" - }, - { - "clientOnly": false, - "color": { - "blue": 0, - "green": 0, - "red": 0 - }, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 11.117486953735352, - "green": 3.580313205718994, - "red": 0.20000000298023224, - "x": 0.20000000298023224, - "y": 3.580313205718994, - "z": 11.117486953735352 - }, - "id": "{aa6e680c-6750-4776-95bc-ef3118cace5c}", - "lastEdited": 1536107948775945, - "lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}", + "id": "{c9352a54-b2cd-4c0f-a898-7e79c01404d0}", + "lastEdited": 1537901430334652, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", "locked": true, "name": "frontWall", "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", "position": { "blue": 2.662257671356201, "green": 1.0063786506652832, - "red": 1.4868733882904053, - "x": 1.4868733882904053, + "red": 1.7517199516296387, + "x": 1.7517199516296387, "y": 1.0063786506652832, "z": 2.662257671356201 }, "queryAACube": { "scale": 11.681488037109375, - "x": -4.353870391845703, + "x": -4.089024066925049, "y": -4.834365367889404, "z": -3.1784863471984863 }, @@ -792,143 +148,229 @@ }, { "clientOnly": false, - "created": "2018-09-05T00:40:03Z", - "dimensions": { - "blue": 2.1097896099090576, - "green": 0.04847164824604988, - "red": 1.458284616470337, - "x": 1.458284616470337, - "y": 0.04847164824604988, - "z": 2.1097896099090576 + "color": { + "blue": 0, + "green": 0, + "red": 0 }, - "id": "{303631f1-04f3-42a6-b8a8-8dd4b65d1231}", - "lastEdited": 1536107948776513, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", + "created": "2018-09-25T18:44:28Z", + "dimensions": { + "blue": 11.117486953735352, + "green": 3.580313205718994, + "red": 0.20000000298023224, + "x": 0.20000000298023224, + "y": 3.580313205718994, + "z": 11.117486953735352 + }, + "id": "{c4b7a530-ec5b-47fc-be60-eed22f96799d}", + "lastEdited": 1537901430334730, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", "locked": true, - "modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal2.fbx", - "name": "Back", + "name": "rightWall", "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", "position": { - "blue": 1.5835940837860107, - "green": 0.09449335932731628, - "red": 3.028078079223633, - "x": 3.028078079223633, - "y": 0.09449335932731628, - "z": 1.5835940837860107 + "blue": 0, + "green": 1.0061144828796387, + "red": 5.229935646057129, + "x": 5.229935646057129, + "y": 1.0061144828796387, + "z": 0 }, "queryAACube": { - "scale": 2.5651814937591553, - "x": 1.7454873323440552, - "y": -1.188097357749939, - "z": 0.3010033369064331 + "scale": 11.681488037109375, + "x": -0.6108083724975586, + "y": -4.834629535675049, + "z": -5.8407440185546875 }, "rotation": { - "w": 0.9084458351135254, - "x": -1.52587890625e-05, - "y": 0.4179598093032837, - "z": -0.0001068115234375 + "w": 0.8637980222702026, + "x": -4.57763671875e-05, + "y": 0.5038070678710938, + "z": -1.52587890625e-05 }, - "script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/backEntityScript.js", - "scriptTimestamp": 1535751754379, - "shapeType": "static-mesh", + "shape": "Cube", + "type": "Box", + "userData": "{\"grabbableKey\":{\"grabbable\":false}}", + "visible": false + }, + { + "clientOnly": false, + "created": "2018-09-25T18:44:28Z", + "dimensions": { + "blue": 14.40000057220459, + "green": 14.40000057220459, + "red": 14.40000057220459, + "x": 14.40000057220459, + "y": 14.40000057220459, + "z": 14.40000057220459 + }, + "id": "{351ddd1e-79b3-4be7-8784-aca29bd65193}", + "lastEdited": 1537901430334210, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", + "locked": true, + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "position": { + "blue": 2.3440732955932617, + "green": 1.6162219047546387, + "red": 2.1396677494049072, + "x": 2.1396677494049072, + "y": 1.6162219047546387, + "z": 2.3440732955932617 + }, + "queryAACube": { + "scale": 24.9415340423584, + "x": -10.331099510192871, + "y": -10.854545593261719, + "z": -10.126693725585938 + }, + "rotation": { + "w": 0.8697794675827026, + "x": -1.52587890625e-05, + "y": 0.4933699369430542, + "z": -4.57763671875e-05 + }, + "shapeType": "box", + "skyboxMode": "enabled", + "type": "Zone", + "userData": "{\"grabbableKey\":{\"grabbable\":false}}" + }, + { + "clientOnly": false, + "color": { + "blue": 0, + "green": 0, + "red": 0 + }, + "created": "2018-09-25T18:44:28Z", + "dimensions": { + "blue": 6.9401350021362305, + "green": 0.04553089290857315, + "red": 7.004304885864258, + "x": 7.004304885864258, + "y": 0.04553089290857315, + "z": 6.9401350021362305 + }, + "id": "{81c13ed1-1873-4f21-adea-5112a0fdacd1}", + "lastEdited": 1537901430334808, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", + "locked": true, + "name": "floor", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "position": { + "blue": 3.6175529956817627, + "green": 0, + "red": 4.367232322692871, + "x": 4.367232322692871, + "y": 0, + "z": 3.6175529956817627 + }, + "queryAACube": { + "scale": 9.860417366027832, + "x": -0.5629763603210449, + "y": -4.930208683013916, + "z": -1.3126556873321533 + }, + "rotation": { + "w": 0.8660253882408142, + "x": -1.5922749298624694e-05, + "y": 0.5, + "z": -4.572480611386709e-05 + }, + "shape": "Cube", + "type": "Box", + "userData": "{\"grabbableKey\":{\"grabbable\":false}}", + "visible": false + }, + { + "clientOnly": false, + "created": "2018-09-25T18:44:28Z", + "dimensions": { + "blue": 6.9401350021362305, + "green": 0.04553089290857315, + "red": 7.004304885864258, + "x": 7.004304885864258, + "y": 0.04553089290857315, + "z": 6.9401350021362305 + }, + "id": "{5582179a-fb69-4678-af0c-c8e6d890839a}", + "lastEdited": 1537901430334966, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", + "locked": true, + "modelURL": "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/floor.fbx", + "name": "floorModel", + "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", + "position": { + "blue": 3.6175529956817627, + "green": 0, + "red": 4.367232322692871, + "x": 4.367232322692871, + "y": 0, + "z": 3.6175529956817627 + }, + "queryAACube": { + "scale": 9.860417366027832, + "x": -0.5629763603210449, + "y": -4.930208683013916, + "z": -1.3126556873321533 + }, + "rotation": { + "w": 0.8660253882408142, + "x": -1.5922749298624694e-05, + "y": 0.5, + "z": -4.572480611386709e-05 + }, + "shapeType": "simple-hull", "type": "Model", "userData": "{\"grabbableKey\":{\"grabbable\":false}}" }, { - "alpha": 0, - "alphaFinish": 0, - "alphaStart": 0.25, "clientOnly": false, - "colorFinish": { + "color": { "blue": 0, "green": 0, - "red": 0, - "x": 0, - "y": 0, - "z": 0 + "red": 0 }, - "colorStart": { - "blue": 255, - "green": 255, - "red": 255, - "x": 255, - "y": 255, - "z": 255 - }, - "created": "2018-09-05T00:40:03Z", + "created": "2018-09-25T18:44:28Z", "dimensions": { - "blue": 13.24000072479248, - "green": 13.24000072479248, - "red": 13.24000072479248, - "x": 13.24000072479248, - "y": 13.24000072479248, - "z": 13.24000072479248 + "blue": 11.117486953735352, + "green": 3.580313205718994, + "red": 0.20000000298023224, + "x": 0.20000000298023224, + "y": 3.580313205718994, + "z": 11.117486953735352 }, - "emitAcceleration": { - "blue": 0, - "green": 0.10000000149011612, - "red": 0, - "x": 0, - "y": 0.10000000149011612, - "z": 0 - }, - "emitDimensions": { - "blue": 1, - "green": 1, - "red": 1, - "x": 1, - "y": 1, - "z": 1 - }, - "emitOrientation": { - "w": 1, - "x": -1.52587890625e-05, - "y": -1.52587890625e-05, - "z": -1.52587890625e-05 - }, - "emitRate": 6, - "emitSpeed": 0, - "emitterShouldTrail": true, - "id": "{8ded39e6-303c-48f2-be79-81b715cca9f7}", - "lastEdited": 1536107948777127, - "lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}", - "lifespan": 10, + "id": "{366ec0b9-5106-4172-a9f6-2143f6c279aa}", + "lastEdited": 1537901430334307, + "lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}", "locked": true, - "maxParticles": 10, - "name": "Stars", + "name": "leftWall", "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "particleRadius": 0.07000000029802322, - "polarFinish": 3.1415927410125732, "position": { - "blue": 3.78922963142395, - "green": 0.3698839843273163, - "red": 1.1863799095153809, - "x": 1.1863799095153809, - "y": 0.3698839843273163, - "z": 3.78922963142395 + "blue": 6.1806135177612305, + "green": 1.0066027641296387, + "red": 1.7338871955871582, + "x": 1.7338871955871582, + "y": 1.0066027641296387, + "z": 6.1806135177612305 }, "queryAACube": { - "scale": 22.932353973388672, - "x": -10.279796600341797, - "y": -11.096293449401855, - "z": -7.676947593688965 + "scale": 11.681488037109375, + "x": -4.106856822967529, + "y": -4.834141254425049, + "z": 0.33986949920654297 }, - "radiusFinish": 0, - "radiusStart": 0, "rotation": { - "w": 0.996429443359375, - "x": -1.52587890625e-05, - "y": -0.08442819118499756, - "z": -4.57763671875e-05 + "w": 0.8637980222702026, + "x": -4.57763671875e-05, + "y": 0.5038070678710938, + "z": -1.52587890625e-05 }, - "speedSpread": 0, - "spinFinish": null, - "spinStart": null, - "textures": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/star.png", - "type": "ParticleEffect", - "userData": "{\"grabbableKey\":{\"grabbable\":false}}" + "shape": "Cube", + "type": "Box", + "userData": "{\"grabbableKey\":{\"grabbable\":false}}", + "visible": false } ], - "Id": "{18abccad-2d57-4176-9d89-24dc424916f5}", + "Id": "{6ec356c4-abf2-41b7-9980-c47dd08343b2}", "Version": 93 } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4b45541e1a..aa2b382c58 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -122,6 +122,7 @@ #include #include #include +#include #include #include #include @@ -365,7 +366,6 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI static const uint32_t INVALID_FRAME = UINT32_MAX; -static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); @@ -5383,8 +5383,8 @@ void Application::resetPhysicsReadyInformation() { // collision information of nearby entities to make running bullet be safe. _fullSceneReceivedCounter = 0; _fullSceneCounterAtLastPhysicsCheck = 0; - _nearbyEntitiesCountAtLastPhysicsCheck = 0; - _nearbyEntitiesStabilityCount = 0; + _gpuTextureMemSizeStabilityCount = 0; + _gpuTextureMemSizeAtLastCheck = 0; _physicsEnabled = false; _octreeProcessor.startEntitySequence(); } @@ -5623,18 +5623,21 @@ void Application::update(float deltaTime) { // for nearby entities before starting bullet up. quint64 now = usecTimestampNow(); if (isServerlessMode() || _octreeProcessor.isLoadSequenceComplete()) { - // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway - _lastPhysicsCheckTime = now; - _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; - _lastQueriedViews.clear(); // Force new view. + bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + if (gpuTextureMemSizeStable() || !enableInterstitial) { + // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway + _lastPhysicsCheckTime = now; + _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; + _lastQueriedViews.clear(); // Force new view. - // process octree stats packets are sent in between full sends of a scene (this isn't currently true). - // We keep physics disabled until we've received a full scene and everything near the avatar in that - // scene is ready to compute its collision shape. - if (getMyAvatar()->isReadyForPhysics()) { - _physicsEnabled = true; - setIsInterstitialMode(false); - getMyAvatar()->updateMotionBehaviorFromMenu(); + // process octree stats packets are sent in between full sends of a scene (this isn't currently true). + // We keep physics disabled until we've received a full scene and everything near the avatar in that + // scene is ready to compute its collision shape. + if (getMyAvatar()->isReadyForPhysics()) { + _physicsEnabled = true; + setIsInterstitialMode(false); + getMyAvatar()->updateMotionBehaviorFromMenu(); + } } } } else if (domainLoadingInProgress) { @@ -5921,6 +5924,10 @@ void Application::update(float deltaTime) { // update the rendering without any simulation getEntities()->update(false); } + // remove recently dead avatarEntities + SetOfEntities deadAvatarEntities; + _entitySimulation->takeDeadAvatarEntities(deadAvatarEntities); + avatarManager->removeDeadAvatarEntities(deadAvatarEntities); } // AvatarManager update @@ -6245,6 +6252,8 @@ int Application::sendNackPackets() { missingSequenceNumbers = sequenceNumberStats.getMissingSet(); }); + _isMissingSequenceNumbers = (missingSequenceNumbers.size() != 0); + // construct nack packet(s) for this node foreach(const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) { nackPacketList->writePrimitive(missingNumber); @@ -6271,9 +6280,19 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { const bool isModifiedQuery = !_physicsEnabled; if (isModifiedQuery) { // Create modified view that is a simple sphere. + bool interstitialModeEnabled = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + ConicalViewFrustum sphericalView; sphericalView.setSimpleRadius(INITIAL_QUERY_RADIUS); - _octreeQuery.setConicalViews({ sphericalView }); + + if (interstitialModeEnabled) { + ConicalViewFrustum farView; + farView.set(_viewFrustum); + _octreeQuery.setConicalViews({ sphericalView, farView }); + } else { + _octreeQuery.setConicalViews({ sphericalView }); + } + _octreeQuery.setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE); static constexpr float MIN_LOD_ADJUST = -20.0f; _octreeQuery.setBoundaryLevelAdjust(MIN_LOD_ADJUST); @@ -6585,69 +6604,23 @@ void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNode } } -bool Application::nearbyEntitiesAreReadyForPhysics() { - // this is used to avoid the following scenario: - // A table has some items sitting on top of it. The items are at rest, meaning they aren't active in bullet. - // Someone logs in close to the table. They receive information about the items on the table before they - // receive information about the table. The items are very close to the avatar's capsule, so they become - // activated in bullet. This causes them to fall to the floor, because the table's shape isn't yet in bullet. - EntityTreePointer entityTree = getEntities()->getTree(); - if (!entityTree) { - return false; - } +bool Application::gpuTextureMemSizeStable() { + auto renderConfig = qApp->getRenderEngine()->getConfiguration(); + auto renderStats = renderConfig->getConfig("Stats"); - // We don't want to use EntityTree::findEntities(AABox, ...) method because that scan will snarf parented entities - // whose bounding boxes cannot be computed (it is too loose for our purposes here). Instead we manufacture - // custom filters and use the general-purpose EntityTree::findEntities(filter, ...) - QVector entities; - AABox avatarBox(getMyAvatar()->getWorldPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE)); - // create two functions that use avatarBox (entityScan and elementScan), the second calls the first - std::function entityScan = [=](EntityItemPointer& entity) { - if (entity->shouldBePhysical()) { - bool success = false; - AABox entityBox = entity->getAABox(success); - // important: bail for entities that cannot supply a valid AABox - return success && avatarBox.touches(entityBox); - } - return false; - }; - std::function elementScan = [&](const OctreeElementPointer& element, void* unused) { - if (element->getAACube().touches(avatarBox)) { - EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - entityTreeElement->getEntities(entityScan, entities); - return true; - } - return false; - }; + qint64 textureResourceGPUMemSize = renderStats->textureResourceGPUMemSize; + qint64 texturePopulatedGPUMemSize = renderStats->textureResourcePopulatedGPUMemSize; + qint64 textureTransferSize = renderStats->texturePendingGPUTransferSize; - entityTree->withReadLock([&] { - // Pass the second function to the general-purpose EntityTree::findEntities() - // which will traverse the tree, apply the two filter functions (to element, then to entities) - // as it traverses. The end result will be a list of entities that match. - entityTree->findEntities(elementScan, entities); - }); - - uint32_t nearbyCount = entities.size(); - if (nearbyCount == _nearbyEntitiesCountAtLastPhysicsCheck) { - _nearbyEntitiesStabilityCount++; + if (_gpuTextureMemSizeAtLastCheck == textureResourceGPUMemSize) { + _gpuTextureMemSizeStabilityCount++; } else { - _nearbyEntitiesStabilityCount = 0; + _gpuTextureMemSizeStabilityCount = 0; } - _nearbyEntitiesCountAtLastPhysicsCheck = nearbyCount; + _gpuTextureMemSizeAtLastCheck = textureResourceGPUMemSize; - const uint32_t MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT = 3; - if (_nearbyEntitiesStabilityCount >= MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT) { - // We've seen the same number of nearby entities for several stats packets in a row. assume we've got all - // the local entities. - bool result = true; - foreach (EntityItemPointer entity, entities) { - if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { - HIFI_FCDEBUG(interfaceapp(), "Physics disabled until entity loads: " << entity->getID() << entity->getName()); - // don't break here because we want all the relevant entities to start their downloads - result = false; - } - } - return result; + if (_gpuTextureMemSizeStabilityCount >= _minimumGPUTextureMemSizeStabilityCount) { + return (textureResourceGPUMemSize == texturePopulatedGPUMemSize) && (textureTransferSize == 0); } return false; } diff --git a/interface/src/Application.h b/interface/src/Application.h index f2e3b3953f..75260b910f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -183,6 +183,8 @@ public: // passes, mirror window passes, etc void copyDisplayViewFrustum(ViewFrustum& viewOut) const; + bool isMissingSequenceNumbers() { return _isMissingSequenceNumbers; } + const ConicalViewFrustums& getConicalViews() const override { return _conicalViews; } const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } @@ -230,6 +232,8 @@ public: float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); } void setSettingConstrainToolbarPosition(bool setting); + Q_INVOKABLE void setMinimumGPUTextureMemStabilityCount(int stabilityCount) { _minimumGPUTextureMemSizeStabilityCount = stabilityCount; } + NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } @@ -525,7 +529,7 @@ private: bool importFromZIP(const QString& filePath); bool importImage(const QString& urlString); - bool nearbyEntitiesAreReadyForPhysics(); + bool gpuTextureMemSizeStable(); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket); @@ -581,6 +585,8 @@ private: QElapsedTimer _lastTimeUpdated; QElapsedTimer _lastTimeRendered; + int _minimumGPUTextureMemSizeStabilityCount { 30 }; + ShapeManager _shapeManager; PhysicalEntitySimulationPointer _entitySimulation; PhysicsEnginePointer _physicsEngine; @@ -709,6 +715,8 @@ private: bool _fakedMouseEvent { false }; + bool _isMissingSequenceNumbers { false }; + void checkChangeCursor(); mutable QMutex _changeCursorLock { QMutex::Recursive }; Qt::CursorShape _desiredCursor{ Qt::BlankCursor }; @@ -719,8 +727,10 @@ private: std::atomic _fullSceneReceivedCounter { 0 }; // how many times have we received a full-scene octree stats packet uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready - uint32_t _nearbyEntitiesCountAtLastPhysicsCheck { 0 }; // how many in-range entities last time we checked physics ready - uint32_t _nearbyEntitiesStabilityCount { 0 }; // how many times has _nearbyEntitiesCountAtLastPhysicsCheck been the same + + qint64 _gpuTextureMemSizeStabilityCount { 0 }; + qint64 _gpuTextureMemSizeAtLastCheck { 0 }; + quint64 _lastPhysicsCheckTime { usecTimestampNow() }; // when did we last check to see if physics was ready bool _keyboardDeviceHasFocus { true }; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index c268561a8d..d31b201dc7 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -452,6 +452,17 @@ void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction transaction.clear(); } +void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) { + for (auto entity : deadEntities) { + QUuid sessionID = entity->getOwningAvatarID(); + AvatarSharedPointer avatar = getAvatarBySessionID(sessionID); + if (avatar) { + const bool REQUIRES_REMOVAL_FROM_TREE = false; + avatar->clearAvatarEntity(entity->getID(), REQUIRES_REMOVAL_FROM_TREE); + } + } +} + void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { auto avatar = std::static_pointer_cast(removedAvatar); { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 3ed156f673..209b976c44 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -26,6 +26,7 @@ #include #include #include +#include // for SetOfEntities #include "AvatarMotionState.h" #include "MyAvatar.h" @@ -187,6 +188,7 @@ public: void queuePhysicsChange(const OtherAvatarPointer& avatar); void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction); void handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction); + void removeDeadAvatarEntities(const SetOfEntities& deadEntities); public slots: /**jsdoc diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 086cbb3425..b347963cf1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -137,7 +137,7 @@ MyAvatar::MyAvatar(QThread* thread) : _useSnapTurnSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "useSnapTurn", _useSnapTurn), _userHeightSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userHeight", DEFAULT_AVATAR_HEIGHT), _flyingHMDSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "flyingHMD", _flyingPrefHMD), - _avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", _flyingPrefHMD) + _avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", 0) { _clientTraitsHandler = std::unique_ptr(new ClientTraitsHandler(this)); diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index 5d4ebe9853..db381d5350 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -10,8 +10,11 @@ // #include "SafeLanding.h" + +#include + #include "EntityTreeRenderer.h" -#include "ModelEntityItem.h" +#include "RenderableModelEntityItem.h" #include "InterfaceLogging.h" #include "Application.h" @@ -39,6 +42,7 @@ void SafeLanding::startEntitySequence(QSharedPointer entityT _entityTree = entityTree; _trackedEntities.clear(); _trackingEntities = true; + _maxTrackedEntityCount = 0; connect(std::const_pointer_cast(_entityTree).get(), &EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity); connect(std::const_pointer_cast(_entityTree).get(), @@ -47,6 +51,7 @@ void SafeLanding::startEntitySequence(QSharedPointer entityT _sequenceNumbers.clear(); _initialStart = INVALID_SEQUENCE; _initialEnd = INVALID_SEQUENCE; + _startTime = usecTimestampNow(); EntityTreeRenderer::setEntityLoadingPriorityFunction(&ElevatedPriority); } } @@ -55,6 +60,7 @@ void SafeLanding::stopEntitySequence() { Locker lock(_lock); _trackingEntities = false; _maxTrackedEntityCount = 0; + _trackedEntityStabilityCount = 0; _initialStart = INVALID_SEQUENCE; _initialEnd = INVALID_SEQUENCE; _trackedEntities.clear(); @@ -66,18 +72,17 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) { Locker lock(_lock); EntityItemPointer entity = _entityTree->findEntityByID(entityID); - if (entity) { + if (entity && entity->getCreated() < _startTime) { _trackedEntities.emplace(entityID, entity); int trackedEntityCount = (int)_trackedEntities.size(); if (trackedEntityCount > _maxTrackedEntityCount) { _maxTrackedEntityCount = trackedEntityCount; + _trackedEntityStabilityCount = 0; } qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName(); } - } else { - qCDebug(interfaceapp) << "Safe Landing: Null Entity: " << entityID; } } @@ -104,10 +109,10 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) { bool SafeLanding::isLoadSequenceComplete() { if (isEntityLoadingComplete() && isSequenceNumbersComplete()) { Locker lock(_lock); - _trackedEntities.clear(); _initialStart = INVALID_SEQUENCE; _initialEnd = INVALID_SEQUENCE; _entityTree = nullptr; + _trackingEntities = false; // Don't track anything else that comes in. EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority); } @@ -116,11 +121,18 @@ bool SafeLanding::isLoadSequenceComplete() { float SafeLanding::loadingProgressPercentage() { Locker lock(_lock); + static const int MINIMUM_TRACKED_ENTITY_STABILITY_COUNT = 15; + + float entityReadyPercentage = 0.0f; if (_maxTrackedEntityCount > 0) { - return ((_maxTrackedEntityCount - _trackedEntities.size()) / (float)_maxTrackedEntityCount); + entityReadyPercentage = ((_maxTrackedEntityCount - _trackedEntities.size()) / (float)_maxTrackedEntityCount); } - return 0.0f; + if (_trackedEntityStabilityCount < MINIMUM_TRACKED_ENTITY_STABILITY_COUNT) { + entityReadyPercentage *= 0.20f; + } + + return entityReadyPercentage; } bool SafeLanding::isSequenceNumbersComplete() { @@ -130,11 +142,16 @@ bool SafeLanding::isSequenceNumbersComplete() { _initialEnd + SEQUENCE_MODULO - _initialStart; auto startIter = _sequenceNumbers.find(_initialStart); auto endIter = _sequenceNumbers.find(_initialEnd - 1); + + bool missingSequenceNumbers = qApp->isMissingSequenceNumbers(); if (sequenceSize == 0 || (startIter != _sequenceNumbers.end() && endIter != _sequenceNumbers.end() - && distance(startIter, endIter) == sequenceSize - 1) ) { - _trackingEntities = false; // Don't track anything else that comes in. + && ((distance(startIter, endIter) == sequenceSize - 1) || !missingSequenceNumbers))) { + bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + if (!enableInterstitial) { + _trackingEntities = false; // Don't track anything else that comes in. + } return true; } } @@ -145,13 +162,13 @@ bool isEntityPhysicsReady(const EntityItemPointer& entity) { if (entity && !entity->getCollisionless()) { const auto& entityType = entity->getType(); if (entityType == EntityTypes::Model) { - ModelEntityItem * modelEntity = std::dynamic_pointer_cast(entity).get(); + RenderableModelEntityItem * modelEntity = std::dynamic_pointer_cast(entity).get(); static const std::set downloadedCollisionTypes { SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, SHAPE_TYPE_SIMPLE_HULL }; bool hasAABox; entity->getAABox(hasAABox); if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) { - return (!entity->shouldBePhysical() || entity->isReadyToComputeShape()); + return (!entity->shouldBePhysical() || entity->isReadyToComputeShape() || modelEntity->computeShapeFailedToLoad()); } } } @@ -166,16 +183,20 @@ bool SafeLanding::isEntityLoadingComplete() { auto entityTree = qApp->getEntities(); auto entityMapIter = _trackedEntities.begin(); + bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + while (entityMapIter != _trackedEntities.end()) { auto entity = entityMapIter->second; bool isVisuallyReady = true; - Settings settings; - bool enableInterstitial = settings.value("enableIntersitialMode", false).toBool(); - if (enableInterstitial) { - isVisuallyReady = (entity->isVisuallyReady() || !entityTree->renderableForEntityId(entityMapIter->first)); + auto entityRenderable = entityTree->renderableForEntityId(entityMapIter->first); + if (!entityRenderable) { + entityTree->addingEntity(entityMapIter->first); + } + + isVisuallyReady = entity->isVisuallyReady() || (!entityRenderable && !entity->isParentPathComplete()); } if (isEntityPhysicsReady(entity) && isVisuallyReady) { @@ -188,6 +209,12 @@ bool SafeLanding::isEntityLoadingComplete() { entityMapIter++; } } + + if (enableInterstitial) { + _trackedEntityStabilityCount++; + } + + return _trackedEntities.empty(); } diff --git a/interface/src/octree/SafeLanding.h b/interface/src/octree/SafeLanding.h index 317e4587c7..51357b60ff 100644 --- a/interface/src/octree/SafeLanding.h +++ b/interface/src/octree/SafeLanding.h @@ -52,6 +52,9 @@ private: int _initialStart { INVALID_SEQUENCE }; int _initialEnd { INVALID_SEQUENCE }; int _maxTrackedEntityCount { 0 }; + int _trackedEntityStabilityCount { 0 }; + + quint64 _startTime { 0 }; struct SequenceLessThan { bool operator()(const int& a, const int& b) const; diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 2e679e0947..75f17def20 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -39,6 +39,7 @@ WindowScriptingInterface::WindowScriptingInterface() { connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &WindowScriptingInterface::disconnectedFromDomain); connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); + connect(&domainHandler, &DomainHandler::redirectErrorStateChanged, this, &WindowScriptingInterface::redirectErrorStateChanged); connect(qApp, &Application::svoImportRequested, [this](const QString& urlString) { static const QMetaMethod svoImportRequestedSignal = diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index ddd7159f23..f6a5a5ef74 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -611,6 +611,14 @@ signals: */ void domainConnectionRefused(const QString& reasonMessage, int reasonCode, const QString& extraInfo); + /**jsdoc + * Triggered when you try to visit a domain but are redirected into the error state. + * @function Window.redirectErrorStateChanged + * @param {boolean} isInErrorState - If true, the user has been redirected to the error URL. + * @returns {Signal} + */ + void redirectErrorStateChanged(bool isInErrorState); + /**jsdoc * Triggered when a still snapshot has been taken by calling {@link Window.takeSnapshot|takeSnapshot} with * includeAnimated = false or {@link Window.takeSecondaryCameraSnapshot|takeSecondaryCameraSnapshot}. diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 5fb4ef3156..d78d83bc09 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -206,11 +206,13 @@ float AvatarData::getDistanceBasedMinRotationDOT(glm::vec3 viewerPosition) const if (distance < AVATAR_DISTANCE_LEVEL_1) { result = AVATAR_MIN_ROTATION_DOT; } else if (distance < AVATAR_DISTANCE_LEVEL_2) { - result = ROTATION_CHANGE_15D; + result = ROTATION_CHANGE_2D; } else if (distance < AVATAR_DISTANCE_LEVEL_3) { - result = ROTATION_CHANGE_45D; + result = ROTATION_CHANGE_4D; } else if (distance < AVATAR_DISTANCE_LEVEL_4) { - result = ROTATION_CHANGE_90D; + result = ROTATION_CHANGE_6D; + } else if (distance < AVATAR_DISTANCE_LEVEL_5) { + result = ROTATION_CHANGE_15D; } return result; } @@ -1802,15 +1804,24 @@ QUrl AvatarData::getWireSafeSkeletonModelURL() const { qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion) { - qint64 bytesWritten = 0; - bytesWritten += destination.writePrimitive(traitType); - if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) { - bytesWritten += destination.writePrimitive(traitVersion); - } + qint64 bytesWritten = 0; if (traitType == AvatarTraits::SkeletonModelURL) { + QByteArray encodedSkeletonURL = getWireSafeSkeletonModelURL().toEncoded(); + + if (encodedSkeletonURL.size() > AvatarTraits::MAXIMUM_TRAIT_SIZE) { + qWarning() << "Refusing to pack simple trait" << traitType << "of size" << encodedSkeletonURL.size() + << "bytes since it exceeds the maximum size" << AvatarTraits::MAXIMUM_TRAIT_SIZE << "bytes"; + return 0; + } + + bytesWritten += destination.writePrimitive(traitType); + + if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) { + bytesWritten += destination.writePrimitive(traitVersion); + } AvatarTraits::TraitWireSize encodedURLSize = encodedSkeletonURL.size(); bytesWritten += destination.writePrimitive(encodedURLSize); @@ -1825,14 +1836,6 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr ExtendedIODevice& destination, AvatarTraits::TraitVersion traitVersion) { qint64 bytesWritten = 0; - bytesWritten += destination.writePrimitive(traitType); - - if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) { - bytesWritten += destination.writePrimitive(traitVersion); - } - - bytesWritten += destination.write(traitInstanceID.toRfc4122()); - if (traitType == AvatarTraits::AvatarEntity) { // grab a read lock on the avatar entities and check for entity data for the given ID QByteArray entityBinaryData; @@ -1843,6 +1846,20 @@ qint64 AvatarData::packTraitInstance(AvatarTraits::TraitType traitType, AvatarTr } }); + if (entityBinaryData.size() > AvatarTraits::MAXIMUM_TRAIT_SIZE) { + qWarning() << "Refusing to pack instanced trait" << traitType << "of size" << entityBinaryData.size() + << "bytes since it exceeds the maximum size " << AvatarTraits::MAXIMUM_TRAIT_SIZE << "bytes"; + return 0; + } + + bytesWritten += destination.writePrimitive(traitType); + + if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) { + bytesWritten += destination.writePrimitive(traitVersion); + } + + bytesWritten += destination.write(traitInstanceID.toRfc4122()); + if (!entityBinaryData.isNull()) { AvatarTraits::TraitWireSize entityBinarySize = entityBinaryData.size(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 860772b7c9..46489451f7 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -309,16 +309,19 @@ const float AVATAR_SEND_FULL_UPDATE_RATIO = 0.02f; const float AVATAR_MIN_ROTATION_DOT = 0.9999999f; const float AVATAR_MIN_TRANSLATION = 0.0001f; -const float ROTATION_CHANGE_15D = 0.9914449f; -const float ROTATION_CHANGE_45D = 0.9238795f; -const float ROTATION_CHANGE_90D = 0.7071068f; -const float ROTATION_CHANGE_179D = 0.0087266f; - -const float AVATAR_DISTANCE_LEVEL_1 = 10.0f; -const float AVATAR_DISTANCE_LEVEL_2 = 100.0f; -const float AVATAR_DISTANCE_LEVEL_3 = 1000.0f; -const float AVATAR_DISTANCE_LEVEL_4 = 10000.0f; +// quaternion dot products +const float ROTATION_CHANGE_2D = 0.99984770f; // 2 degrees +const float ROTATION_CHANGE_4D = 0.99939083f; // 4 degrees +const float ROTATION_CHANGE_6D = 0.99862953f; // 6 degrees +const float ROTATION_CHANGE_15D = 0.99144486f; // 15 degrees +const float ROTATION_CHANGE_179D = 0.00872653f; // 179 degrees +// rotation culling distance thresholds +const float AVATAR_DISTANCE_LEVEL_1 = 12.5f; // meters +const float AVATAR_DISTANCE_LEVEL_2 = 16.6f; // meters +const float AVATAR_DISTANCE_LEVEL_3 = 25.0f; // meters +const float AVATAR_DISTANCE_LEVEL_4 = 50.0f; // meters +const float AVATAR_DISTANCE_LEVEL_5 = 200.0f; // meters // Where one's own Avatar begins in the world (will be overwritten if avatar data file is found). // This is the start location in the Sandbox (xyz: 6270, 211, 6000). diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index af65a32ef5..b9c6899e09 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -339,7 +339,7 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess // grab the last trait versions for this avatar auto& lastProcessedVersions = _processedTraitVersions[avatarID]; - while (traitType != AvatarTraits::NullTrait) { + while (traitType != AvatarTraits::NullTrait && message->getBytesLeftToRead() > 0) { AvatarTraits::TraitVersion packetTraitVersion; message->readPrimitive(&packetTraitVersion); @@ -380,7 +380,7 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer mess } } - if (skipBinaryTrait) { + if (skipBinaryTrait && traitBinarySize > 0) { // we didn't read this trait because it was older or because we didn't have an avatar to process it for message->seek(message->getPosition() + traitBinarySize); } diff --git a/libraries/avatars/src/AvatarTraits.h b/libraries/avatars/src/AvatarTraits.h index f0c807a432..5e28515d12 100644 --- a/libraries/avatars/src/AvatarTraits.h +++ b/libraries/avatars/src/AvatarTraits.h @@ -39,6 +39,7 @@ namespace AvatarTraits { using TraitWireSize = int16_t; const TraitWireSize DELETED_TRAIT_SIZE = -1; + const TraitWireSize MAXIMUM_TRAIT_SIZE = INT16_MAX; inline qint64 packInstancedTraitDelete(TraitType traitType, TraitInstanceID instanceID, ExtendedIODevice& destination, TraitVersion traitVersion = NULL_TRAIT_VERSION) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index dbbf8af4b9..6e82d26f29 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -310,10 +310,10 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r } auto entityID = entity->getEntityItemID(); - processedIds.insert(entityID); auto renderable = EntityRenderer::addToScene(*this, entity, scene, transaction); if (renderable) { _entitiesInScene.insert({ entityID, renderable }); + processedIds.insert(entityID); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index dbbfacea69..095283b1e5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -315,6 +315,14 @@ void RenderableModelEntityItem::getCollisionGeometryResource() { _compoundShapeResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); } +bool RenderableModelEntityItem::computeShapeFailedToLoad() { + if (!_compoundShapeResource) { + getCollisionGeometryResource(); + } + + return (_compoundShapeResource && _compoundShapeResource->isFailed()); +} + void RenderableModelEntityItem::setShapeType(ShapeType type) { ModelEntityItem::setShapeType(type); if (getShapeType() == SHAPE_TYPE_COMPOUND) { @@ -343,7 +351,6 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { bool RenderableModelEntityItem::isReadyToComputeShape() const { ShapeType type = getShapeType(); - auto model = getModel(); if (type == SHAPE_TYPE_COMPOUND) { if (!model || getCompoundShapeURL().isEmpty()) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index fa49624f7e..b5f9d9f833 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -81,6 +81,7 @@ public: virtual bool isReadyToComputeShape() const override; virtual void computeShapeInfo(ShapeInfo& shapeInfo) override; + bool computeShapeFailedToLoad(); virtual bool contains(const glm::vec3& point) const override; void stopModelOverrideIfNoParent(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 1a263fba79..f51a3f7740 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -104,6 +104,10 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi _networkTexture.reset(); }); } + + withWriteLock([&] { + entity->setVisuallyReady(true); + }); } else { bool textureNeedsUpdate = resultWithReadLock([&]{ return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures); @@ -113,6 +117,12 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi _networkTexture = DependencyManager::get()->getTexture(_particleProperties.textures); }); } + + if (_networkTexture) { + withWriteLock([&] { + entity->setVisuallyReady(_networkTexture->isFailed() || _networkTexture->isLoaded()); + }); + } } void* key = (void*)this; diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index b19e1c33d3..f107bcae6e 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -104,7 +104,7 @@ protected: QMutex _dynamicsMutex { QMutex::Recursive }; protected: - SetOfEntities _deadEntities; + SetOfEntities _deadEntities; // dead entities that might still be in the _entityTree private: void moveSimpleKinematics(); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 975acf153a..cea3e94ef0 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -166,6 +166,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte { _type = EntityTypes::ParticleEffect; setColor(DEFAULT_COLOR); + _visuallyReady = false; } void ParticleEffectEntityItem::setAlpha(float alpha) { @@ -777,4 +778,4 @@ particle::Properties ParticleEffectEntityItem::getParticleProperties() const { } return result; -} \ No newline at end of file +} diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index f669e8aaef..4d6297303b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -551,6 +551,11 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, image::TextureUsage::Type type, MapChannel channel) { + + if (baseUrl.isEmpty()) { + return nullptr; + } + const auto url = getTextureUrl(baseUrl, fbxTexture); const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxNumPixels); _textures[channel] = Texture { fbxTexture.name, texture }; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 8085039b02..f8ab8ceaec 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -161,8 +161,14 @@ void AddressManager::storeCurrentAddress() { // be loaded over http(s) // url.scheme() == URL_SCHEME_HTTP || // url.scheme() == URL_SCHEME_HTTPS || + bool isInErrorState = DependencyManager::get()->getDomainHandler().isInErrorState(); if (isConnected()) { - currentAddressHandle.set(url); + if (isInErrorState) { + // save the last address visited before the problem url. + currentAddressHandle.set(lastAddress()); + } else { + currentAddressHandle.set(url); + } } else { qCWarning(networking) << "Ignoring attempt to save current address because not connected to domain:" << url; } @@ -861,6 +867,10 @@ void AddressManager::goToUser(const QString& username, bool shouldMatchOrientati QByteArray(), nullptr, requestParams); } +bool AddressManager::canGoBack() const { + return (_backStack.size() > 0); +} + void AddressManager::refreshPreviousLookup() { // if we have a non-empty previous lookup, fire it again now (but don't re-store it in the history) if (!_previousAPILookup.isEmpty()) { diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 17041a5fd7..5318822cdc 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -254,6 +254,12 @@ public slots: */ void goToLastAddress() { handleUrl(_lastVisitedURL, LookupTrigger::AttemptedRefresh); } + /**jsdoc + * Returns if going back is possible. + * @function location.canGoBack + */ + bool canGoBack() const; + /**jsdoc * Refresh the current address, e.g., after connecting to a domain in order to position the user to the desired location. * @function location.refreshPreviousLookup diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index df34a1fb59..615546b410 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -123,6 +123,7 @@ void DomainHandler::hardReset() { softReset(); _isInErrorState = false; + emit redirectErrorStateChanged(_isInErrorState); qCDebug(networking) << "Hard reset in NodeList DomainHandler."; _pendingDomainID = QUuid(); @@ -138,6 +139,11 @@ void DomainHandler::hardReset() { _pendingPath.clear(); } +bool DomainHandler::isHardRefusal(int reasonCode) { + return (reasonCode == (int)ConnectionRefusedReason::ProtocolMismatch || reasonCode == (int)ConnectionRefusedReason::NotAuthorized || + reasonCode == (int)ConnectionRefusedReason::TimedOut); +} + bool DomainHandler::getInterstitialModeEnabled() const { return _interstitialModeSettingLock.resultWithReadLock([&] { return _enableInterstitialMode.get(); @@ -327,6 +333,7 @@ void DomainHandler::setIsConnected(bool isConnected) { _isConnected = isConnected; if (_isConnected) { + _lastDomainConnectionError = -1; emit connectedToDomain(_domainURL); if (_domainURL.scheme() == URL_SCHEME_HIFI && !_domainURL.host().isEmpty()) { @@ -358,9 +365,11 @@ void DomainHandler::loadedErrorDomain(std::map namedPaths) { void DomainHandler::setRedirectErrorState(QUrl errorUrl, QString reasonMessage, int reasonCode, const QString& extraInfo) { _lastDomainConnectionError = reasonCode; - if (getInterstitialModeEnabled()) { + if (getInterstitialModeEnabled() && isHardRefusal(reasonCode)) { _errorDomainURL = errorUrl; _isInErrorState = true; + qCDebug(networking) << "Error connecting to domain: " << reasonMessage; + emit redirectErrorStateChanged(_isInErrorState); emit redirectToErrorDomainURL(_errorDomainURL); } else { emit domainConnectionRefused(reasonMessage, reasonCode, extraInfo); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index e9ec20ba2e..ddd23339df 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -187,8 +187,6 @@ private slots: signals: void domainURLChanged(QUrl domainURL); - void domainConnectionErrorChanged(int reasonCode); - // NOTE: the emission of completedSocketDiscovery does not mean a connection to DS is established // It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on void completedSocketDiscovery(); @@ -205,6 +203,7 @@ signals: void domainConnectionRefused(QString reasonMessage, int reason, const QString& extraInfo); void redirectToErrorDomainURL(QUrl errorDomainURL); + void redirectErrorStateChanged(bool isInErrorState); void limitOfSilentDomainCheckInsReached(); @@ -213,6 +212,8 @@ private: void sendDisconnectPacket(); void hardReset(); + bool isHardRefusal(int reasonCode); + QUuid _uuid; Node::LocalID _localID; QUrl _domainURL; @@ -230,7 +231,7 @@ private: QString _pendingPath; QTimer _settingsTimer; mutable ReadWriteLockable _interstitialModeSettingLock; - Setting::Handle _enableInterstitialMode{ "enableInterstitialMode", false }; + Setting::Handle _enableInterstitialMode{ "enableInterstitialMode", true }; QSet _domainConnectionRefusals; bool _hasCheckedForAccessToken { false }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index e458ffab7e..917a4ca791 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -332,7 +332,6 @@ void NodeList::sendDomainServerCheckIn() { qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort; _domainHandler.setPort(domainPort); } - } // check if we're missing a keypair we need to verify ourselves with the domain-server diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 2004f8953d..ab8bfb8290 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -79,6 +79,9 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { _deadEntities.insert(entity); } } + if (entity->getClientOnly()) { + _deadAvatarEntities.insert(entity); + } } void PhysicalEntitySimulation::removeOwnershipData(EntityMotionState* motionState) { @@ -123,6 +126,11 @@ void PhysicalEntitySimulation::takeDeadEntities(SetOfEntities& deadEntities) { _deadEntities.clear(); } +void PhysicalEntitySimulation::takeDeadAvatarEntities(SetOfEntities& deadEntities) { + _deadAvatarEntities.swap(deadEntities); + _deadAvatarEntities.clear(); +} + void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine QMutexLocker lock(&_mutex); diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index fdf996df25..843069e247 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -60,6 +60,7 @@ public: virtual void applyDynamicChanges() override; virtual void takeDeadEntities(SetOfEntities& deadEntities) override; + void takeDeadAvatarEntities(SetOfEntities& deadEntities); signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); @@ -112,6 +113,7 @@ private: VectorOfEntityMotionStates _owned; VectorOfEntityMotionStates _bids; + SetOfEntities _deadAvatarEntities; workload::SpacePointer _space; uint64_t _nextBidExpiry; uint32_t _lastStepSendPackets { 0 }; diff --git a/plugins/hifiCodec/CMakeLists.txt b/plugins/hifiCodec/CMakeLists.txt index 9ecaf7b511..0d4f093fc2 100644 --- a/plugins/hifiCodec/CMakeLists.txt +++ b/plugins/hifiCodec/CMakeLists.txt @@ -9,10 +9,7 @@ set(TARGET_NAME hifiCodec) setup_hifi_client_server_plugin() link_hifi_libraries(audio plugins) -add_dependency_external_projects(hifiAudioCodec) -target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES}) - +target_hifiAudioCodec() if (BUILD_SERVER) install_beside_console() endif () diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 6da037a712..9efb040624 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -39,8 +39,9 @@ var DEFAULT_SCRIPTS_SEPARATE = [ //"system/chat.js" ]; -if (Settings.getValue("enableInterstitialMode", false)) { - DEFAULT_SCRIPTS_SEPARATE.push("system/interstitialPage.js"); +if (Window.interstitialModeEnabled) { + DEFAULT_SCRIPTS_COMBINED.push("system/interstitialPage.js"); + DEFAULT_SCRIPTS_COMBINED.push("system/redirectOverlays.js"); } // add a menu item for debugging diff --git a/scripts/developer/utilities/render/textureMonitor.qml b/scripts/developer/utilities/render/textureMonitor.qml index 97cc577ff9..b01a390fa8 100644 --- a/scripts/developer/utilities/render/textureMonitor.qml +++ b/scripts/developer/utilities/render/textureMonitor.qml @@ -75,4 +75,4 @@ Item { } } -} \ No newline at end of file +} diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 444a18ced5..efb842a9bb 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -139,8 +139,8 @@ function AppUi(properties) { that.isOpen = false; } } - console.debug(that.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type + - "\nNew screen URL: " + url + "\nCurrent app open status: " + that.isOpen + "\n"); + // console.debug(that.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type + + // "\nNew screen URL: " + url + "\nCurrent app open status: " + that.isOpen + "\n"); }; // Overwrite with the given properties: diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 5e798ed680..2e73526728 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -110,6 +110,8 @@ Script.include("/~/system/libraries/Xform.js"); this.reticleMinY = MARGIN; this.reticleMaxY; + this.ignoredEntities = []; + var ACTION_TTL = 15; // seconds var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object @@ -314,6 +316,17 @@ Script.include("/~/system/libraries/Xform.js"); return point2d; }; + this.restoreIgnoredEntities = function() { + for (var i = 0; i < this.ignoredEntities; i++) { + var data = { + action: 'remove', + id: this.ignoredEntities[i] + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + } + this.ignoredEntities = []; + }; + this.notPointingAtEntity = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; var entityProperty = Entities.getEntityProperties(intersection.objectID); @@ -323,6 +336,15 @@ Script.include("/~/system/libraries/Xform.js"); if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { return true; + } else if (intersection.type === Picks.INTERSECTED_ENTITY && !Window.isPhysicsEnabled()) { + // add to ignored items. + var data = { + action: 'add', + id: intersection.objectID + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + this.ignoredEntities.push(intersection.objectID); + } return false; }; @@ -383,6 +405,7 @@ Script.include("/~/system/libraries/Xform.js"); this.isReady = function (controllerData) { if (HMD.active) { if (this.notPointingAtEntity(controllerData)) { + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } @@ -394,9 +417,11 @@ Script.include("/~/system/libraries/Xform.js"); return makeRunningValues(true, [], []); } else { this.destroyContextOverlay(); + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } } + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); }; @@ -407,6 +432,7 @@ Script.include("/~/system/libraries/Xform.js"); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); this.highlightedEntity = null; + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } this.intersectionDistance = controllerData.rayPicks[this.hand].distance; @@ -437,6 +463,7 @@ Script.include("/~/system/libraries/Xform.js"); if (nearGrabReadiness[k].active && (nearGrabReadiness[k].targets[0] === this.grabbedThingID || HMD.tabletID && nearGrabReadiness[k].targets[0] === HMD.tabletID)) { this.endFarGrabAction(); + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } } @@ -448,6 +475,7 @@ Script.include("/~/system/libraries/Xform.js"); for (var j = 0; j < nearGrabReadiness.length; j++) { if (nearGrabReadiness[j].active) { this.endFarGrabAction(); + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } } @@ -466,6 +494,7 @@ Script.include("/~/system/libraries/Xform.js"); ]); if (targetProps.href !== "") { AddressManager.handleLookupString(targetProps.href); + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } @@ -583,6 +612,7 @@ Script.include("/~/system/libraries/Xform.js"); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); this.highlightedEntity = null; + this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } } diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 0c786dad87..19e603b4ab 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -37,6 +37,8 @@ var tablet = null; var button = null; + var errorConnectingToDomain = false; + // Tips have a character limit of 69 var userTips = [ "Tip: Visit TheSpot to explore featured domains!", @@ -48,7 +50,7 @@ "Tip: Use the Create app to import models and create custom entities.", "Tip: We're open source! Feel free to contribute to our code on GitHub!", "Tip: What emotes have you used in the Emote app?", - "Tip: Take and share your snapshots with the everyone using the Snap app.", + "Tip: Take and share your snapshots with everyone using the Snap app.", "Tip: Did you know you can show websites in-world by creating a web entity?", "Tip: Find out more information about domains by visiting our website!", "Tip: Did you know you can get cool new apps from the Marketplace?", @@ -125,7 +127,7 @@ localPosition: { x: 0.0 , y: -1.6, z: 0.0 }, text: toolTip, textAlpha: 1, - backgroundAlpha: 1, + backgroundAlpha: 0.00393, lineHeight: 0.13, visible: isVisible, ignoreRayIntersection: true, @@ -135,17 +137,47 @@ parentID: anchorOverlay }); - var loadingToTheSpotID = Overlays.addOverlay("image3d", { + var loadingToTheSpotText = Overlays.addOverlay("text3d", { name: "Loading-Destination-Card-Text", - localPosition: { x: 0.0 , y: -1.5, z: -0.3 }, - url: Script.resourcesPath() + "images/interstitialPage/goTo_button.png", + localPosition: { x: 0.0 , y: -1.687, z: -0.3 }, + text: "Go To TheSpot", + textAlpha: 1, + backgroundAlpha: 0.00393, + lineHeight: 0.10, + visible: isVisible, + ignoreRayIntersection: true, + dimensions: {x: 1, y: 0.17}, + drawInFront: true, + grabbable: false, + localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }), + parentID: anchorOverlay + }); + + var loadingToTheSpotID = Overlays.addOverlay("image3d", { + name: "Loading-Destination-Card-GoTo-Image", + localPosition: { x: 0.0 , y: -1.75, z: -0.3 }, + url: Script.resourcesPath() + "images/interstitialPage/button.png", alpha: 1, visible: isVisible, emissive: true, ignoreRayIntersection: false, drawInFront: true, grabbable: false, - localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }), + localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }), + parentID: anchorOverlay + }); + + var loadingToTheSpotHoverID = Overlays.addOverlay("image3d", { + name: "Loading-Destination-Card-GoTo-Image-Hover", + localPosition: { x: 0.0 , y: -1.75, z: -0.3 }, + url: Script.resourcesPath() + "images/interstitialPage/button_hover.png", + alpha: 1, + visible: false, + emissive: true, + ignoreRayIntersection: false, + drawInFront: true, + grabbable: false, + localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }), parentID: anchorOverlay }); @@ -185,10 +217,11 @@ var currentDomain = "no domain"; var timer = null; var target = 0; + var textureMemSizeStabilityCount = 0; + var textureMemSizeAtLastCheck = 0; var connectionToDomainFailed = false; - function getAnchorLocalYOffset() { var loadingSpherePosition = Overlays.getProperty(loadingSphereID, "position"); var loadingSphereOrientation = Overlays.getProperty(loadingSphereID, "rotation"); @@ -227,6 +260,8 @@ updateOverlays(false); startAudio(); target = 0; + textureMemSizeStabilityCount = 0; + textureMemSizeAtLastCheck = 0; currentProgress = 0.1; connectionToDomainFailed = false; previousCameraMode = Camera.mode; @@ -235,6 +270,13 @@ } } + function toggleInterstitialPage(isInErrorState) { + errorConnectingToDomain = isInErrorState; + if (!errorConnectingToDomain) { + domainChanged(location); + } + } + function startAudio() { sample = Audio.playSound(tune, { localOnly: true, @@ -251,11 +293,12 @@ function domainChanged(domain) { if (domain !== currentDomain) { MyAvatar.restoreAnimation(); + resetValues(); var name = location.placename; domainName = name.charAt(0).toUpperCase() + name.slice(1); var doRequest = true; if (name.length === 0 && location.href === "file:///~/serverless/tutorial.json") { - domainName = "Serveless Domain (Tutorial)"; + domainName = "Serverless Domain (Tutorial)"; doRequest = false; } var domainNameLeftMargin = getLeftMargin(domainNameTextID, domainName); @@ -306,8 +349,30 @@ var THE_PLACE = (HifiAbout.buildVersion === "dev") ? "hifi://TheSpot-dev": "hifi://TheSpot"; function clickedOnOverlay(overlayID, event) { - if (loadingToTheSpotID === overlayID) { + if (loadingToTheSpotHoverID === overlayID) { location.handleLookupString(THE_PLACE); + Overlays.editOverlay(loadingToTheSpotHoverID, {visible: false}); + Overlays.editOverlay(loadingToTheSpotID, {visible: true}); + } + } + + function onEnterOverlay(overlayID, event) { + if (currentDomain === "no domain") { + return; + } + if (overlayID === loadingToTheSpotID) { + Overlays.editOverlay(loadingToTheSpotID, {visible: false}); + Overlays.editOverlay(loadingToTheSpotHoverID, {visible: true}); + } + } + + function onLeaveOverlay(overlayID, event) { + if (currentDomain === "no domain") { + return; + } + if (overlayID === loadingToTheSpotHoverID) { + Overlays.editOverlay(loadingToTheSpotHoverID, {visible: false}); + Overlays.editOverlay(loadingToTheSpotID, {visible: true}); } } @@ -340,6 +405,7 @@ renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = physicsEnabled; renderViewTask.getConfig("LightingModel")["enablePointLight"] = physicsEnabled; Overlays.editOverlay(loadingSphereID, mainSphereProperties); + Overlays.editOverlay(loadingToTheSpotText, properties); Overlays.editOverlay(loadingToTheSpotID, properties); Overlays.editOverlay(domainNameTextID, properties); Overlays.editOverlay(domainDescription, domainTextProperties); @@ -347,10 +413,11 @@ Overlays.editOverlay(loadingBarPlacard, properties); Overlays.editOverlay(loadingBarProgress, loadingBarProperties); - - Menu.setIsOptionChecked("Show Overlays", physicsEnabled); - if (!HMD.active) { - toolbar.writeProperty("visible", physicsEnabled); + if (!DEBUG) { + Menu.setIsOptionChecked("Show Overlays", physicsEnabled); + if (!HMD.active) { + toolbar.writeProperty("visible", physicsEnabled); + } } resetValues(); @@ -360,7 +427,6 @@ } } - function scaleInterstitialPage(sensorToWorldScale) { var yOffset = getAnchorLocalYOffset(); var localPosition = { @@ -372,19 +438,53 @@ Overlays.editOverlay(anchorOverlay, { localPosition: localPosition }); } + function sleep(milliseconds) { + var start = new Date().getTime(); + for (var i = 0; i < 1e7; i++) { + if ((new Date().getTime() - start) > milliseconds){ + break; + } + } + } + function update() { + var renderStats = Render.getConfig("Stats"); var physicsEnabled = Window.isPhysicsEnabled(); var thisInterval = Date.now(); var deltaTime = (thisInterval - lastInterval); lastInterval = thisInterval; var domainLoadingProgressPercentage = Window.domainLoadingProgress(); - - var progress = MIN_LOADING_PROGRESS * domainLoadingProgressPercentage; + var progress = ((TOTAL_LOADING_PROGRESS * 0.4) * domainLoadingProgressPercentage); if (progress >= target) { target = progress; } + if (currentProgress >= (TOTAL_LOADING_PROGRESS * 0.4)) { + var textureResourceGPUMemSize = renderStats.textureResourceGPUMemSize; + var texturePopulatedGPUMemSize = renderStats.textureResourcePopulatedGPUMemSize; + + if (textureMemSizeAtLastCheck === textureResourceGPUMemSize) { + textureMemSizeStabilityCount++; + } else { + textureMemSizeStabilityCount = 0; + } + + textureMemSizeAtLastCheck = textureResourceGPUMemSize; + + if (textureMemSizeStabilityCount >= 20) { + + if (textureResourceGPUMemSize > 0) { + // print((texturePopulatedGPUMemSize / textureResourceGPUMemSize)); + var gpuPercantage = (TOTAL_LOADING_PROGRESS * 0.6) * (texturePopulatedGPUMemSize / textureResourceGPUMemSize); + var totalProgress = progress + gpuPercantage; + if (totalProgress >= target) { + target = totalProgress; + } + } + } + } + if ((physicsEnabled && (currentProgress < TOTAL_LOADING_PROGRESS))) { target = TOTAL_LOADING_PROGRESS; } @@ -399,30 +499,40 @@ }; Overlays.editOverlay(loadingBarProgress, properties); - if ((physicsEnabled && (currentProgress >= (TOTAL_LOADING_PROGRESS - EPSILON)))) { + + if (errorConnectingToDomain) { + updateOverlays(errorConnectingToDomain); + // setting hover id to invisible + Overlays.editOverlay(loadingToTheSpotHoverID, {visible: false}); + endAudio(); + currentDomain = "no domain"; + timer = null; + // The toolbar doesn't become visible in time to match the speed of + // the signal handling of redirectErrorStateChanged in both this script + // and the redirectOverlays.js script. Use a sleep function to ensure + // the toolbar becomes visible again. + sleep(300); + if (!HMD.active) { + toolbar.writeProperty("visible", true); + } + return; + } else if ((physicsEnabled && (currentProgress >= (TOTAL_LOADING_PROGRESS - EPSILON)))) { updateOverlays((physicsEnabled || connectionToDomainFailed)); + // setting hover id to invisible + Overlays.editOverlay(loadingToTheSpotHoverID, {visible: false}); endAudio(); currentDomain = "no domain"; timer = null; return; } - timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS); } var whiteColor = {red: 255, green: 255, blue: 255}; var greyColor = {red: 125, green: 125, blue: 125}; Overlays.mouseReleaseOnOverlay.connect(clickedOnOverlay); - Overlays.hoverEnterOverlay.connect(function(overlayID, event) { - if (overlayID === loadingToTheSpotID) { - Overlays.editOverlay(loadingToTheSpotID, { color: greyColor }); - } - }); + Overlays.hoverEnterOverlay.connect(onEnterOverlay); - Overlays.hoverLeaveOverlay.connect(function(overlayID, event) { - if (overlayID === loadingToTheSpotID) { - Overlays.editOverlay(loadingToTheSpotID, { color: whiteColor }); - } - }); + Overlays.hoverLeaveOverlay.connect(onLeaveOverlay); location.hostChanged.connect(domainChanged); location.lookupResultsFinished.connect(function() { @@ -430,6 +540,7 @@ connectionToDomainFailed = !location.isConnected; }, 1200); }); + Window.redirectErrorStateChanged.connect(toggleInterstitialPage); MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage); MyAvatar.sessionUUIDChanged.connect(function() { @@ -448,9 +559,17 @@ }); } + // set left margin of text. + var loadingTextProperties = { + leftMargin: getLeftMargin(loadingToTheSpotText, "Go To TheSpot") + 0.045 + }; + + Overlays.editOverlay(loadingToTheSpotText, loadingTextProperties); + function cleanup() { Overlays.deleteOverlay(loadingSphereID); Overlays.deleteOverlay(loadingToTheSpotID); + Overlays.deleteOverlay(loadingToTheSpotHoverID); Overlays.deleteOverlay(domainNameTextID); Overlays.deleteOverlay(domainDescription); Overlays.deleteOverlay(domainToolTip); diff --git a/scripts/system/redirectOverlays.js b/scripts/system/redirectOverlays.js new file mode 100644 index 0000000000..b1180e0cd0 --- /dev/null +++ b/scripts/system/redirectOverlays.js @@ -0,0 +1,257 @@ +"use strict"; +(function() { + + var ERROR_MESSAGE_MAP = [ + "Oops! Protocol version mismatch.", + "Oops! Not authorized to join domain.", + "Oops! Connection timed out.", + "Oops! Something went wrong." + ]; + + var PROTOCOL_VERSION_MISMATCH = 1; + var NOT_AUTHORIZED = 3; + var TIMEOUT = 5; + var hardRefusalErrors = [PROTOCOL_VERSION_MISMATCH, + NOT_AUTHORIZED, TIMEOUT]; + var timer = null; + var isErrorState = false; + + function getOopsText() { + var error = Window.getLastDomainConnectionError(); + var errorMessageMapIndex = hardRefusalErrors.indexOf(error); + if (error === -1) { + // not an error. + return ""; + } else if (errorMessageMapIndex >= 0) { + return ERROR_MESSAGE_MAP[errorMessageMapIndex]; + } else { + // some other text. + return ERROR_MESSAGE_MAP[4]; + } + }; + + var oopsDimensions = {x: 4.2, y: 0.8}; + + var redirectOopsText = Overlays.addOverlay("text3d", { + name: "oopsText", + position: {x: 0, y: 1.6763916015625, z: 1.45927095413208}, + rotation: {x: -4.57763671875e-05, y: 0.4957197904586792, z: -7.62939453125e-05, w: 0.8684672117233276}, + text: getOopsText(), + textAlpha: 1, + backgroundColor: {x: 0, y: 0, z:0}, + backgroundAlpha: 0, + lineHeight: 0.10, + leftMargin: 0.538373570564886, + visible: false, + emissive: true, + ignoreRayIntersection: true, + dimensions: oopsDimensions, + grabbable: false, + }); + + var tryAgainImageNeutral = Overlays.addOverlay("image3d", { + name: "tryAgainImage", + localPosition: {x: -0.6, y: -0.6, z: 0.0}, + url: Script.resourcesPath() + "images/interstitialPage/button.png", + alpha: 1, + visible: false, + emissive: true, + ignoreRayIntersection: false, + grabbable: false, + orientation: Overlays.getProperty(redirectOopsText, "orientation"), + parentID: redirectOopsText + }); + + var tryAgainImageHover = Overlays.addOverlay("image3d", { + name: "tryAgainImageHover", + localPosition: {x: -0.6, y: -0.6, z: 0.0}, + url: Script.resourcesPath() + "images/interstitialPage/button_hover.png", + alpha: 1, + visible: false, + emissive: true, + ignoreRayIntersection: false, + grabbable: false, + orientation: Overlays.getProperty(redirectOopsText, "orientation"), + parentID: redirectOopsText + }); + + var tryAgainText = Overlays.addOverlay("text3d", { + name: "tryAgainText", + localPosition: {x: -0.6, y: -0.962, z: 0.0}, + text: "Try Again", + textAlpha: 1, + backgroundAlpha: 0.00393, + lineHeight: 0.08, + visible: false, + emissive: true, + ignoreRayIntersection: true, + grabbable: false, + orientation: Overlays.getProperty(redirectOopsText, "orientation"), + parentID: redirectOopsText + }); + + var backImageNeutral = Overlays.addOverlay("image3d", { + name: "backImage", + localPosition: {x: 0.6, y: -0.6, z: 0.0}, + url: Script.resourcesPath() + "images/interstitialPage/button.png", + alpha: 1, + visible: false, + emissive: true, + ignoreRayIntersection: false, + grabbable: false, + orientation: Overlays.getProperty(redirectOopsText, "orientation"), + parentID: redirectOopsText + }); + + var backImageHover = Overlays.addOverlay("image3d", { + name: "backImageHover", + localPosition: {x: 0.6, y: -0.6, z: 0.0}, + url: Script.resourcesPath() + "images/interstitialPage/button_hover.png", + alpha: 1, + visible: false, + emissive: true, + ignoreRayIntersection: false, + grabbable: false, + orientation: Overlays.getProperty(redirectOopsText, "orientation"), + parentID: redirectOopsText + }); + + var backText = Overlays.addOverlay("text3d", { + name: "backText", + localPosition: {x: 0.6, y: -0.962, z: 0.0}, + text: "Back", + textAlpha: 1, + backgroundAlpha: 0.00393, + lineHeight: 0.08, + visible: false, + emissive: true, + ignoreRayIntersection: true, + grabbable: false, + orientation: Overlays.getProperty(redirectOopsText, "orientation"), + parentID: redirectOopsText + }); + + function toggleOverlays(isInErrorState) { + isErrorState = isInErrorState; + if (!isInErrorState) { + var properties = { + visible: false + }; + + Overlays.editOverlay(redirectOopsText, properties); + Overlays.editOverlay(tryAgainImageNeutral, properties); + Overlays.editOverlay(tryAgainImageHover, properties); + Overlays.editOverlay(backImageNeutral, properties); + Overlays.editOverlay(backImageHover, properties); + Overlays.editOverlay(tryAgainText, properties); + Overlays.editOverlay(backText, properties); + return; + } + var oopsText = getOopsText(); + // if oopsText === "", it was a success. + var overlaysVisible = (oopsText !== ""); + // for catching init or if error state were to be different. + isErrorState = overlaysVisible; + var properties = { + visible: overlaysVisible + }; + + var textWidth = Overlays.textSize(redirectOopsText, oopsText).width; + var textOverlayWidth = oopsDimensions.x; + + var oopsTextProperties = { + visible: overlaysVisible, + text: oopsText, + textAlpha: overlaysVisible, + // either visible or invisible. 0 doesn't work in Mac. + backgroundAlpha: overlaysVisible * 0.00393, + leftMargin: (textOverlayWidth - textWidth) / 2 + }; + + var tryAgainTextWidth = Overlays.textSize(tryAgainText, "Try Again").width; + var tryAgainImageWidth = Overlays.getProperty(tryAgainImageNeutral, "dimensions").x; + + var tryAgainTextProperties = { + visible: overlaysVisible, + leftMargin: (tryAgainImageWidth - tryAgainTextWidth) / 2 + }; + + var backTextWidth = Overlays.textSize(backText, "Back").width; + var backImageWidth = Overlays.getProperty(backImageNeutral, "dimensions").x; + + var backTextProperties = { + visible: overlaysVisible, + leftMargin: (backImageWidth - backTextWidth) / 2 + }; + + Overlays.editOverlay(redirectOopsText, oopsTextProperties); + Overlays.editOverlay(tryAgainImageNeutral, properties); + Overlays.editOverlay(backImageNeutral, properties); + Overlays.editOverlay(tryAgainImageHover, {visible: false}); + Overlays.editOverlay(backImageHover, {visible: false}); + Overlays.editOverlay(tryAgainText, tryAgainTextProperties); + Overlays.editOverlay(backText, backTextProperties); + + } + + function clickedOnOverlay(overlayID, event) { + if (event.isRightButton) { + // don't allow right-clicks. + return; + } + if (tryAgainImageHover === overlayID) { + location.goToLastAddress(); + } else if (backImageHover === overlayID && location.canGoBack()) { + location.goBack(); + } + } + + function cleanup() { + Script.clearInterval(timer); + timer = null; + Overlays.deleteOverlay(redirectOopsText); + Overlays.deleteOverlay(tryAgainImageNeutral); + Overlays.deleteOverlay(backImageNeutral); + Overlays.deleteOverlay(tryAgainImageHover); + Overlays.deleteOverlay(backImageHover); + Overlays.deleteOverlay(tryAgainText); + Overlays.deleteOverlay(backText); + } + + toggleOverlays(true); + + Overlays.mouseReleaseOnOverlay.connect(clickedOnOverlay); + Overlays.hoverEnterOverlay.connect(function(overlayID, event) { + if (!isErrorState) { + // don't allow hover overlay events to get caught if it's not in error state anymore. + return; + } + if (overlayID === backImageNeutral && location.canGoBack()) { + Overlays.editOverlay(backImageNeutral, {visible: false}); + Overlays.editOverlay(backImageHover, {visible: true}); + } + if (overlayID === tryAgainImageNeutral) { + Overlays.editOverlay(tryAgainImageNeutral, {visible: false}); + Overlays.editOverlay(tryAgainImageHover, {visible: true}); + } + }); + + Overlays.hoverLeaveOverlay.connect(function(overlayID, event) { + if (!isErrorState) { + // don't allow hover overlay events to get caught if it's not in error state anymore. + return; + } + if (overlayID === backImageHover) { + Overlays.editOverlay(backImageHover, {visible: false}); + Overlays.editOverlay(backImageNeutral, {visible: true}); + } + if (overlayID === tryAgainImageHover) { + Overlays.editOverlay(tryAgainImageHover, {visible: false}); + Overlays.editOverlay(tryAgainImageNeutral, {visible: true}); + } + }); + + Window.redirectErrorStateChanged.connect(toggleOverlays); + + Script.scriptEnding.connect(cleanup); +}());