mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-10 11:33:23 +02:00
Merge pull request #13938 from wayne-chen/interstitalMerged
Interstitial Page with 404 Redirect
This commit is contained in:
commit
f67deb9f65
37 changed files with 1835 additions and 172 deletions
|
@ -332,6 +332,10 @@ if (APPLE)
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
"${RESOURCES_DEV_DIR}/fonts"
|
||||
# add redirect json to macOS builds.
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
)
|
||||
|
||||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
|
@ -360,6 +364,9 @@ else()
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
|
|
BIN
interface/resources/images/loadingBar_placard.png
Normal file
BIN
interface/resources/images/loadingBar_placard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
interface/resources/images/loadingBar_progress.png
Normal file
BIN
interface/resources/images/loadingBar_progress.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_auth.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_auth.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/redirect/oopsDialog_auth.png
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_auth.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.png
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_vague.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_vague.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/redirect/oopsDialog_vague.png
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_vague.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5 KiB |
|
@ -79,7 +79,7 @@ StackView {
|
|||
return;
|
||||
}
|
||||
location.text = targetString;
|
||||
toggleOrGo(true, targetString);
|
||||
toggleOrGo(targetString, true);
|
||||
clearAddressLineTimer.start();
|
||||
}
|
||||
|
||||
|
@ -399,7 +399,7 @@ StackView {
|
|||
}
|
||||
}
|
||||
|
||||
function toggleOrGo(fromSuggestions, address) {
|
||||
function toggleOrGo(address, fromSuggestions) {
|
||||
if (address !== undefined && address !== "") {
|
||||
addressBarDialog.loadAddress(address, fromSuggestions);
|
||||
clearAddressLineTimer.start();
|
||||
|
|
934
interface/resources/serverless/redirect.json
Normal file
934
interface/resources/serverless/redirect.json
Normal file
|
@ -0,0 +1,934 @@
|
|||
{
|
||||
"DataVersion": 0,
|
||||
"Paths":
|
||||
{
|
||||
"/": "/4,1.4,4/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": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2018-09-05T00:40:03Z",
|
||||
"dimensions": {
|
||||
"blue": 8.645400047302246,
|
||||
"green": 0.20000000298023224,
|
||||
"red": 20.025121688842773,
|
||||
"x": 20.025121688842773,
|
||||
"y": 0.20000000298023224,
|
||||
"z": 8.645400047302246
|
||||
},
|
||||
"id": "{e44fb546-b34a-4966-9b11-73556f800d21}",
|
||||
"lastEdited": 1536107948776951,
|
||||
"lastEditedBy": "{ce82d352-3002-44ae-9b76-66492989a1db}",
|
||||
"locked": true,
|
||||
"name": "ceiling",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 4.846520900726318,
|
||||
"green": 2.912982940673828,
|
||||
"red": 5.739595890045166,
|
||||
"x": 5.739595890045166,
|
||||
"y": 2.912982940673828,
|
||||
"z": 4.846520900726318
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 21.812576293945312,
|
||||
"x": -5.16669225692749,
|
||||
"y": -7.993305206298828,
|
||||
"z": -6.059767246246338
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.970295786857605,
|
||||
"x": 0,
|
||||
"y": -0.24192190170288086,
|
||||
"z": 0
|
||||
},
|
||||
"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": 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",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"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}",
|
||||
"locked": true,
|
||||
"name": "backWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 5.268576622009277,
|
||||
"green": 1.0066027641296387,
|
||||
"red": 6.093774318695068,
|
||||
"x": 6.093774318695068,
|
||||
"y": 1.0066027641296387,
|
||||
"z": 5.268576622009277
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": 0.25303030014038086,
|
||||
"y": -4.834141254425049,
|
||||
"z": -0.5721673965454102
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9662165641784668,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": -0.2576791048049927,
|
||||
"z": 1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"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": {
|
||||
"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": "{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}",
|
||||
"locked": true,
|
||||
"name": "frontWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 2.662257671356201,
|
||||
"green": 1.0063786506652832,
|
||||
"red": 1.4868733882904053,
|
||||
"x": 1.4868733882904053,
|
||||
"y": 1.0063786506652832,
|
||||
"z": 2.662257671356201
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -4.353870391845703,
|
||||
"y": -4.834365367889404,
|
||||
"z": -3.1784863471984863
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9666743278503418,
|
||||
"x": -4.57763671875e-05,
|
||||
"y": -0.2560006380081177,
|
||||
"z": 1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"visible": 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": "{303631f1-04f3-42a6-b8a8-8dd4b65d1231}",
|
||||
"lastEdited": 1536107948776513,
|
||||
"lastEditedBy": "{b5bba536-25e5-4b12-a1be-5c7cd196a06a}",
|
||||
"locked": true,
|
||||
"modelURL": "http://hifi-content.s3.amazonaws.com/alexia/Models/Portal/portal2.fbx",
|
||||
"name": "Back",
|
||||
"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
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.5651814937591553,
|
||||
"x": 1.7454873323440552,
|
||||
"y": -1.188097357749939,
|
||||
"z": 0.3010033369064331
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9084458351135254,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.4179598093032837,
|
||||
"z": -0.0001068115234375
|
||||
},
|
||||
"script": "https://hifi-content.s3.amazonaws.com/wayne/404redirectionScripts/backEntityScript.js",
|
||||
"scriptTimestamp": 1535751754379,
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model",
|
||||
"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,
|
||||
"emitterShouldTrail": true,
|
||||
"id": "{8ded39e6-303c-48f2-be79-81b715cca9f7}",
|
||||
"lastEdited": 1536107948777127,
|
||||
"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": 3.78922963142395,
|
||||
"green": 0.3698839843273163,
|
||||
"red": 1.1863799095153809,
|
||||
"x": 1.1863799095153809,
|
||||
"y": 0.3698839843273163,
|
||||
"z": 3.78922963142395
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 22.932353973388672,
|
||||
"x": -10.279796600341797,
|
||||
"y": -11.096293449401855,
|
||||
"z": -7.676947593688965
|
||||
},
|
||||
"radiusFinish": 0,
|
||||
"radiusStart": 0,
|
||||
"rotation": {
|
||||
"w": 0.996429443359375,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -0.08442819118499756,
|
||||
"z": -4.57763671875e-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}}"
|
||||
}
|
||||
],
|
||||
"Id": "{18abccad-2d57-4176-9d89-24dc424916f5}",
|
||||
"Version": 93
|
||||
}
|
|
@ -1186,6 +1186,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||
|
||||
connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl)));
|
||||
connect(&domainHandler, SIGNAL(redirectToErrorDomainURL(QUrl)), SLOT(goToErrorDomainURL(QUrl)));
|
||||
connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){
|
||||
setCrashAnnotation("domain", domainURL.toString().toStdString());
|
||||
});
|
||||
|
@ -1199,6 +1200,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
});
|
||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused);
|
||||
|
||||
nodeList->getDomainHandler().setErrorDomainURL(QUrl(REDIRECT_HIFI_ADDRESS));
|
||||
|
||||
// We could clear ATP assets only when changing domains, but it's possible that the domain you are connected
|
||||
// to has gone down and switched to a new content set, so when you reconnect the cached ATP assets will no longer be valid.
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, DependencyManager::get<ScriptCache>().data(), &ScriptCache::clearATPScriptsFromCache);
|
||||
|
@ -1640,7 +1643,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
audioClient->setMuted(!audioClient->isMuted());
|
||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||
cycleCamera();
|
||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU) && !isInterstitialMode()) {
|
||||
toggleTabletUI();
|
||||
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
||||
auto oldPos = getApplicationCompositor().getReticlePosition();
|
||||
|
@ -2249,6 +2252,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
|
||||
connect(&domainHandler, &DomainHandler::domainURLChanged, this, &Application::addAssetToWorldMessageClose);
|
||||
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &Application::addAssetToWorldMessageClose);
|
||||
|
||||
updateSystemTabletMode();
|
||||
|
||||
|
@ -3012,6 +3016,9 @@ void Application::initializeUi() {
|
|||
if (_window && _window->isFullScreen()) {
|
||||
setFullscreen(nullptr, true);
|
||||
}
|
||||
|
||||
|
||||
setIsInterstitialMode(true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3490,6 +3497,15 @@ bool Application::isServerlessMode() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Application::setIsInterstitialMode(bool interstitialMode) {
|
||||
if (_interstitialMode != interstitialMode) {
|
||||
_interstitialMode = interstitialMode;
|
||||
|
||||
DependencyManager::get<AudioClient>()->setAudioPaused(_interstitialMode);
|
||||
DependencyManager::get<AvatarManager>()->setMyAvatarDataPacketsPaused(_interstitialMode);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::setIsServerlessMode(bool serverlessDomain) {
|
||||
auto tree = getEntities()->getTree();
|
||||
if (tree) {
|
||||
|
@ -3497,9 +3513,9 @@ void Application::setIsServerlessMode(bool serverlessDomain) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::loadServerlessDomain(QUrl domainURL) {
|
||||
void Application::loadServerlessDomain(QUrl domainURL, bool errorDomain) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL));
|
||||
QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL), Q_ARG(bool, errorDomain));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3531,8 +3547,11 @@ void Application::loadServerlessDomain(QUrl domainURL) {
|
|||
}
|
||||
|
||||
std::map<QString, QString> namedPaths = tmpTree->getNamedPaths();
|
||||
nodeList->getDomainHandler().connectedToServerless(namedPaths);
|
||||
|
||||
if (errorDomain) {
|
||||
nodeList->getDomainHandler().loadedErrorDomain(namedPaths);
|
||||
} else {
|
||||
nodeList->getDomainHandler().connectedToServerless(namedPaths);
|
||||
}
|
||||
|
||||
_fullSceneReceivedCounter++;
|
||||
}
|
||||
|
@ -3767,7 +3786,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
|
||||
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
||||
if (_controllerScriptingInterface->isKeyCaptured(event) || isInterstitialMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5554,6 +5573,7 @@ void Application::update(float deltaTime) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_physicsEnabled) {
|
||||
if (!domainLoadingInProgress) {
|
||||
PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
|
||||
|
@ -5574,6 +5594,7 @@ void Application::update(float deltaTime) {
|
|||
// scene is ready to compute its collision shape.
|
||||
if (getMyAvatar()->isReadyForPhysics()) {
|
||||
_physicsEnabled = true;
|
||||
setIsInterstitialMode(false);
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
}
|
||||
}
|
||||
|
@ -5653,7 +5674,7 @@ void Application::update(float deltaTime) {
|
|||
// Transfer the user inputs to the driveKeys
|
||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||
myAvatar->clearDriveKeys();
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT && !isInterstitialMode()) {
|
||||
if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
||||
|
@ -5969,7 +5990,7 @@ void Application::update(float deltaTime) {
|
|||
// send packet containing downstream audio stats to the AudioMixer
|
||||
{
|
||||
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
|
||||
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) {
|
||||
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS && !isInterstitialMode()) {
|
||||
_lastSendDownstreamAudioStats = now;
|
||||
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);
|
||||
|
@ -6132,21 +6153,23 @@ void Application::updateRenderArgs(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::queryAvatars() {
|
||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||
unsigned char* bufferStart = destinationBuffer;
|
||||
if (!isInterstitialMode()) {
|
||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||
unsigned char* bufferStart = destinationBuffer;
|
||||
|
||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
|
||||
for (const auto& view : _conicalViews) {
|
||||
destinationBuffer += view.serialize(destinationBuffer);
|
||||
for (const auto& view : _conicalViews) {
|
||||
destinationBuffer += view.serialize(destinationBuffer);
|
||||
}
|
||||
|
||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6369,6 +6392,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
||||
|
||||
resetPhysicsReadyInformation();
|
||||
setIsInterstitialMode(true);
|
||||
|
||||
_octreeServerSceneStats.withWriteLock([&] {
|
||||
_octreeServerSceneStats.clear();
|
||||
|
@ -6399,6 +6423,16 @@ void Application::domainURLChanged(QUrl domainURL) {
|
|||
updateWindowTitle();
|
||||
}
|
||||
|
||||
void Application::goToErrorDomainURL(QUrl errorDomainURL) {
|
||||
// disable physics until we have enough information about our new location to not cause craziness.
|
||||
resetPhysicsReadyInformation();
|
||||
setIsServerlessMode(errorDomainURL.scheme() != URL_SCHEME_HIFI);
|
||||
if (isServerlessMode()) {
|
||||
loadServerlessDomain(errorDomainURL, true);
|
||||
}
|
||||
updateWindowTitle();
|
||||
}
|
||||
|
||||
|
||||
void Application::resettingDomain() {
|
||||
_notifiedPacketVersionMismatchThisDomain = false;
|
||||
|
@ -6437,7 +6471,7 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
_octreeQuery.incrementConnectionID();
|
||||
}
|
||||
|
||||
if (node->getType() == NodeType::AudioMixer) {
|
||||
if (node->getType() == NodeType::AudioMixer && !isInterstitialMode()) {
|
||||
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
||||
}
|
||||
|
||||
|
@ -6457,8 +6491,10 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
getMyAvatar()->markIdentityDataChanged();
|
||||
getMyAvatar()->resetLastSent();
|
||||
|
||||
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
||||
getMyAvatar()->sendAvatarDataPacket(true);
|
||||
if (!isInterstitialMode()) {
|
||||
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
||||
getMyAvatar()->sendAvatarDataPacket(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7809,7 +7845,7 @@ float Application::getRenderResolutionScale() const {
|
|||
}
|
||||
|
||||
void Application::notifyPacketVersionMismatch() {
|
||||
if (!_notifiedPacketVersionMismatchThisDomain) {
|
||||
if (!_notifiedPacketVersionMismatchThisDomain && !isInterstitialMode()) {
|
||||
_notifiedPacketVersionMismatchThisDomain = true;
|
||||
|
||||
QString message = "The location you are visiting is running an incompatible server version.\n";
|
||||
|
|
|
@ -224,6 +224,7 @@ public:
|
|||
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
||||
void setPreferStylusOverLaser(bool value);
|
||||
|
||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||
bool getPreferAvatarFingerOverStylus() { return false; }
|
||||
|
@ -304,6 +305,7 @@ public:
|
|||
void saveNextPhysicsStats(QString filename);
|
||||
|
||||
bool isServerlessMode() const;
|
||||
bool isInterstitialMode() const { return _interstitialMode; }
|
||||
|
||||
void replaceDomainContent(const QString& url);
|
||||
|
||||
|
@ -340,6 +342,7 @@ public slots:
|
|||
bool importEntities(const QString& url);
|
||||
void updateThreadPoolCount() const;
|
||||
void updateSystemTabletMode();
|
||||
void goToErrorDomainURL(QUrl errorDomainURL);
|
||||
|
||||
Q_INVOKABLE void loadDialog();
|
||||
Q_INVOKABLE void loadScriptURLDialog() const;
|
||||
|
@ -428,7 +431,8 @@ public slots:
|
|||
void setPreferredCursor(const QString& cursor);
|
||||
|
||||
void setIsServerlessMode(bool serverlessDomain);
|
||||
void loadServerlessDomain(QUrl domainURL);
|
||||
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
|
||||
void setIsInterstitialMode(bool interstialMode);
|
||||
|
||||
void updateVerboseLogging();
|
||||
|
||||
|
@ -627,6 +631,7 @@ private:
|
|||
QHash<int, QKeyEvent> _keysPressed;
|
||||
|
||||
bool _enableProcessOctreeThread;
|
||||
bool _interstitialMode { false };
|
||||
|
||||
OctreePacketProcessor _octreeProcessor;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
|
|
@ -11,16 +11,18 @@
|
|||
|
||||
#include "ConnectionMonitor.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <DomainHandler.h>
|
||||
#include <AddressManager.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
// Because the connection monitor is created at startup, the time we wait on initial load
|
||||
// should be longer to allow the application to initialize.
|
||||
static const int ON_INITIAL_LOAD_DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 10000;
|
||||
static const int DISPLAY_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
||||
static const int ON_INITIAL_LOAD_REDIRECT_AFTER_DISCONNECTED_FOR_X_MS = 10000;
|
||||
static const int REDIRECT_AFTER_DISCONNECTED_FOR_X_MS = 5000;
|
||||
|
||||
void ConnectionMonitor::init() {
|
||||
// Connect to domain disconnected message
|
||||
|
@ -30,23 +32,25 @@ void ConnectionMonitor::init() {
|
|||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &ConnectionMonitor::startTimer);
|
||||
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &ConnectionMonitor::stopTimer);
|
||||
connect(this, &ConnectionMonitor::setRedirectErrorState, &domainHandler, &DomainHandler::setRedirectErrorState);
|
||||
|
||||
_timer.setSingleShot(true);
|
||||
if (!domainHandler.isConnected()) {
|
||||
_timer.start(ON_INITIAL_LOAD_DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start(ON_INITIAL_LOAD_REDIRECT_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
}
|
||||
|
||||
connect(&_timer, &QTimer::timeout, this, []() {
|
||||
qDebug() << "ConnectionMonitor: Showing connection failure window";
|
||||
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(true);
|
||||
connect(&_timer, &QTimer::timeout, this, [this]() {
|
||||
qDebug() << "ConnectionMonitor: Redirecting to 404 error domain";
|
||||
// set in a timeout error
|
||||
emit setRedirectErrorState(REDIRECT_HIFI_ADDRESS, 5);
|
||||
});
|
||||
}
|
||||
|
||||
void ConnectionMonitor::startTimer() {
|
||||
_timer.start(DISPLAY_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
_timer.start(REDIRECT_AFTER_DISCONNECTED_FOR_X_MS);
|
||||
}
|
||||
|
||||
void ConnectionMonitor::stopTimer() {
|
||||
_timer.stop();
|
||||
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(false);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
class QUrl;
|
||||
class QString;
|
||||
|
||||
class ConnectionMonitor : public QObject {
|
||||
|
@ -22,6 +23,9 @@ class ConnectionMonitor : public QObject {
|
|||
public:
|
||||
void init();
|
||||
|
||||
signals:
|
||||
void setRedirectErrorState(QUrl errorURL, int reasonCode);
|
||||
|
||||
private slots:
|
||||
void startTimer();
|
||||
void stopTimer();
|
||||
|
|
|
@ -137,7 +137,7 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
|||
quint64 now = usecTimestampNow();
|
||||
quint64 dt = now - _lastSendAvatarDataTime;
|
||||
|
||||
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS) {
|
||||
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused) {
|
||||
// send head/hand data to the avatar mixer and voxel server
|
||||
PerformanceTimer perfTimer("send");
|
||||
_myAvatar->sendAvatarDataPacket();
|
||||
|
@ -155,6 +155,16 @@ float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& ra
|
|||
return avatar ? avatar->getDataRate(rateName) : 0.0f;
|
||||
}
|
||||
|
||||
void AvatarManager::setMyAvatarDataPacketsPaused(bool pause) {
|
||||
if (_myAvatarDataPacketsPaused != pause) {
|
||||
_myAvatarDataPacketsPaused = pause;
|
||||
|
||||
if (!_myAvatarDataPacketsPaused) {
|
||||
_myAvatar->sendAvatarDataPacket(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) const {
|
||||
auto avatar = getAvatarBySessionID(sessionID);
|
||||
return avatar ? avatar->getUpdateRate(rateName) : 0.0f;
|
||||
|
@ -802,13 +812,13 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
|
|||
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
||||
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
||||
QJsonObject thisAvatarPalData;
|
||||
|
||||
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
||||
currentSessionUUID = "";
|
||||
}
|
||||
|
||||
|
||||
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
||||
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
||||
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
||||
|
|
|
@ -91,6 +91,8 @@ public:
|
|||
void updateOtherAvatars(float deltaTime);
|
||||
void sendIdentityRequest(const QUuid& avatarID) const;
|
||||
|
||||
void setMyAvatarDataPacketsPaused(bool puase);
|
||||
|
||||
void postUpdate(float deltaTime, const render::ScenePointer& scene);
|
||||
|
||||
void clearOtherAvatars() override;
|
||||
|
@ -219,6 +221,7 @@ private:
|
|||
int _numAvatarsNotUpdated { 0 };
|
||||
float _avatarSimulationTime { 0.0f };
|
||||
bool _shouldRender { true };
|
||||
bool _myAvatarDataPacketsPaused { false };
|
||||
mutable int _identityRequestsSent { 0 };
|
||||
|
||||
mutable std::mutex _spaceLock;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
#include "SafeLanding.h"
|
||||
|
||||
OctreePacketProcessor::OctreePacketProcessor():
|
||||
_safeLanding(new SafeLanding())
|
||||
|
@ -133,7 +132,3 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
|
|||
void OctreePacketProcessor::startEntitySequence() {
|
||||
_safeLanding->startEntitySequence(qApp->getEntities());
|
||||
}
|
||||
|
||||
bool OctreePacketProcessor::isLoadSequenceComplete() const {
|
||||
return _safeLanding->isLoadSequenceComplete();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <ReceivedPacketProcessor.h>
|
||||
#include <ReceivedMessage.h>
|
||||
|
||||
class SafeLanding;
|
||||
#include "SafeLanding.h"
|
||||
|
||||
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
|
||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||
|
@ -26,7 +26,8 @@ public:
|
|||
~OctreePacketProcessor();
|
||||
|
||||
void startEntitySequence();
|
||||
bool isLoadSequenceComplete() const;
|
||||
bool isLoadSequenceComplete() const { return _safeLanding->isLoadSequenceComplete(); }
|
||||
float domainLoadingProgress() const { return _safeLanding->loadingProgressPercentage(); }
|
||||
|
||||
signals:
|
||||
void packetVersionMismatch();
|
||||
|
@ -40,4 +41,4 @@ private slots:
|
|||
private:
|
||||
std::unique_ptr<SafeLanding> _safeLanding;
|
||||
};
|
||||
#endif // hifi_OctreePacketProcessor_h
|
||||
#endif // hifi_OctreePacketProcessor_h
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "EntityTreeRenderer.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "Application.h"
|
||||
|
||||
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
||||
|
||||
|
@ -53,6 +54,7 @@ void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityT
|
|||
void SafeLanding::stopEntitySequence() {
|
||||
Locker lock(_lock);
|
||||
_trackingEntities = false;
|
||||
_maxTrackedEntityCount = 0;
|
||||
_initialStart = INVALID_SEQUENCE;
|
||||
_initialEnd = INVALID_SEQUENCE;
|
||||
_trackedEntities.clear();
|
||||
|
@ -64,20 +66,13 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
|
|||
Locker lock(_lock);
|
||||
EntityItemPointer entity = _entityTree->findEntityByID(entityID);
|
||||
|
||||
if (entity && !entity->getCollisionless()) {
|
||||
const auto& entityType = entity->getType();
|
||||
if (entityType == EntityTypes::Model) {
|
||||
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
|
||||
static const std::set<ShapeType> 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) {
|
||||
// Only track entities with downloaded collision bodies.
|
||||
_trackedEntities.emplace(entityID, entity);
|
||||
}
|
||||
}
|
||||
_trackedEntities.emplace(entityID, entity);
|
||||
int trackedEntityCount = (int)_trackedEntities.size();
|
||||
|
||||
if (trackedEntityCount > _maxTrackedEntityCount) {
|
||||
_maxTrackedEntityCount = trackedEntityCount;
|
||||
}
|
||||
qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +97,7 @@ void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) {
|
|||
}
|
||||
|
||||
bool SafeLanding::isLoadSequenceComplete() {
|
||||
if (isEntityPhysicsComplete() && isSequenceNumbersComplete()) {
|
||||
if (isEntityLoadingComplete() && isSequenceNumbersComplete()) {
|
||||
Locker lock(_lock);
|
||||
_trackedEntities.clear();
|
||||
_initialStart = INVALID_SEQUENCE;
|
||||
|
@ -114,6 +109,15 @@ bool SafeLanding::isLoadSequenceComplete() {
|
|||
return !_trackingEntities;
|
||||
}
|
||||
|
||||
float SafeLanding::loadingProgressPercentage() {
|
||||
Locker lock(_lock);
|
||||
if (_maxTrackedEntityCount > 0) {
|
||||
return ((_maxTrackedEntityCount - _trackedEntities.size()) / (float)_maxTrackedEntityCount);
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool SafeLanding::isSequenceNumbersComplete() {
|
||||
if (_initialStart != INVALID_SEQUENCE) {
|
||||
Locker lock(_lock);
|
||||
|
@ -132,17 +136,42 @@ bool SafeLanding::isSequenceNumbersComplete() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SafeLanding::isEntityPhysicsComplete() {
|
||||
Locker lock(_lock);
|
||||
for (auto entityMapIter = _trackedEntities.begin(); entityMapIter != _trackedEntities.end(); ++entityMapIter) {
|
||||
auto entity = entityMapIter->second;
|
||||
if (!entity->shouldBePhysical() || entity->isReadyToComputeShape()) {
|
||||
entityMapIter = _trackedEntities.erase(entityMapIter);
|
||||
if (entityMapIter == _trackedEntities.end()) {
|
||||
break;
|
||||
bool isEntityPhysicsReady(const EntityItemPointer& entity) {
|
||||
if (entity && !entity->getCollisionless()) {
|
||||
const auto& entityType = entity->getType();
|
||||
if (entityType == EntityTypes::Model) {
|
||||
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
|
||||
static const std::set<ShapeType> 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->isReadyToComputeShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SafeLanding::isEntityLoadingComplete() {
|
||||
Locker lock(_lock);
|
||||
auto entityTree = qApp->getEntities();
|
||||
auto entityMapIter = _trackedEntities.begin();
|
||||
|
||||
while (entityMapIter != _trackedEntities.end()) {
|
||||
auto entity = entityMapIter->second;
|
||||
bool isVisuallyReady = (entity->isVisuallyReady() || !entityTree->renderableForEntityId(entityMapIter->first));
|
||||
if (isEntityPhysicsReady(entity) && isVisuallyReady) {
|
||||
entityMapIter = _trackedEntities.erase(entityMapIter);
|
||||
} else {
|
||||
if (!isVisuallyReady) {
|
||||
entity->requestRenderUpdate();
|
||||
}
|
||||
|
||||
entityMapIter++;
|
||||
}
|
||||
}
|
||||
return _trackedEntities.empty();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityDynamicInterface.h"
|
||||
|
||||
class EntityTreeRenderer;
|
||||
class EntityItemID;
|
||||
|
@ -29,6 +30,7 @@ public:
|
|||
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
||||
void noteReceivedsequenceNumber(int sequenceNumber);
|
||||
bool isLoadSequenceComplete();
|
||||
float loadingProgressPercentage();
|
||||
|
||||
private slots:
|
||||
void addTrackedEntity(const EntityItemID& entityID);
|
||||
|
@ -37,7 +39,7 @@ private slots:
|
|||
private:
|
||||
bool isSequenceNumbersComplete();
|
||||
void debugDumpSequenceIDs() const;
|
||||
bool isEntityPhysicsComplete();
|
||||
bool isEntityLoadingComplete();
|
||||
|
||||
std::mutex _lock;
|
||||
using Locker = std::lock_guard<std::mutex>;
|
||||
|
@ -49,6 +51,7 @@ private:
|
|||
static constexpr int INVALID_SEQUENCE = -1;
|
||||
int _initialStart { INVALID_SEQUENCE };
|
||||
int _initialEnd { INVALID_SEQUENCE };
|
||||
int _maxTrackedEntityCount { 0 };
|
||||
|
||||
struct SequenceLessThan {
|
||||
bool operator()(const int& a, const int& b) const;
|
||||
|
|
|
@ -409,6 +409,10 @@ glm::vec2 WindowScriptingInterface::getDeviceSize() const {
|
|||
return qApp->getDeviceSize();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getLastDomainConnectionError() const {
|
||||
return DependencyManager::get<NodeList>()->getDomainHandler().getLastDomainConnectionError();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getX() {
|
||||
return qApp->getWindow()->geometry().x();
|
||||
}
|
||||
|
@ -584,3 +588,8 @@ void WindowScriptingInterface::onMessageBoxSelected(int button) {
|
|||
_messageBoxes.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float WindowScriptingInterface::domainLoadingProgress() {
|
||||
return qApp->getOctreePacketProcessor().domainLoadingProgress();
|
||||
}
|
||||
|
|
|
@ -491,6 +491,13 @@ public slots:
|
|||
*/
|
||||
glm::vec2 getDeviceSize() const;
|
||||
|
||||
/**jsdoc
|
||||
* Gets the last domain connection error when a connection is refused.
|
||||
* @function Window.getLastDomainConnectionError
|
||||
* @returns {Window.ConnectionRefusedReason} Integer number that enumerates the last domain connection refused.
|
||||
*/
|
||||
int getLastDomainConnectionError() const;
|
||||
|
||||
/**jsdoc
|
||||
* Open a non-modal message box that can have a variety of button combinations. See also,
|
||||
* {@link Window.updateMessageBox|updateMessageBox} and {@link Window.closeMessageBox|closeMessageBox}.
|
||||
|
@ -561,6 +568,8 @@ public slots:
|
|||
*/
|
||||
void closeMessageBox(int id);
|
||||
|
||||
float domainLoadingProgress();
|
||||
|
||||
private slots:
|
||||
void onWindowGeometryChanged(const QRect& geometry);
|
||||
void onMessageBoxSelected(int button);
|
||||
|
|
|
@ -106,6 +106,10 @@ extern std::atomic<size_t> DECIMATED_TEXTURE_COUNT;
|
|||
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
|
||||
|
||||
void Stats::updateStats(bool force) {
|
||||
|
||||
if (qApp->isInterstitialMode()) {
|
||||
return;
|
||||
}
|
||||
QQuickItem* parent = parentItem();
|
||||
if (!force) {
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
|
|
|
@ -305,6 +305,16 @@ void AudioClient::audioMixerKilled() {
|
|||
emit disconnected();
|
||||
}
|
||||
|
||||
void AudioClient::setAudioPaused(bool pause) {
|
||||
if (_audioPaused != pause) {
|
||||
_audioPaused = pause;
|
||||
|
||||
if (!_audioPaused) {
|
||||
negotiateAudioFormat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||
QAudioDeviceInfo result;
|
||||
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
||||
|
@ -651,7 +661,6 @@ void AudioClient::stop() {
|
|||
}
|
||||
|
||||
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
char bitset;
|
||||
message->readPrimitive(&bitset);
|
||||
|
||||
|
@ -664,11 +673,10 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessag
|
|||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||
} else {
|
||||
_receivedAudioStream.clearReverb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
|
||||
if (message->getType() == PacketType::SilentAudioFrame) {
|
||||
_silentInbound.increment();
|
||||
} else {
|
||||
|
@ -1026,80 +1034,82 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
|||
}
|
||||
|
||||
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||
if (_muted) {
|
||||
_lastInputLoudness = 0.0f;
|
||||
_timeSinceLastClip = 0.0f;
|
||||
} else {
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
// The audio gate includes DC removal
|
||||
_audioGate->render(samples, samples, numFrames);
|
||||
} else {
|
||||
_audioGate->removeDC(samples, samples, numFrames);
|
||||
}
|
||||
|
||||
int32_t loudness = 0;
|
||||
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
||||
bool didClip = false;
|
||||
for (int i = 0; i < numSamples; ++i) {
|
||||
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
||||
int32_t sample = std::abs((int32_t)samples[i]);
|
||||
loudness += sample;
|
||||
didClip |= (sample > CLIPPING_THRESHOLD);
|
||||
}
|
||||
_lastInputLoudness = (float)loudness / numSamples;
|
||||
|
||||
if (didClip) {
|
||||
if (!_audioPaused) {
|
||||
if (_muted) {
|
||||
_lastInputLoudness = 0.0f;
|
||||
_timeSinceLastClip = 0.0f;
|
||||
} else if (_timeSinceLastClip >= 0.0f) {
|
||||
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
||||
} else {
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
// The audio gate includes DC removal
|
||||
_audioGate->render(samples, samples, numFrames);
|
||||
} else {
|
||||
_audioGate->removeDC(samples, samples, numFrames);
|
||||
}
|
||||
|
||||
int32_t loudness = 0;
|
||||
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
||||
bool didClip = false;
|
||||
for (int i = 0; i < numSamples; ++i) {
|
||||
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
||||
int32_t sample = std::abs((int32_t)samples[i]);
|
||||
loudness += sample;
|
||||
didClip |= (sample > CLIPPING_THRESHOLD);
|
||||
}
|
||||
_lastInputLoudness = (float)loudness / numSamples;
|
||||
|
||||
if (didClip) {
|
||||
_timeSinceLastClip = 0.0f;
|
||||
} else if (_timeSinceLastClip >= 0.0f) {
|
||||
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
||||
}
|
||||
|
||||
emit inputReceived(audioBuffer);
|
||||
}
|
||||
|
||||
emit inputReceived(audioBuffer);
|
||||
emit inputLoudnessChanged(_lastInputLoudness);
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||
_audioGateOpen = audioGateOpen;
|
||||
|
||||
if (openedInLastBlock) {
|
||||
emit noiseGateOpened();
|
||||
} else if (closedInLastBlock) {
|
||||
emit noiseGateClosed();
|
||||
}
|
||||
|
||||
// the codec must be flushed to silence before sending silent packets,
|
||||
// so delay the transition to silent packets by one packet after becoming silent.
|
||||
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
||||
if (!audioGateOpen && !closedInLastBlock) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
_silentOutbound.increment();
|
||||
} else {
|
||||
_audioOutbound.increment();
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
audioTransform.setTranslation(_positionGetter());
|
||||
audioTransform.setRotation(_orientationGetter());
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audioBuffer, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audioBuffer;
|
||||
}
|
||||
|
||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||
packetType, _selectedCodecName);
|
||||
_stats.sentPacket();
|
||||
}
|
||||
|
||||
emit inputLoudnessChanged(_lastInputLoudness);
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||
_audioGateOpen = audioGateOpen;
|
||||
|
||||
if (openedInLastBlock) {
|
||||
emit noiseGateOpened();
|
||||
} else if (closedInLastBlock) {
|
||||
emit noiseGateClosed();
|
||||
}
|
||||
|
||||
// the codec must be flushed to silence before sending silent packets,
|
||||
// so delay the transition to silent packets by one packet after becoming silent.
|
||||
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
||||
if (!audioGateOpen && !closedInLastBlock) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
_silentOutbound.increment();
|
||||
} else {
|
||||
_audioOutbound.increment();
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
audioTransform.setTranslation(_positionGetter());
|
||||
audioTransform.setRotation(_orientationGetter());
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audioBuffer, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audioBuffer;
|
||||
}
|
||||
|
||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||
packetType, _selectedCodecName);
|
||||
_stats.sentPacket();
|
||||
}
|
||||
|
||||
void AudioClient::handleMicAudioInput() {
|
||||
|
|
|
@ -162,6 +162,7 @@ public:
|
|||
|
||||
bool startRecording(const QString& filename);
|
||||
void stopRecording();
|
||||
void setAudioPaused(bool pause);
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -416,6 +417,7 @@ private:
|
|||
QVector<AudioInjectorPointer> _activeLocalAudioInjectors;
|
||||
|
||||
bool _isPlayingBackRecording { false };
|
||||
bool _audioPaused { false };
|
||||
|
||||
CodecPluginPointer _codec;
|
||||
QString _selectedCodecName;
|
||||
|
|
|
@ -1297,9 +1297,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
}
|
||||
});
|
||||
|
||||
// Check for removal
|
||||
ModelPointer model;
|
||||
withReadLock([&] { model = _model; });
|
||||
|
||||
withWriteLock([&] {
|
||||
bool visuallyReady = true;
|
||||
if (_hasModel) {
|
||||
if (model && _didLastVisualGeometryRequestSucceed) {
|
||||
visuallyReady = (_prevModelLoaded && _texturesLoaded);
|
||||
}
|
||||
}
|
||||
entity->setVisuallyReady(visuallyReady);
|
||||
});
|
||||
|
||||
// Check for removal
|
||||
if (!_hasModel) {
|
||||
if (model) {
|
||||
model->removeFromScene(scene, transaction);
|
||||
|
@ -1441,11 +1452,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
// That is where _currentFrame and _lastAnimated were updated.
|
||||
if (_animating) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
||||
|
||||
|
||||
if (!jointsMapped()) {
|
||||
mapJoints(entity, model->getJointNames());
|
||||
//else the joint have been mapped before but we have a new animation to load
|
||||
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
|
||||
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
|
||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(entity->getAnimationURL());
|
||||
_jointMappingCompleted = false;
|
||||
mapJoints(entity, model->getJointNames());
|
||||
|
|
|
@ -288,6 +288,17 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
updateHazeFromEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
bool visuallyReady = true;
|
||||
uint32_t skyboxMode = entity->getSkyboxMode();
|
||||
if (skyboxMode == COMPONENT_MODE_ENABLED && !_skyboxTextureURL.isEmpty()) {
|
||||
bool skyboxLoadedOrFailed = (_skyboxTexture && (_skyboxTexture->isLoaded() || _skyboxTexture->isFailed()));
|
||||
|
||||
visuallyReady = skyboxLoadedOrFailed;
|
||||
}
|
||||
|
||||
entity->setVisuallyReady(visuallyReady);
|
||||
|
||||
if (bloomChanged) {
|
||||
updateBloomFromEntity(entity);
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ public:
|
|||
void setDynamic(bool value);
|
||||
|
||||
virtual bool shouldBePhysical() const { return false; }
|
||||
bool isVisuallyReady() const { return _visuallyReady; }
|
||||
|
||||
bool getLocked() const;
|
||||
void setLocked(bool value);
|
||||
|
@ -527,6 +528,7 @@ public:
|
|||
void removeCloneID(const QUuid& cloneID);
|
||||
const QVector<QUuid> getCloneIDs() const;
|
||||
void setCloneIDs(const QVector<QUuid>& cloneIDs);
|
||||
void setVisuallyReady(bool visuallyReady) { _visuallyReady = visuallyReady; }
|
||||
|
||||
signals:
|
||||
void requestRenderUpdate();
|
||||
|
@ -639,6 +641,7 @@ protected:
|
|||
EntityTreeElementPointer _element; // set by EntityTreeElement
|
||||
void* _physicsInfo { nullptr }; // set by EntitySimulation
|
||||
bool _simulated { false }; // set by EntitySimulation
|
||||
bool _visuallyReady { true };
|
||||
|
||||
bool addActionInternal(EntitySimulationPointer simulation, EntityDynamicPointer action);
|
||||
bool removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation = nullptr);
|
||||
|
|
|
@ -40,6 +40,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(
|
|||
_type = EntityTypes::Model;
|
||||
_lastKnownCurrentFrame = -1;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
_visuallyReady = false;
|
||||
}
|
||||
|
||||
const QString ModelEntityItem::getTextures() const {
|
||||
|
|
|
@ -42,6 +42,7 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en
|
|||
|
||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||
_compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
|
||||
_visuallyReady = false;
|
||||
}
|
||||
|
||||
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "udt/PacketHeaders.h"
|
||||
|
||||
const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json";
|
||||
const QString REDIRECT_HIFI_ADDRESS = "file:///~/serverless/redirect.json";
|
||||
const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager";
|
||||
const QString SETTINGS_CURRENT_ADDRESS_KEY = "address";
|
||||
|
||||
|
@ -111,6 +112,9 @@ QUrl AddressManager::currentFacingPublicAddress() const {
|
|||
return shareableAddress;
|
||||
}
|
||||
|
||||
QUrl AddressManager::lastAddress() const {
|
||||
return _lastVisitedURL;
|
||||
}
|
||||
|
||||
void AddressManager::loadSettings(const QString& lookupString) {
|
||||
#if defined(USE_GLES) && defined(Q_OS_WIN)
|
||||
|
@ -247,9 +251,12 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_USER, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// in case we're failing to connect to where we thought this user was
|
||||
// store their username as previous lookup so we can refresh their location via API
|
||||
_previousLookup = lookupUrl;
|
||||
_previousAPILookup = lookupUrl;
|
||||
} else {
|
||||
// we're assuming this is either a network address or global place name
|
||||
// check if it is a network address first
|
||||
|
@ -259,8 +266,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_NETWORK_ADDRESS, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// a network address lookup clears the previous lookup since we don't expect to re-attempt it
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
// If the host changed then we have already saved to history
|
||||
if (hostChanged) {
|
||||
|
@ -278,8 +288,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
} else if (handleDomainID(lookupUrl.host())){
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_DOMAIN_ID, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// store this domain ID as the previous lookup in case we're failing to connect and want to refresh API info
|
||||
_previousLookup = lookupUrl;
|
||||
_previousAPILookup = lookupUrl;
|
||||
|
||||
// no place name - this is probably a domain ID
|
||||
// try to look up the domain ID on the metaverse API
|
||||
|
@ -287,8 +300,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
} else {
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_PLACE, lookupUrl.toString());
|
||||
|
||||
// save the last visited domain URL.
|
||||
_lastVisitedURL = lookupUrl;
|
||||
|
||||
// store this place name as the previous lookup in case we fail to connect and want to refresh API info
|
||||
_previousLookup = lookupUrl;
|
||||
_previousAPILookup = lookupUrl;
|
||||
|
||||
// wasn't an address - lookup the place name
|
||||
// we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after
|
||||
|
@ -302,7 +318,7 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
qCDebug(networking) << "Going to relative path" << lookupUrl.path();
|
||||
|
||||
// a path lookup clears the previous lookup since we don't expect to re-attempt it
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
// if this is a relative path then handle it as a relative viewpoint
|
||||
handlePath(lookupUrl.path(), trigger, true);
|
||||
|
@ -314,7 +330,10 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
// be loaded over http(s)
|
||||
// lookupUrl.scheme() == URL_SCHEME_HTTP ||
|
||||
// lookupUrl.scheme() == URL_SCHEME_HTTPS ||
|
||||
_previousLookup.clear();
|
||||
// TODO once a file can return a connection refusal if there were to be some kind of load error, we'd
|
||||
// need to store the previous domain tried in _lastVisitedURL. For now , do not store it.
|
||||
|
||||
_previousAPILookup.clear();
|
||||
_shareablePlaceName.clear();
|
||||
setDomainInfo(lookupUrl, trigger);
|
||||
emit lookupResultsFinished();
|
||||
|
@ -381,7 +400,7 @@ void AddressManager::handleAPIResponse(QNetworkReply* requestReply) {
|
|||
QJsonObject dataObject = responseObject["data"].toObject();
|
||||
|
||||
// Lookup succeeded, don't keep re-trying it (especially on server restarts)
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
if (!dataObject.isEmpty()) {
|
||||
goToAddressFromObject(dataObject.toVariantMap(), requestReply);
|
||||
|
@ -547,7 +566,7 @@ void AddressManager::handleAPIError(QNetworkReply* errorReply) {
|
|||
|
||||
if (errorReply->error() == QNetworkReply::ContentNotFoundError) {
|
||||
// if this is a lookup that has no result, don't keep re-trying it
|
||||
_previousLookup.clear();
|
||||
_previousAPILookup.clear();
|
||||
|
||||
emit lookupResultIsNotFound();
|
||||
}
|
||||
|
@ -709,7 +728,6 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
|
|||
// We use _newHostLookupPath to determine if the client has already stored its last address
|
||||
// before moving to a new host thanks to the information in the same lookup URL.
|
||||
|
||||
|
||||
if (definitelyPathOnly || (!pathString.isEmpty() && pathString != _newHostLookupPath)
|
||||
|| trigger == Back || trigger == Forward) {
|
||||
addCurrentAddressToHistory(trigger);
|
||||
|
@ -843,8 +861,8 @@ void AddressManager::goToUser(const QString& username, bool shouldMatchOrientati
|
|||
|
||||
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 (!_previousLookup.isEmpty()) {
|
||||
handleUrl(_previousLookup, LookupTrigger::AttemptedRefresh);
|
||||
if (!_previousAPILookup.isEmpty()) {
|
||||
handleUrl(_previousAPILookup, LookupTrigger::AttemptedRefresh);
|
||||
} else {
|
||||
handleUrl(currentAddress(), LookupTrigger::AttemptedRefresh);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "AccountManager.h"
|
||||
|
||||
extern const QString DEFAULT_HIFI_ADDRESS;
|
||||
extern const QString REDIRECT_HIFI_ADDRESS;
|
||||
|
||||
const QString SANDBOX_HIFI_ADDRESS = "hifi://localhost";
|
||||
const QString INDEX_PATH = "/";
|
||||
|
@ -55,7 +56,6 @@ const QString GET_PLACE = "/api/v1/places/%1";
|
|||
* <em>Read-only.</em>
|
||||
* @property {boolean} isConnected - <code>true</code> if you're connected to the domain in your current <code>href</code>
|
||||
* metaverse address, otherwise <code>false</code>.
|
||||
* <em>Read-only.</em>
|
||||
* @property {string} pathname - The location and orientation in your current <code>href</code> metaverse address
|
||||
* (e.g., <code>"/15,-10,26/0,0,0,1"</code>).
|
||||
* <em>Read-only.</em>
|
||||
|
@ -140,7 +140,8 @@ public:
|
|||
* </table>
|
||||
* @typedef {number} location.LookupTrigger
|
||||
*/
|
||||
enum LookupTrigger {
|
||||
enum LookupTrigger
|
||||
{
|
||||
UserInput,
|
||||
Back,
|
||||
Forward,
|
||||
|
@ -164,6 +165,8 @@ public:
|
|||
QString currentPath(bool withOrientation = true) const;
|
||||
QString currentFacingPath() const;
|
||||
|
||||
QUrl lastAddress() const;
|
||||
|
||||
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
|
||||
QString getPlaceName() const;
|
||||
QString getDomainID() const;
|
||||
|
@ -191,7 +194,7 @@ public slots:
|
|||
* Helps ensure that user's location history is correctly maintained.
|
||||
*/
|
||||
void handleLookupString(const QString& lookupString, bool fromSuggestions = false);
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* Go to a position and orientation resulting from a lookup for a named path in the domain (set in the domain server's
|
||||
* settings).
|
||||
|
@ -204,8 +207,9 @@ public slots:
|
|||
// functions and signals that should be exposed are moved to a scripting interface class.
|
||||
//
|
||||
// we currently expect this to be called from NodeList once handleLookupString has been called with a path
|
||||
bool goToViewpointForPath(const QString& viewpointString, const QString& pathString)
|
||||
{ return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString); }
|
||||
bool goToViewpointForPath(const QString& viewpointString, const QString& pathString) {
|
||||
return handleViewpoint(viewpointString, false, DomainPathResponse, false, pathString);
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Go back to the previous location in your navigation history, if there is one.
|
||||
|
@ -226,8 +230,10 @@ public slots:
|
|||
* @param {location.LookupTrigger} trigger=StartupFromSettings - The reason for the function call. Helps ensure that user's
|
||||
* location history is correctly maintained.
|
||||
*/
|
||||
void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger); }
|
||||
|
||||
void goToLocalSandbox(QString path = "", LookupTrigger trigger = LookupTrigger::StartupFromSettings) {
|
||||
handleUrl(SANDBOX_HIFI_ADDRESS + path, trigger);
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* Go to the default "welcome" metaverse address.
|
||||
* @function location.goToEntry
|
||||
|
@ -245,6 +251,12 @@ public slots:
|
|||
*/
|
||||
void goToUser(const QString& username, bool shouldMatchOrientation = true);
|
||||
|
||||
/**jsdoc
|
||||
* Go to the last address tried. This will be the last URL tried from location.handleLookupString
|
||||
* @function location.goToLastAddress
|
||||
*/
|
||||
void goToLastAddress() { handleUrl(_lastVisitedURL, LookupTrigger::AttemptedRefresh); }
|
||||
|
||||
/**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
|
||||
|
@ -352,7 +364,8 @@ signals:
|
|||
* location.locationChangeRequired.connect(onLocationChangeRequired);
|
||||
*/
|
||||
void locationChangeRequired(const glm::vec3& newPosition,
|
||||
bool hasOrientationChange, const glm::quat& newOrientation,
|
||||
bool hasOrientationChange,
|
||||
const glm::quat& newOrientation,
|
||||
bool shouldFaceLocation);
|
||||
|
||||
/**jsdoc
|
||||
|
@ -423,7 +436,7 @@ private slots:
|
|||
void handleShareableNameAPIResponse(QNetworkReply* requestReply);
|
||||
|
||||
private:
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply* reply);
|
||||
void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply* reply);
|
||||
|
||||
// Set host and port, and return `true` if it was changed.
|
||||
bool setHost(const QString& host, LookupTrigger trigger, quint16 port = 0);
|
||||
|
@ -435,8 +448,11 @@ private:
|
|||
|
||||
bool handleNetworkAddress(const QString& lookupString, LookupTrigger trigger, bool& hostChanged);
|
||||
void handlePath(const QString& path, LookupTrigger trigger, bool wasPathOnly = false);
|
||||
bool handleViewpoint(const QString& viewpointString, bool shouldFace, LookupTrigger trigger,
|
||||
bool definitelyPathOnly = false, const QString& pathString = QString());
|
||||
bool handleViewpoint(const QString& viewpointString,
|
||||
bool shouldFace,
|
||||
LookupTrigger trigger,
|
||||
bool definitelyPathOnly = false,
|
||||
const QString& pathString = QString());
|
||||
bool handleUsername(const QString& lookupString);
|
||||
bool handleDomainID(const QString& host);
|
||||
|
||||
|
@ -446,6 +462,7 @@ private:
|
|||
void addCurrentAddressToHistory(LookupTrigger trigger);
|
||||
|
||||
QUrl _domainURL;
|
||||
QUrl _lastVisitedURL;
|
||||
|
||||
QUuid _rootPlaceID;
|
||||
PositionGetter _positionGetter;
|
||||
|
@ -459,7 +476,7 @@ private:
|
|||
|
||||
QString _newHostLookupPath;
|
||||
|
||||
QUrl _previousLookup;
|
||||
QUrl _previousAPILookup;
|
||||
};
|
||||
|
||||
#endif // hifi_AddressManager_h
|
||||
#endif // hifi_AddressManager_h
|
||||
|
|
|
@ -99,6 +99,7 @@ void DomainHandler::softReset() {
|
|||
|
||||
clearSettings();
|
||||
|
||||
_isInErrorState = false;
|
||||
_connectionDenialsSinceKeypairRegen = 0;
|
||||
_checkInPacketsSinceLastReply = 0;
|
||||
|
||||
|
@ -128,6 +129,11 @@ void DomainHandler::hardReset() {
|
|||
_pendingPath.clear();
|
||||
}
|
||||
|
||||
void DomainHandler::setErrorDomainURL(const QUrl& url) {
|
||||
_errorDomainURL = url;
|
||||
return;
|
||||
}
|
||||
|
||||
void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hostname) {
|
||||
if (_sockAddr != sockAddr) {
|
||||
// we should reset on a sockAddr change
|
||||
|
@ -171,7 +177,8 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) {
|
|||
domainPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
}
|
||||
|
||||
if (_domainURL != domainURL || _sockAddr.getPort() != domainPort) {
|
||||
// if it's in the error state, reset and try again.
|
||||
if ((_domainURL != domainURL || _sockAddr.getPort() != domainPort) || _isInErrorState) {
|
||||
// re-set the domain info so that auth information is reloaded
|
||||
hardReset();
|
||||
|
||||
|
@ -206,7 +213,8 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) {
|
|||
|
||||
void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id) {
|
||||
|
||||
if (_iceServerSockAddr.getAddress().toString() != iceServerHostname || id != _pendingDomainID) {
|
||||
// if it's in the error state, reset and try again.
|
||||
if ((_iceServerSockAddr.getAddress().toString() != iceServerHostname || id != _pendingDomainID) || _isInErrorState) {
|
||||
// re-set the domain info to connect to new domain
|
||||
hardReset();
|
||||
|
||||
|
@ -316,6 +324,23 @@ void DomainHandler::connectedToServerless(std::map<QString, QString> namedPaths)
|
|||
setIsConnected(true);
|
||||
}
|
||||
|
||||
void DomainHandler::loadedErrorDomain(std::map<QString, QString> namedPaths) {
|
||||
auto lookup = namedPaths.find("/");
|
||||
QString viewpoint;
|
||||
if (lookup != namedPaths.end()) {
|
||||
viewpoint = lookup->second;
|
||||
} else {
|
||||
viewpoint = DOMAIN_SPAWNING_POINT;
|
||||
}
|
||||
DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, QString());
|
||||
}
|
||||
|
||||
void DomainHandler::setRedirectErrorState(QUrl errorUrl, int reasonCode) {
|
||||
_errorDomainURL = errorUrl;
|
||||
_lastDomainConnectionError = reasonCode;
|
||||
emit redirectToErrorDomainURL(_errorDomainURL);
|
||||
}
|
||||
|
||||
void DomainHandler::requestDomainSettings() {
|
||||
qCDebug(networking) << "Requesting settings from domain server";
|
||||
|
||||
|
@ -451,7 +476,18 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
|
|||
|
||||
if (!_domainConnectionRefusals.contains(reasonMessage)) {
|
||||
_domainConnectionRefusals.insert(reasonMessage);
|
||||
#if defined(Q_OS_ANDROID)
|
||||
emit domainConnectionRefused(reasonMessage, (int)reasonCode, extraInfo);
|
||||
#else
|
||||
if (reasonCode == ConnectionRefusedReason::ProtocolMismatch || reasonCode == ConnectionRefusedReason::NotAuthorized) {
|
||||
_isInErrorState = true;
|
||||
// ingest the error - this is a "hard" connection refusal.
|
||||
emit redirectToErrorDomainURL(_errorDomainURL);
|
||||
} else {
|
||||
emit domainConnectionRefused(reasonMessage, (int)reasonCode, extraInfo);
|
||||
}
|
||||
_lastDomainConnectionError = (int)reasonCode;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
|
|
@ -50,6 +50,11 @@ public:
|
|||
|
||||
QString getHostname() const { return _domainURL.host(); }
|
||||
|
||||
QUrl getErrorDomainURL(){ return _errorDomainURL; }
|
||||
void setErrorDomainURL(const QUrl& url);
|
||||
|
||||
int getLastDomainConnectionError() { return _lastDomainConnectionError; }
|
||||
|
||||
const QHostAddress& getIP() const { return _sockAddr.getAddress(); }
|
||||
void setIPToLocalhost() { _sockAddr.setAddress(QHostAddress(QHostAddress::LocalHost)); }
|
||||
|
||||
|
@ -81,6 +86,10 @@ public:
|
|||
|
||||
void connectedToServerless(std::map<QString, QString> namedPaths);
|
||||
|
||||
void loadedErrorDomain(std::map<QString, QString> namedPaths);
|
||||
// sets domain handler in error state.
|
||||
void setRedirectErrorState(QUrl errorUrl, int reasonCode);
|
||||
|
||||
QString getViewPointFromNamedPath(QString namedPath);
|
||||
|
||||
bool hasSettings() const { return !_settingsObject.isEmpty(); }
|
||||
|
@ -135,6 +144,11 @@ public:
|
|||
* <td><code>4</code></td>
|
||||
* <td>The domain already has its maximum number of users.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td><strong>TimedOut</strong></td>
|
||||
* <td><code>5</code></td>
|
||||
* <td>Connecting to the domain timed out.</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {number} Window.ConnectionRefusedReason
|
||||
|
@ -144,7 +158,8 @@ public:
|
|||
ProtocolMismatch,
|
||||
LoginError,
|
||||
NotAuthorized,
|
||||
TooManyUsers
|
||||
TooManyUsers,
|
||||
TimedOut
|
||||
};
|
||||
|
||||
public slots:
|
||||
|
@ -164,6 +179,8 @@ 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();
|
||||
|
@ -179,6 +196,7 @@ signals:
|
|||
void settingsReceiveFail();
|
||||
|
||||
void domainConnectionRefused(QString reasonMessage, int reason, const QString& extraInfo);
|
||||
void redirectToErrorDomainURL(QUrl errorDomainURL);
|
||||
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
|
||||
|
@ -190,6 +208,7 @@ private:
|
|||
QUuid _uuid;
|
||||
Node::LocalID _localID;
|
||||
QUrl _domainURL;
|
||||
QUrl _errorDomainURL;
|
||||
HifiSockAddr _sockAddr;
|
||||
QUuid _assignmentUUID;
|
||||
QUuid _connectionToken;
|
||||
|
@ -198,6 +217,7 @@ private:
|
|||
HifiSockAddr _iceServerSockAddr;
|
||||
NetworkPeer _icePeer;
|
||||
bool _isConnected { false };
|
||||
bool _isInErrorState { false };
|
||||
QJsonObject _settingsObject;
|
||||
QString _pendingPath;
|
||||
QTimer _settingsTimer;
|
||||
|
@ -210,6 +230,9 @@ private:
|
|||
QTimer _apiRefreshTimer;
|
||||
|
||||
std::map<QString, QString> _namedPaths;
|
||||
|
||||
// domain connection error upon connection refusal.
|
||||
int _lastDomainConnectionError{ -1 };
|
||||
};
|
||||
|
||||
const QString DOMAIN_SPAWNING_POINT { "/0, -10, 0" };
|
||||
|
|
|
@ -35,6 +35,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
];
|
||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||
"system/controllers/controllerScripts.js",
|
||||
"system/interstitialPage.js"
|
||||
//"system/chat.js"
|
||||
];
|
||||
|
||||
|
|
476
scripts/system/interstitialPage.js
Normal file
476
scripts/system/interstitialPage.js
Normal file
|
@ -0,0 +1,476 @@
|
|||
//
|
||||
// interstitialPage.js
|
||||
// scripts/system
|
||||
//
|
||||
// Created by Dante Ruiz on 08/02/2018.
|
||||
// Copyright 2012 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global Script, Controller, Overlays, Quat, MyAvatar, Entities, print, Vec3, AddressManager, Render, Window, Toolbars,
|
||||
Camera, HMD, location, Account, Xform*/
|
||||
|
||||
(function() {
|
||||
Script.include("/~/system/libraries/Xform.js");
|
||||
var DEBUG = false;
|
||||
var MIN_LOADING_PROGRESS = 3.6;
|
||||
var TOTAL_LOADING_PROGRESS = 3.8;
|
||||
var EPSILON = 0.01;
|
||||
var isVisible = false;
|
||||
var VOLUME = 0.4;
|
||||
var tune = SoundCache.getSound("http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/crystals_and_voices.wav");
|
||||
var sample = null;
|
||||
var MAX_LEFT_MARGIN = 1.9;
|
||||
var INNER_CIRCLE_WIDTH = 4.7;
|
||||
var DEFAULT_Z_OFFSET = 5.45;
|
||||
var previousCameraMode = Camera.mode;
|
||||
|
||||
var renderViewTask = Render.getConfig("RenderMainView");
|
||||
var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
var request = Script.require('request').request;
|
||||
var BUTTON_PROPERTIES = {
|
||||
text: "Interstitial"
|
||||
};
|
||||
|
||||
var tablet = null;
|
||||
var button = null;
|
||||
|
||||
// Tips have a character limit of 69
|
||||
var userTips = [
|
||||
"Tip: Visit TheSpot to explore featured domains!",
|
||||
"Tip: Visit our docs online to learn more about scripting!",
|
||||
"Tip: Don't want others invading your personal space? Turn on the Bubble!",
|
||||
"Tip: Want to make a friend? Shake hands with them in VR!",
|
||||
"Tip: Enjoy live music? Visit Rust to dance your heart out!",
|
||||
"Tip: Have you visited BodyMart to check out the new avatars recently?",
|
||||
"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: 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?",
|
||||
"Tip: Print your snapshots from the Snap app to share with others!",
|
||||
"Tip: Log in to make friends, visit new domains, and save avatars!"
|
||||
];
|
||||
|
||||
var DEFAULT_DIMENSIONS = { x: 24, y: 24, z: 24 };
|
||||
|
||||
var loadingSphereID = Overlays.addOverlay("model", {
|
||||
name: "Loading-Sphere",
|
||||
position: Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0.0, y: -1.0, z: 0.0}), Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.95, z: 0})),
|
||||
orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation),
|
||||
url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/black-sphere.fbx",
|
||||
dimensions: DEFAULT_DIMENSIONS,
|
||||
alpha: 1,
|
||||
visible: isVisible,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
parentID: MyAvatar.SELF_ID
|
||||
});
|
||||
|
||||
var anchorOverlay = Overlays.addOverlay("cube", {
|
||||
dimensions: {x: 0.2, y: 0.2, z: 0.2},
|
||||
visible: false,
|
||||
grabbable: false,
|
||||
ignoreRayIntersection: true,
|
||||
localPosition: {x: 0.0, y: getAnchorLocalYOffset(), z: DEFAULT_Z_OFFSET },
|
||||
orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation),
|
||||
solid: true,
|
||||
drawInFront: true,
|
||||
parentID: loadingSphereID
|
||||
});
|
||||
|
||||
|
||||
var domainName = "";
|
||||
var domainNameTextID = Overlays.addOverlay("text3d", {
|
||||
name: "Loading-Destination-Card-Text",
|
||||
localPosition: { x: 0.0, y: 0.8, z: -0.001 },
|
||||
text: domainName,
|
||||
textAlpha: 1,
|
||||
backgroundAlpha: 1,
|
||||
lineHeight: 0.42,
|
||||
visible: isVisible,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var domainText = "";
|
||||
var domainDescription = Overlays.addOverlay("text3d", {
|
||||
name: "Loading-Hostname",
|
||||
localPosition: { x: 0.0, y: 0.32, z: 0.0 },
|
||||
text: domainText,
|
||||
textAlpha: 1,
|
||||
backgroundAlpha: 1,
|
||||
lineHeight: 0.13,
|
||||
visible: isVisible,
|
||||
backgroundAlpha: 0,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var toolTip = "";
|
||||
|
||||
var domainToolTip = Overlays.addOverlay("text3d", {
|
||||
name: "Loading-Tooltip",
|
||||
localPosition: { x: 0.0 , y: -1.6, z: 0.0 },
|
||||
text: toolTip,
|
||||
textAlpha: 1,
|
||||
backgroundAlpha: 1,
|
||||
lineHeight: 0.13,
|
||||
visible: isVisible,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var loadingToTheSpotID = Overlays.addOverlay("image3d", {
|
||||
name: "Loading-Destination-Card-Text",
|
||||
localPosition: { x: 0.0 , y: -1.8, z: 0.0 },
|
||||
url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/goTo_button.png",
|
||||
alpha: 1,
|
||||
dimensions: { x: 1.2, y: 0.6},
|
||||
visible: isVisible,
|
||||
emissive: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var loadingBarPlacard = Overlays.addOverlay("image3d", {
|
||||
name: "Loading-Bar-Placard",
|
||||
localPosition: { x: 0.0, y: -0.99, z: 0.3 },
|
||||
url: Script.resourcesPath() + "images/loadingBar_placard.png",
|
||||
alpha: 1,
|
||||
dimensions: { x: 4, y: 2.8},
|
||||
visible: isVisible,
|
||||
emissive: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var loadingBarProgress = Overlays.addOverlay("image3d", {
|
||||
name: "Loading-Bar-Progress",
|
||||
localPosition: { x: 0.0, y: -0.90, z: 0.0 },
|
||||
url: Script.resourcesPath() + "images/loadingBar_progress.png",
|
||||
alpha: 1,
|
||||
dimensions: {x: 3.8, y: 2.8},
|
||||
visible: isVisible,
|
||||
emissive: true,
|
||||
ignoreRayIntersection: false,
|
||||
drawInFront: true,
|
||||
grabbable: false,
|
||||
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||
parentID: anchorOverlay
|
||||
});
|
||||
|
||||
var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update
|
||||
var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ;
|
||||
var lastInterval = Date.now();
|
||||
var currentDomain = "no domain";
|
||||
var timer = null;
|
||||
var target = 0;
|
||||
|
||||
var connectionToDomainFailed = false;
|
||||
|
||||
|
||||
function getAnchorLocalYOffset() {
|
||||
var loadingSpherePosition = Overlays.getProperty(loadingSphereID, "position");
|
||||
var loadingSphereOrientation = Overlays.getProperty(loadingSphereID, "rotation");
|
||||
var overlayXform = new Xform(loadingSphereOrientation, loadingSpherePosition);
|
||||
var worldToOverlayXform = overlayXform.inv();
|
||||
var headPosition = MyAvatar.getHeadPosition();
|
||||
var headPositionInOverlaySpace = worldToOverlayXform.xformPoint(headPosition);
|
||||
return headPositionInOverlaySpace.y;
|
||||
}
|
||||
|
||||
function getLeftMargin(overlayID, text) {
|
||||
var textSize = Overlays.textSize(overlayID, text);
|
||||
var sizeDifference = ((INNER_CIRCLE_WIDTH - textSize.width) / 2);
|
||||
var leftMargin = -(MAX_LEFT_MARGIN - sizeDifference);
|
||||
return leftMargin;
|
||||
}
|
||||
|
||||
function lerp(a, b, t) {
|
||||
return ((1 - t) * a + t * b);
|
||||
}
|
||||
|
||||
function resetValues() {
|
||||
var properties = {
|
||||
localPosition: { x: 1.85, y: -0.935, z: 0.0 },
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 2.8
|
||||
}
|
||||
};
|
||||
|
||||
Overlays.editOverlay(loadingBarProgress, properties);
|
||||
}
|
||||
|
||||
function startInterstitialPage() {
|
||||
if (timer === null) {
|
||||
updateOverlays(false);
|
||||
startAudio();
|
||||
target = 0;
|
||||
currentProgress = 0.1;
|
||||
connectionToDomainFailed = false;
|
||||
previousCameraMode = Camera.mode;
|
||||
Camera.mode = "first person";
|
||||
timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
|
||||
function startAudio() {
|
||||
sample = Audio.playSound(tune, {
|
||||
localOnly: true,
|
||||
position: MyAvatar.getHeadPosition(),
|
||||
volume: VOLUME
|
||||
});
|
||||
}
|
||||
|
||||
function endAudio() {
|
||||
sample.stop();
|
||||
sample = null;
|
||||
}
|
||||
|
||||
function domainChanged(domain) {
|
||||
if (domain !== currentDomain) {
|
||||
MyAvatar.restoreAnimation();
|
||||
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)";
|
||||
doRequest = false;
|
||||
}
|
||||
var domainNameLeftMargin = getLeftMargin(domainNameTextID, domainName);
|
||||
var textProperties = {
|
||||
text: domainName,
|
||||
leftMargin: domainNameLeftMargin
|
||||
};
|
||||
|
||||
if (doRequest) {
|
||||
var url = Account.metaverseServerURL + '/api/v1/places/' + domain;
|
||||
request({
|
||||
uri: url
|
||||
}, function(error, data) {
|
||||
if (data.status === "success") {
|
||||
var domainInfo = data.data;
|
||||
var domainDescriptionText = domainInfo.place.description;
|
||||
var leftMargin = getLeftMargin(domainDescription, domainDescriptionText);
|
||||
var domainDescriptionProperties = {
|
||||
text: domainDescriptionText,
|
||||
leftMargin: leftMargin
|
||||
};
|
||||
Overlays.editOverlay(domainDescription, domainDescriptionProperties);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var domainDescriptionProperties = {
|
||||
text: ""
|
||||
};
|
||||
Overlays.editOverlay(domainDescription, domainDescriptionProperties);
|
||||
}
|
||||
|
||||
var randomIndex = Math.floor(Math.random() * userTips.length);
|
||||
var tip = userTips[randomIndex];
|
||||
var tipLeftMargin = getLeftMargin(domainToolTip, tip);
|
||||
var toolTipProperties = {
|
||||
text: tip,
|
||||
leftMargin: tipLeftMargin
|
||||
};
|
||||
|
||||
Overlays.editOverlay(domainNameTextID, textProperties);
|
||||
Overlays.editOverlay(domainToolTip, toolTipProperties);
|
||||
|
||||
|
||||
startInterstitialPage();
|
||||
currentDomain = domain;
|
||||
}
|
||||
}
|
||||
|
||||
var THE_PLACE = (HifiAbout.buildVersion === "dev") ? "hifi://TheSpot-dev": "hifi://TheSpot";
|
||||
function clickedOnOverlay(overlayID, event) {
|
||||
if (loadingToTheSpotID === overlayID) {
|
||||
location.handleLookupString(THE_PLACE);
|
||||
}
|
||||
}
|
||||
|
||||
var currentProgress = 0.1;
|
||||
|
||||
function updateOverlays(physicsEnabled) {
|
||||
var properties = {
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
var mainSphereProperties = {
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
var domainTextProperties = {
|
||||
text: domainText,
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
var loadingBarProperties = {
|
||||
dimensions: { x: 0.0, y: 2.8 },
|
||||
visible: !physicsEnabled
|
||||
};
|
||||
|
||||
if (!HMD.active) {
|
||||
MyAvatar.headOrientation = Quat.multiply(Quat.cancelOutRollAndPitch(MyAvatar.headOrientation), Quat.fromPitchYawRollDegrees(-3.0, 0, 0));
|
||||
}
|
||||
|
||||
renderViewTask.getConfig("LightingModel")["enableAmbientLight"] = physicsEnabled;
|
||||
renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = physicsEnabled;
|
||||
renderViewTask.getConfig("LightingModel")["enablePointLight"] = physicsEnabled;
|
||||
Overlays.editOverlay(loadingSphereID, mainSphereProperties);
|
||||
Overlays.editOverlay(loadingToTheSpotID, properties);
|
||||
Overlays.editOverlay(domainNameTextID, properties);
|
||||
Overlays.editOverlay(domainDescription, domainTextProperties);
|
||||
Overlays.editOverlay(domainToolTip, properties);
|
||||
Overlays.editOverlay(loadingBarPlacard, properties);
|
||||
Overlays.editOverlay(loadingBarProgress, loadingBarProperties);
|
||||
|
||||
|
||||
Menu.setIsOptionChecked("Show Overlays", physicsEnabled);
|
||||
if (!HMD.active) {
|
||||
toolbar.writeProperty("visible", physicsEnabled);
|
||||
}
|
||||
|
||||
resetValues();
|
||||
|
||||
if (physicsEnabled) {
|
||||
Camera.mode = previousCameraMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function scaleInterstitialPage(sensorToWorldScale) {
|
||||
var yOffset = getAnchorLocalYOffset();
|
||||
var localPosition = {
|
||||
x: 0.0,
|
||||
y: yOffset,
|
||||
z: 5.45
|
||||
};
|
||||
|
||||
Overlays.editOverlay(anchorOverlay, { localPosition: localPosition });
|
||||
}
|
||||
|
||||
function update() {
|
||||
var physicsEnabled = Window.isPhysicsEnabled();
|
||||
var thisInterval = Date.now();
|
||||
var deltaTime = (thisInterval - lastInterval);
|
||||
lastInterval = thisInterval;
|
||||
|
||||
var domainLoadingProgressPercentage = Window.domainLoadingProgress();
|
||||
|
||||
var progress = MIN_LOADING_PROGRESS * domainLoadingProgressPercentage;
|
||||
if (progress >= target) {
|
||||
target = progress;
|
||||
}
|
||||
|
||||
if ((physicsEnabled && (currentProgress < TOTAL_LOADING_PROGRESS))) {
|
||||
target = TOTAL_LOADING_PROGRESS;
|
||||
}
|
||||
|
||||
currentProgress = lerp(currentProgress, target, 0.2);
|
||||
var properties = {
|
||||
localPosition: { x: (1.85 - (currentProgress / 2) - (-0.029 * (currentProgress / TOTAL_LOADING_PROGRESS))), y: -0.935, z: 0.0 },
|
||||
dimensions: {
|
||||
x: currentProgress,
|
||||
y: 2.8
|
||||
}
|
||||
};
|
||||
|
||||
Overlays.editOverlay(loadingBarProgress, properties);
|
||||
if ((physicsEnabled && (currentProgress >= (TOTAL_LOADING_PROGRESS - EPSILON)))) {
|
||||
updateOverlays((physicsEnabled || connectionToDomainFailed));
|
||||
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.hoverLeaveOverlay.connect(function(overlayID, event) {
|
||||
if (overlayID === loadingToTheSpotID) {
|
||||
Overlays.editOverlay(loadingToTheSpotID, { color: whiteColor});
|
||||
}
|
||||
});
|
||||
|
||||
location.hostChanged.connect(domainChanged);
|
||||
location.lookupResultsFinished.connect(function() {
|
||||
Script.setTimeout(function() {
|
||||
connectionToDomainFailed = !location.isConnected;
|
||||
}, 1200);
|
||||
});
|
||||
|
||||
MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage);
|
||||
MyAvatar.sessionUUIDChanged.connect(function() {
|
||||
var avatarSessionUUID = MyAvatar.sessionUUID;
|
||||
Overlays.editOverlay(loadingSphereID, { parentID: avatarSessionUUID });
|
||||
});
|
||||
|
||||
var toggle = true;
|
||||
if (DEBUG) {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton(BUTTON_PROPERTIES);
|
||||
|
||||
button.clicked.connect(function() {
|
||||
toggle = !toggle;
|
||||
updateOverlays(toggle);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Overlays.deleteOverlay(loadingSphereID);
|
||||
Overlays.deleteOverlay(loadingToTheSpotID);
|
||||
Overlays.deleteOverlay(domainNameTextID);
|
||||
Overlays.deleteOverlay(domainDescription);
|
||||
Overlays.deleteOverlay(domainToolTip);
|
||||
Overlays.deleteOverlay(loadingBarPlacard);
|
||||
Overlays.deleteOverlay(loadingBarProgress);
|
||||
Overlays.deleteOverlay(anchorOverlay);
|
||||
|
||||
if (DEBUG) {
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
|
||||
renderViewTask.getConfig("LightingModel")["enableAmbientLight"] = true;
|
||||
renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = true;
|
||||
renderViewTask.getConfig("LightingModel")["enablePointLight"] = true;
|
||||
Menu.setIsOptionChecked("Show Overlays", true);
|
||||
if (!HMD.active) {
|
||||
toolbar.writeProperty("visible", true);
|
||||
}
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}());
|
Loading…
Reference in a new issue