Merge pull request #13938 from wayne-chen/interstitalMerged

Interstitial Page with 404 Redirect
This commit is contained in:
John Conklin II 2018-09-12 08:39:52 -07:00 committed by GitHub
commit f67deb9f65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 1835 additions and 172 deletions

View file

@ -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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -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();

View 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
}

View file

@ -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";

View file

@ -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;

View file

@ -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);
}

View file

@ -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();

View file

@ -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());

View file

@ -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;

View file

@ -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();
}

View file

@ -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

View file

@ -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();
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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);

View file

@ -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)) {

View file

@ -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() {

View file

@ -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;

View file

@ -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());

View file

@ -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);
}

View file

@ -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);

View file

@ -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 {

View file

@ -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 {

View file

@ -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);
}

View file

@ -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

View file

@ -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>();

View file

@ -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" };

View file

@ -35,6 +35,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
];
var DEFAULT_SCRIPTS_SEPARATE = [
"system/controllers/controllerScripts.js",
"system/interstitialPage.js"
//"system/chat.js"
];

View 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);
}());