mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 00:36:47 +02:00
Merge branch 'master' into hazeZone
This commit is contained in:
commit
349e12c065
41 changed files with 2835 additions and 645 deletions
11
cmake/externals/draco/CMakeLists.txt
vendored
11
cmake/externals/draco/CMakeLists.txt
vendored
|
@ -13,7 +13,7 @@ ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL http://hifi-public.s3.amazonaws.com/dependencies/draco-1.1.0.zip
|
URL http://hifi-public.s3.amazonaws.com/dependencies/draco-1.1.0.zip
|
||||||
URL_MD5 208f8b04c91d5f1c73d731a3ea37c5bb
|
URL_MD5 208f8b04c91d5f1c73d731a3ea37c5bb
|
||||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTRA_CMAKE_FLAGS}
|
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>-$<CONFIG> ${EXTRA_CMAKE_FLAGS}
|
||||||
LOG_DOWNLOAD 1
|
LOG_DOWNLOAD 1
|
||||||
LOG_CONFIGURE 1
|
LOG_CONFIGURE 1
|
||||||
LOG_BUILD 1
|
LOG_BUILD 1
|
||||||
|
@ -23,10 +23,11 @@ ExternalProject_Add(
|
||||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||||
|
|
||||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||||
|
set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$<CONFIG>")
|
||||||
|
|
||||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||||
|
|
||||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of Draco include directories")
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of Draco include directories")
|
||||||
|
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
set(LIB_PREFIX "lib")
|
set(LIB_PREFIX "lib")
|
||||||
|
@ -35,6 +36,6 @@ elseif (WIN32)
|
||||||
set(LIB_EXT "lib")
|
set(LIB_EXT "lib")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${INSTALL_DIR}/lib/${LIB_PREFIX}draco.${LIB_EXT} CACHE FILEPATH "Path to Draco release library")
|
set(${EXTERNAL_NAME_UPPER}_LIBRARY ${SUFFIXED_INSTALL_DIR}/lib/${LIB_PREFIX}draco.${LIB_EXT} CACHE FILEPATH "Path to Draco release library")
|
||||||
set(${EXTERNAL_NAME_UPPER}_ENCODER_LIBRARY ${INSTALL_DIR}/lib/${LIB_PREFIX}dracoenc.${LIB_EXT} CACHE FILEPATH "Path to Draco encoder release library")
|
set(${EXTERNAL_NAME_UPPER}_ENCODER_LIBRARY ${SUFFIXED_INSTALL_DIR}/lib/${LIB_PREFIX}dracoenc.${LIB_EXT} CACHE FILEPATH "Path to Draco encoder release library")
|
||||||
set(${EXTERNAL_NAME_UPPER}_DECODER_LIBRARY ${INSTALL_DIR}/lib/${LIB_PREFIX}dracodec.${LIB_EXT} CACHE FILEPATH "Path to Draco decoder release library")
|
set(${EXTERNAL_NAME_UPPER}_DECODER_LIBRARY ${SUFFIXED_INSTALL_DIR}/lib/${LIB_PREFIX}dracodec.${LIB_EXT} CACHE FILEPATH "Path to Draco decoder release library")
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
{
|
{
|
||||||
"version": 1.9,
|
"version": 2.0,
|
||||||
"settings": [
|
"settings": [
|
||||||
|
{
|
||||||
|
"name": "label",
|
||||||
|
"label": "Label",
|
||||||
|
"settings": [
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "metaverse",
|
"name": "metaverse",
|
||||||
"label": "Metaverse / Networking",
|
"label": "Metaverse / Networking",
|
||||||
|
@ -14,7 +20,8 @@
|
||||||
{
|
{
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"label": "Domain ID",
|
"label": "Domain ID",
|
||||||
"help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank."
|
"help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank.",
|
||||||
|
"advanced": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "automatic_networking",
|
"name": "automatic_networking",
|
||||||
|
@ -82,11 +89,13 @@
|
||||||
{
|
{
|
||||||
"name": "description",
|
"name": "description",
|
||||||
"label": "Description",
|
"label": "Description",
|
||||||
|
"advanced": true,
|
||||||
"help": "A description of your domain (256 character limit)."
|
"help": "A description of your domain (256 character limit)."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maturity",
|
"name": "maturity",
|
||||||
"label": "Maturity",
|
"label": "Maturity",
|
||||||
|
"advanced": true,
|
||||||
"help": "A maturity rating, available as a guideline for content on your domain.",
|
"help": "A maturity rating, available as a guideline for content on your domain.",
|
||||||
"default": "unrated",
|
"default": "unrated",
|
||||||
"type": "select",
|
"type": "select",
|
||||||
|
@ -116,6 +125,7 @@
|
||||||
{
|
{
|
||||||
"name": "hosts",
|
"name": "hosts",
|
||||||
"label": "Hosts",
|
"label": "Hosts",
|
||||||
|
"advanced": true,
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"can_add_new_rows": true,
|
"can_add_new_rows": true,
|
||||||
"help": "Usernames of hosts who can reliably show your domain to new visitors.",
|
"help": "Usernames of hosts who can reliably show your domain to new visitors.",
|
||||||
|
@ -131,6 +141,7 @@
|
||||||
{
|
{
|
||||||
"name": "tags",
|
"name": "tags",
|
||||||
"label": "Tags",
|
"label": "Tags",
|
||||||
|
"advanced": true,
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"can_add_new_rows": true,
|
"can_add_new_rows": true,
|
||||||
"help": "Common categories under which your domain falls.",
|
"help": "Common categories under which your domain falls.",
|
||||||
|
@ -1625,6 +1636,29 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wizard",
|
||||||
|
"label": "Setup Wizard",
|
||||||
|
"restart": false,
|
||||||
|
"hidden": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"name": "cloud_domain",
|
||||||
|
"type": "checkbox",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "steps_completed",
|
||||||
|
"type": "int",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "completed_once",
|
||||||
|
"type": "checkbox",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
body {
|
body {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
|
margin-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[hidden] {
|
[hidden] {
|
||||||
|
@ -27,14 +28,14 @@ body {
|
||||||
.table .value-row td,
|
.table .value-row td,
|
||||||
.table .value-category td,
|
.table .value-category td,
|
||||||
.table .inputs td {
|
.table .inputs td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table .table-checkbox {
|
.table .table-checkbox {
|
||||||
/* Fix IE sizing checkboxes to fill table cell */
|
/* Fix IE sizing checkboxes to fill table cell */
|
||||||
width: auto;
|
width: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.value-category:not(.inputs) {
|
.value-category:not(.inputs) {
|
||||||
|
@ -80,8 +81,10 @@ span.port {
|
||||||
}
|
}
|
||||||
|
|
||||||
#setup-sidebar.affix {
|
#setup-sidebar.affix {
|
||||||
position: fixed;
|
/* This overrides a case where going to the bottom of the page,
|
||||||
top: 15px;
|
* then scrolling up, causes `position: relative` to be added to the style
|
||||||
|
*/
|
||||||
|
position: fixed !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#setup-sidebar button {
|
#setup-sidebar button {
|
||||||
|
@ -145,55 +148,55 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
caption {
|
caption {
|
||||||
color: #333;
|
color: #333;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
table > tbody > .headers > td {
|
table > tbody > .headers > td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
table .headers + .headers td {
|
table .headers + .headers td {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #222;
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
#security table .headers td + td {
|
#security table .headers td + td {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip.top .tooltip-arrow {
|
.tooltip.top .tooltip-arrow {
|
||||||
border-top-color: #fff;
|
border-top-color: #fff;
|
||||||
border-width: 10px 10px 0;
|
border-width: 10px 10px 0;
|
||||||
margin-bottom: -5px;
|
margin-bottom: -5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip-inner {
|
.tooltip-inner {
|
||||||
padding: 20px 20px 10px 20px;
|
padding: 20px 20px 10px 20px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #333;
|
color: #333;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
box-shadow: 0 3px 8px 8px #e8e8e8;
|
box-shadow: 0 3px 8px 8px #e8e8e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip.in {
|
.tooltip.in {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip-inner ul {
|
.tooltip-inner ul {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip-inner li {
|
.tooltip-inner li {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#security .tooltip-inner {
|
#security .tooltip-inner {
|
||||||
max-width: 520px;
|
max-width: 520px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#xs-advanced-container {
|
#xs-advanced-container {
|
||||||
|
@ -241,6 +244,20 @@ table .headers + .headers td {
|
||||||
animation-delay: -0.16s;
|
animation-delay: -0.16s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.col-centered {
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-hack-parent {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-hack {
|
||||||
|
text-align: left;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
@-webkit-keyframes bouncedelay {
|
@-webkit-keyframes bouncedelay {
|
||||||
0%, 80%, 100% { -webkit-transform: scale(0.0) }
|
0%, 80%, 100% { -webkit-transform: scale(0.0) }
|
||||||
40% { -webkit-transform: scale(1.0) }
|
40% { -webkit-transform: scale(1.0) }
|
||||||
|
@ -255,3 +272,50 @@ table .headers + .headers td {
|
||||||
-webkit-transform: scale(1.0);
|
-webkit-transform: scale(1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* From https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d */
|
||||||
|
.glyphicon-refresh-animate {
|
||||||
|
-animation: spin .7s infinite linear;
|
||||||
|
-ms-animation: spin .7s infinite linear;
|
||||||
|
-webkit-animation: spinw .7s infinite linear;
|
||||||
|
-moz-animation: spinm .7s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: scale(1) rotate(0deg); }
|
||||||
|
to { transform: scale(1) rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spinw {
|
||||||
|
from { -webkit-transform: rotate(0deg); }
|
||||||
|
to { -webkit-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes spinm {
|
||||||
|
from { -moz-transform: rotate(0deg); }
|
||||||
|
to { -moz-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-text {
|
||||||
|
padding-top: 10px;
|
||||||
|
color: #EB5757;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-connected-header {
|
||||||
|
color: #6FCF97;
|
||||||
|
font-size: 30px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#visit-domain-link,
|
||||||
|
.blue-link {
|
||||||
|
font-size: 14px;
|
||||||
|
text-decoration-line: underline;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #2F80ED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#manage-cloud-domains-link {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
BIN
domain-server/resources/web/favicon.ico
Normal file
BIN
domain-server/resources/web/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -13,7 +13,7 @@
|
||||||
<script src='/js/sweetalert.min.js'></script>
|
<script src='/js/sweetalert.min.js'></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-default" role="navigation">
|
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- Brand and toggle get grouped for better mobile display -->
|
<!-- Brand and toggle get grouped for better mobile display -->
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="/">domain-server</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
|
@ -40,6 +39,7 @@
|
||||||
<li><a href="/settings/">Settings</a></li>
|
<li><a href="/settings/">Settings</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-right navbar-nav">
|
<ul class="nav navbar-right navbar-nav">
|
||||||
|
<li><a id="visit-domain-link" target="_blank" style="display: none;">Visit domain in VR</a></li>
|
||||||
<li><a href="#" id="restart-server"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
|
<li><a href="#" id="restart-server"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
25
domain-server/resources/web/images/checkmark.svg
Normal file
25
domain-server/resources/web/images/checkmark.svg
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<svg width="676" height="676" viewBox="0 0 676 676" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>CongratulationImage</title>
|
||||||
|
<desc>Created using Figma</desc>
|
||||||
|
<g id="Canvas" transform="matrix(4 0 0 4 -21208 -17980)">
|
||||||
|
<g id="CongratulationImage">
|
||||||
|
<g id="Ellipse">
|
||||||
|
<use xlink:href="#path0_fill" transform="translate(5302 4495)" fill="#FFFFFF"/>
|
||||||
|
<mask id="mask0_outline_ins">
|
||||||
|
<use xlink:href="#path0_fill" fill="white" transform="translate(5302 4495)"/>
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_outline_ins)">
|
||||||
|
<use xlink:href="#path1_stroke_2x" transform="translate(5302 4495)" fill="#219653"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="Vector 2">
|
||||||
|
<use xlink:href="#path2_stroke" transform="translate(5355 4559)" fill="#219653"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<path id="path0_fill" d="M 169 84.5C 169 131.168 131.168 169 84.5 169C 37.8319 169 0 131.168 0 84.5C 0 37.8319 37.8319 0 84.5 0C 131.168 0 169 37.8319 169 84.5Z"/>
|
||||||
|
<path id="path1_stroke_2x" d="M 154 84.5C 154 122.884 122.884 154 84.5 154L 84.5 184C 139.452 184 184 139.452 184 84.5L 154 84.5ZM 84.5 154C 46.1162 154 15 122.884 15 84.5L -15 84.5C -15 139.452 29.5477 184 84.5 184L 84.5 154ZM 15 84.5C 15 46.1162 46.1162 15 84.5 15L 84.5 -15C 29.5477 -15 -15 29.5477 -15 84.5L 15 84.5ZM 84.5 15C 122.884 15 154 46.1162 154 84.5L 184 84.5C 184 29.5477 139.452 -15 84.5 -15L 84.5 15Z"/>
|
||||||
|
<path id="path2_stroke" d="M 5.18747 19.8031C 2.19593 16.9382 -2.5517 17.0408 -5.41666 20.0323C -8.28162 23.0238 -8.17901 27.7715 -5.18747 30.6364L 5.18747 19.8031ZM 20.6541 45L 15.4667 50.4167C 18.3816 53.2083 22.9831 53.1924 25.8787 50.3809L 20.6541 45ZM 72.2246 5.38085C 75.1964 2.49539 75.2663 -2.25283 72.3809 -5.2246C 69.4954 -8.19636 64.7472 -8.26632 61.7754 -5.38085L 72.2246 5.38085ZM -5.18747 30.6364L 15.4667 50.4167L 25.8416 39.5833L 5.18747 19.8031L -5.18747 30.6364ZM 25.8787 50.3809L 72.2246 5.38085L 61.7754 -5.38085L 15.4295 39.6191L 25.8787 50.3809Z"/>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
|
@ -32,7 +32,6 @@ $(document).ready(function(){
|
||||||
$('ul.nav a').filter(function() {
|
$('ul.nav a').filter(function() {
|
||||||
return this.href == url;
|
return this.href == url;
|
||||||
}).parent().addClass('active');
|
}).parent().addClass('active');
|
||||||
|
|
||||||
$('body').on('click', '#restart-server', function(e) {
|
$('body').on('click', '#restart-server', function(e) {
|
||||||
swal( {
|
swal( {
|
||||||
title: "Are you sure?",
|
title: "Are you sure?",
|
||||||
|
@ -46,4 +45,4 @@ $(document).ready(function(){
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
393
domain-server/resources/web/js/shared.js
Normal file
393
domain-server/resources/web/js/shared.js
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
var Settings = {
|
||||||
|
showAdvanced: false,
|
||||||
|
ADVANCED_CLASS: 'advanced-setting',
|
||||||
|
DEPRECATED_CLASS: 'deprecated-setting',
|
||||||
|
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
||||||
|
DATA_ROW_CLASS: 'value-row',
|
||||||
|
DATA_COL_CLASS: 'value-col',
|
||||||
|
DATA_CATEGORY_CLASS: 'value-category',
|
||||||
|
ADD_ROW_BUTTON_CLASS: 'add-row',
|
||||||
|
ADD_ROW_SPAN_CLASSES: 'glyphicon glyphicon-plus add-row',
|
||||||
|
DEL_ROW_BUTTON_CLASS: 'del-row',
|
||||||
|
DEL_ROW_SPAN_CLASSES: 'glyphicon glyphicon-remove del-row',
|
||||||
|
ADD_CATEGORY_BUTTON_CLASS: 'add-category',
|
||||||
|
ADD_CATEGORY_SPAN_CLASSES: 'glyphicon glyphicon-plus add-category',
|
||||||
|
TOGGLE_CATEGORY_COLUMN_CLASS: 'toggle-category',
|
||||||
|
TOGGLE_CATEGORY_SPAN_CLASS: 'toggle-category-icon',
|
||||||
|
TOGGLE_CATEGORY_SPAN_CLASSES: 'glyphicon toggle-category-icon',
|
||||||
|
TOGGLE_CATEGORY_EXPANDED_CLASS: 'glyphicon-triangle-bottom',
|
||||||
|
TOGGLE_CATEGORY_CONTRACTED_CLASS: 'glyphicon-triangle-right',
|
||||||
|
DEL_CATEGORY_BUTTON_CLASS: 'del-category',
|
||||||
|
DEL_CATEGORY_SPAN_CLASSES: 'glyphicon glyphicon-remove del-category',
|
||||||
|
MOVE_UP_BUTTON_CLASS: 'move-up',
|
||||||
|
MOVE_UP_SPAN_CLASSES: 'glyphicon glyphicon-chevron-up move-up',
|
||||||
|
MOVE_DOWN_BUTTON_CLASS: 'move-down',
|
||||||
|
MOVE_DOWN_SPAN_CLASSES: 'glyphicon glyphicon-chevron-down move-down',
|
||||||
|
TABLE_BUTTONS_CLASS: 'buttons',
|
||||||
|
ADD_DEL_BUTTONS_CLASS: 'add-del-buttons',
|
||||||
|
ADD_DEL_BUTTONS_CLASSES: 'buttons add-del-buttons',
|
||||||
|
REORDER_BUTTONS_CLASS: 'reorder-buttons',
|
||||||
|
REORDER_BUTTONS_CLASSES: 'buttons reorder-buttons',
|
||||||
|
NEW_ROW_CLASS: 'new-row',
|
||||||
|
CONNECT_ACCOUNT_BTN_ID: 'connect-account-btn',
|
||||||
|
DISCONNECT_ACCOUNT_BTN_ID: 'disconnect-account-btn',
|
||||||
|
CREATE_DOMAIN_ID_BTN_ID: 'create-domain-btn',
|
||||||
|
CHOOSE_DOMAIN_ID_BTN_ID: 'choose-domain-btn',
|
||||||
|
GET_TEMPORARY_NAME_BTN_ID: 'get-temp-name-btn',
|
||||||
|
DOMAIN_ID_SELECTOR: '[name="metaverse.id"]',
|
||||||
|
ACCESS_TOKEN_SELECTOR: '[name="metaverse.access_token"]',
|
||||||
|
PLACES_TABLE_ID: 'places-table',
|
||||||
|
ADD_PLACE_BTN_ID: 'add-place-btn',
|
||||||
|
FORM_ID: 'settings-form',
|
||||||
|
INVALID_ROW_CLASS: 'invalid-input',
|
||||||
|
DATA_ROW_INDEX: 'data-row-index'
|
||||||
|
};
|
||||||
|
|
||||||
|
var URLs = {
|
||||||
|
// STABLE METAVERSE_URL: https://metaverse.highfidelity.com
|
||||||
|
// STAGING METAVERSE_URL: https://staging.highfidelity.com
|
||||||
|
METAVERSE_URL: 'https://metaverse.highfidelity.com',
|
||||||
|
PLACE_URL: 'https://hifi.place',
|
||||||
|
};
|
||||||
|
|
||||||
|
var Strings = {
|
||||||
|
LOADING_SETTINGS_ERROR: "There was a problem loading the domain settings.\nPlease refresh the page to try again.",
|
||||||
|
|
||||||
|
CHOOSE_DOMAIN_BUTTON: "Choose from my domains",
|
||||||
|
CREATE_DOMAIN_BUTTON: "Create new domain ID",
|
||||||
|
CREATE_DOMAIN_SUCCESS_JUST_CONNECTED: "We connnected your High Fidelity account and created a new domain ID for this machine.",
|
||||||
|
CREATE_DOMAIN_SUCCESS: "We created a new domain ID for this machine.",
|
||||||
|
|
||||||
|
// When a place modification fails, they will be brought back to the previous
|
||||||
|
// dialog with new path still set, allowing them to retry immediately, and without
|
||||||
|
// having to type the new path in again.
|
||||||
|
EDIT_PLACE_TITLE: "Modify Viewpoint or Path",
|
||||||
|
EDIT_PLACE_ERROR: "Failed to update place path. Please try again.",
|
||||||
|
EDIT_PLACE_CONFIRM_BUTTON: "Save",
|
||||||
|
EDIT_PLACE_CONFIRM_BUTTON_PENDING: "Saving...",
|
||||||
|
EDIT_PLACE_CANCEL_BUTTON: "Cancel",
|
||||||
|
|
||||||
|
REMOVE_PLACE_TITLE: "Are you sure you want to remove <strong>{{place}}</strong>?",
|
||||||
|
REMOVE_PLACE_ERROR: "Failed to remove place. Please try again.",
|
||||||
|
REMOVE_PLACE_DELETE_BUTTON: "Delete",
|
||||||
|
REMOVE_PLACE_DELETE_BUTTON_PENDING: "Deleting...",
|
||||||
|
REMOVE_PLACE_CANCEL_BUTTON: "Cancel",
|
||||||
|
|
||||||
|
ADD_PLACE_TITLE: "Choose a place",
|
||||||
|
ADD_PLACE_MESSAGE: "Choose the High Fidelity place to point at this domain server.",
|
||||||
|
ADD_PLACE_CONFIRM_BUTTON: "Choose place",
|
||||||
|
ADD_PLACE_CONFIRM_BUTTON_PENDING: "Saving...",
|
||||||
|
ADD_PLACE_CANCEL_BUTTON: "Cancel",
|
||||||
|
ADD_PLACE_UNKNOWN_ERROR: "There was an error adding this place name.",
|
||||||
|
|
||||||
|
ADD_PLACE_NO_PLACES_MESSAGE: "<p>You do not have any places in your High Fidelity account."
|
||||||
|
+ "<br/><br/>Go to your <a href='https://metaverse.highfidelity.com/user/places/new'>places page</a> to create a new one. Once your place is created re-open this dialog to select it.</p>",
|
||||||
|
ADD_PLACE_NO_PLACES_BUTTON: "Create new place",
|
||||||
|
ADD_PLACE_UNABLE_TO_LOAD_ERROR: "We were unable to load your place names. Please try again later.",
|
||||||
|
ADD_PLACE_LOADING_DIALOG: "Loading your places...",
|
||||||
|
|
||||||
|
ADD_PLACE_NOT_CONNECTED_TITLE: "Access token required",
|
||||||
|
ADD_PLACE_NOT_CONNECTED_MESSAGE: "You must have an access token to query your High Fidelity places.<br><br>Please follow the instructions on the settings page to add an access token.",
|
||||||
|
};
|
||||||
|
|
||||||
|
var DOMAIN_ID_TYPE_NONE = 0;
|
||||||
|
var DOMAIN_ID_TYPE_TEMP = 1;
|
||||||
|
var DOMAIN_ID_TYPE_FULL = 2;
|
||||||
|
var DOMAIN_ID_TYPE_UNKNOWN = 3;
|
||||||
|
|
||||||
|
function domainIDIsSet() {
|
||||||
|
return Settings.data.values.metaverse.id.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentDomainIDType() {
|
||||||
|
if (!domainIDIsSet()) {
|
||||||
|
return DOMAIN_ID_TYPE_NONE;
|
||||||
|
}
|
||||||
|
if (typeof DomainInfo === 'undefined') {
|
||||||
|
return DOMAIN_ID_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
if (DomainInfo !== null) {
|
||||||
|
if (DomainInfo.name !== undefined) {
|
||||||
|
return DOMAIN_ID_TYPE_TEMP;
|
||||||
|
}
|
||||||
|
return DOMAIN_ID_TYPE_FULL;
|
||||||
|
}
|
||||||
|
return DOMAIN_ID_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLoadingDialog(msg) {
|
||||||
|
var message = '<div class="text-center">';
|
||||||
|
message += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> ' + msg;
|
||||||
|
message += '</div>';
|
||||||
|
|
||||||
|
return bootbox.dialog({
|
||||||
|
message: message,
|
||||||
|
closeButton: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendUpdatePlaceRequest(id, path, domainID, clearDomainID, onSuccess, onError) {
|
||||||
|
var data = {
|
||||||
|
place_id: id,
|
||||||
|
path: path
|
||||||
|
};
|
||||||
|
if (domainID) {
|
||||||
|
data.domain_id = domainID;
|
||||||
|
}
|
||||||
|
if (clearDomainID) {
|
||||||
|
data.domain_id = null;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/places',
|
||||||
|
type: 'PUT',
|
||||||
|
data: data,
|
||||||
|
success: onSuccess,
|
||||||
|
error: onError
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAdded) {
|
||||||
|
if (accessToken) {
|
||||||
|
|
||||||
|
var loadingDialog = showLoadingDialog(Strings.ADD_PLACE_LOADING_DIALOG);
|
||||||
|
|
||||||
|
$.ajax("/api/places", {
|
||||||
|
dataType: 'json',
|
||||||
|
jsonp: false,
|
||||||
|
success: function(data) {
|
||||||
|
if (data.status == 'success') {
|
||||||
|
var modal_buttons = {
|
||||||
|
cancel: {
|
||||||
|
label: Strings.ADD_PLACE_CANCEL_BUTTON,
|
||||||
|
className: 'add-place-cancel-button btn-default'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialog;
|
||||||
|
var modal_body;
|
||||||
|
|
||||||
|
if (data.data.places.length) {
|
||||||
|
var places_by_id = {};
|
||||||
|
|
||||||
|
modal_body = $('<div>');
|
||||||
|
|
||||||
|
modal_body.append($("<p>Choose a place name that you own or <a href='" + URLs.METAVERSE_URL + "/user/places' target='_blank'>register a new place name</a></p>"));
|
||||||
|
|
||||||
|
var currentDomainIDType = getCurrentDomainIDType();
|
||||||
|
if (currentDomainIDType === DOMAIN_ID_TYPE_TEMP) {
|
||||||
|
var warning = "<div class='domain-loading-error alert alert-warning'>";
|
||||||
|
warning += "If you choose a place name it will replace your current temporary place name.";
|
||||||
|
warning += "</div>";
|
||||||
|
modal_body.append(warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup a select box for the returned places
|
||||||
|
modal_body.append($("<label for='place-name-select'>Places</label>"));
|
||||||
|
place_select = $("<select id='place-name-select' class='form-control'></select>");
|
||||||
|
_.each(data.data.places, function(place) {
|
||||||
|
places_by_id[place.id] = place;
|
||||||
|
place_select.append("<option value='" + place.id + "'>" + place.name + "</option>");
|
||||||
|
})
|
||||||
|
modal_body.append(place_select);
|
||||||
|
modal_body.append($("<p id='place-name-warning' class='warning-text' style='display: none'>This place name already points to a place or path. Saving this would overwrite the previous settings associated with it.</p>"));
|
||||||
|
|
||||||
|
if (forcePathTo === undefined || forcePathTo === null) {
|
||||||
|
var path = "<div class='form-group'>";
|
||||||
|
path += "<label for='place-path-input' class='control-label'>Path</label>";
|
||||||
|
path += "<input type='text' id='place-path-input' class='form-control' value='/'>";
|
||||||
|
path += "</div>";
|
||||||
|
modal_body.append($(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
var place_select = modal_body.find("#place-name-select")
|
||||||
|
place_select.change(function(ev) {
|
||||||
|
var warning = modal_body.find("#place-name-warning");
|
||||||
|
var place = places_by_id[$(this).val()];
|
||||||
|
if (place === undefined || place.pointee === null) {
|
||||||
|
warning.hide();
|
||||||
|
} else {
|
||||||
|
warning.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
place_select.trigger('change');
|
||||||
|
|
||||||
|
modal_buttons["success"] = {
|
||||||
|
label: Strings.ADD_PLACE_CONFIRM_BUTTON,
|
||||||
|
className: 'add-place-confirm-button btn btn-primary',
|
||||||
|
callback: function() {
|
||||||
|
var placeID = $('#place-name-select').val();
|
||||||
|
// set the place ID on the form
|
||||||
|
$(Settings.place_ID_SELECTOR).val(placeID).change();
|
||||||
|
|
||||||
|
if (forcePathTo === undefined || forcePathTo === null) {
|
||||||
|
var placePath = $('#place-path-input').val();
|
||||||
|
} else {
|
||||||
|
var placePath = forcePathTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.add-place-confirm-button').attr('disabled', 'disabled');
|
||||||
|
$('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON_PENDING);
|
||||||
|
$('.add-place-cancel-button').attr('disabled', 'disabled');
|
||||||
|
|
||||||
|
function finalizeSaveDomainID(domainID) {
|
||||||
|
var jsonSettings = {
|
||||||
|
metaverse: {
|
||||||
|
id: domainID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dialog = showLoadingDialog("Waiting for Domain Server to restart...");
|
||||||
|
$.ajax('/settings.json', {
|
||||||
|
data: JSON.stringify(jsonSettings),
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'POST'
|
||||||
|
}).done(function(data) {
|
||||||
|
if (data.status == "success") {
|
||||||
|
waitForDomainServerRestart(function() {
|
||||||
|
dialog.modal('hide');
|
||||||
|
if (onSuccessfullyAdded) {
|
||||||
|
onSuccessfullyAdded(places_by_id[placeID].name, domainID);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
bootbox.alert("Failed to add place");
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
bootbox.alert("Failed to add place");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishSettingUpPlace(domainID) {
|
||||||
|
sendUpdatePlaceRequest(
|
||||||
|
placeID,
|
||||||
|
placePath,
|
||||||
|
domainID,
|
||||||
|
false,
|
||||||
|
function(data) {
|
||||||
|
$(Settings.DOMAIN_ID_SELECTOR).val(domainID).change();
|
||||||
|
dialog.modal('hide')
|
||||||
|
if (domainID) {
|
||||||
|
finalizeSaveDomainID(domainID);
|
||||||
|
} else {
|
||||||
|
if (onSuccessfullyAdded) {
|
||||||
|
onSuccessfullyAdded(places_by_id[placeID].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(data) {
|
||||||
|
$('.add-place-confirm-button').removeAttr('disabled');
|
||||||
|
$('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON);
|
||||||
|
$('.add-place-cancel-button').removeAttr('disabled');
|
||||||
|
bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentDomainIDType === DOMAIN_ID_TYPE_FULL) {
|
||||||
|
finishSettingUpPlace();
|
||||||
|
} else {
|
||||||
|
sendCreateDomainRequest(function(domainID) {
|
||||||
|
console.log("Created domain", domainID);
|
||||||
|
finishSettingUpPlace(domainID);
|
||||||
|
}, function() {
|
||||||
|
$('.add-place-confirm-button').removeAttr('disabled');
|
||||||
|
$('.add-place-confirm-button').html(Strings.ADD_PLACE_CONFIRM_BUTTON);
|
||||||
|
$('.add-place-cancel-button').removeAttr('disabled');
|
||||||
|
bootbox.alert(Strings.ADD_PLACE_UNKNOWN_ERROR);
|
||||||
|
bootbox.alert("FAIL");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modal_buttons["success"] = {
|
||||||
|
label: Strings.ADD_PLACE_NO_PLACES_BUTTON,
|
||||||
|
callback: function() {
|
||||||
|
window.open(URLs.METAVERSE_URL + "/user/places", '_blank');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modal_body = Strings.ADD_PLACE_NO_PLACES_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog = bootbox.dialog({
|
||||||
|
title: Strings.ADD_PLACE_TITLE,
|
||||||
|
message: modal_body,
|
||||||
|
closeButton: false,
|
||||||
|
buttons: modal_buttons
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
loadingDialog.modal('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
bootbox.alert({
|
||||||
|
title: Strings.ADD_PLACE_NOT_CONNECTED_TITLE,
|
||||||
|
message: Strings.ADD_PLACE_NOT_CONNECTED_MESSAGE
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendCreateDomainRequest(onSuccess, onError) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/domains',
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'POST',
|
||||||
|
data: { label: "" },
|
||||||
|
success: function(data) {
|
||||||
|
onSuccess(data.domain.id);
|
||||||
|
},
|
||||||
|
error: onError
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForDomainServerRestart(callback) {
|
||||||
|
function checkForDomainUp() {
|
||||||
|
$.ajax('', {
|
||||||
|
success: function() {
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
setTimeout(checkForDomainUp, 50);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(checkForDomainUp, 10);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareAccessTokenPrompt(callback) {
|
||||||
|
swal({
|
||||||
|
title: "Connect Account",
|
||||||
|
type: "input",
|
||||||
|
text: "Paste your created access token here." +
|
||||||
|
"</br></br>If you did not successfully create an access token click cancel below and attempt to connect your account again.</br></br>",
|
||||||
|
showCancelButton: true,
|
||||||
|
closeOnConfirm: false,
|
||||||
|
html: true
|
||||||
|
}, function(inputValue){
|
||||||
|
if (inputValue === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputValue === "") {
|
||||||
|
swal.showInputError("Please paste your access token in the input field.")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback(inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
swal.close();
|
||||||
|
});
|
||||||
|
}
|
|
@ -9,16 +9,18 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
||||||
<div id="setup-sidebar" class="hidden-xs" data-spy="affix" data-offset-top="55" data-clampedwidth="#setup-sidebar-col">
|
<div id="setup-sidebar" data-clampedwidth="#setup-sidebar-col">
|
||||||
<script id="list-group-template" type="text/template">
|
<script id="list-group-template" type="text/template">
|
||||||
<% _.each(descriptions, function(group){ %>
|
<% _.each(descriptions, function(group){ %>
|
||||||
<% panelID = group.name ? group.name : group.html_id %>
|
<% if (!group.hidden) { %>
|
||||||
<li>
|
<% panelID = group.name ? group.name : group.html_id %>
|
||||||
<a href="#<%- panelID %>" class="list-group-item">
|
<li>
|
||||||
<span class="badge"></span>
|
<a href="#<%- panelID %>" class="list-group-item">
|
||||||
<%- group.label %>
|
<span class="badge"></span>
|
||||||
</a>
|
<%- group.label %>
|
||||||
</li>
|
</a>
|
||||||
|
</li>
|
||||||
|
<% } %>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -26,49 +28,63 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<button id="advanced-toggle-button" class="btn btn-info advanced-toggle">Show advanced</button>
|
<button id="advanced-toggle-button" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||||
<button class="btn btn-success save-button">Save</button>
|
<button class="btn btn-success save-button" disabled>Save</button>
|
||||||
|
<div id="manage-cloud-domains-link" style="display: none;">
|
||||||
|
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Manage Cloud Hosted Domains</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-9 col-sm-9 col-xs-12">
|
<div class="col-md-9 col-sm-9 col-xs-12">
|
||||||
|
|
||||||
<div id="xs-advanced-container" class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
<div id="xs-advanced-container" class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
||||||
<button id="advanced-toggle-button-xs" class="btn btn-info advanced-toggle">Show advanced</button>
|
<button id="advanced-toggle-button-xs" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
|
|
||||||
|
<div id="cloud-domains-alert" class="alert alert-info alert-dismissible" role="alert" style="display: none;">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<span class="alert-link">
|
||||||
|
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Visit Cloud Hosted Domains</a> to manage all your cloud domains
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form id="settings-form" role="form">
|
<form id="settings-form" role="form">
|
||||||
|
|
||||||
<script id="panels-template" type="text/template">
|
<script id="panels-template" type="text/template">
|
||||||
<% _.each(descriptions, function(group){ %>
|
<% _.each(descriptions, function(group){ %>
|
||||||
<% var settings = _.partition(group.settings, function(value, index) { return !value.deprecated })[0] %>
|
<% if (!group.hidden) { %>
|
||||||
<% split_settings = _.partition(settings, function(value, index) { return !value.advanced }) %>
|
<% var settings = _.partition(group.settings, function(value, index) { return !value.deprecated })[0] %>
|
||||||
<% isAdvanced = _.isEmpty(split_settings[0]) %>
|
<% split_settings = _.partition(settings, function(value, index) { return !value.advanced }) %>
|
||||||
<% if (isAdvanced) { %>
|
<% isAdvanced = _.isEmpty(split_settings[0]) && !_.isEmpty(split_settings[1]) %>
|
||||||
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
<% if (isAdvanced) { %>
|
||||||
<% } %>
|
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% isGrouped = !!group.name %>
|
<% isGrouped = !!group.name %>
|
||||||
<% panelID = isGrouped ? group.name : group.html_id %>
|
<% panelID = isGrouped ? group.name : group.html_id %>
|
||||||
|
|
||||||
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
||||||
id="<%- panelID %>">
|
id="<%- panelID %>">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title"><%- group.label %></h3>
|
<h3 class="panel-title"><%- group.label %></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<% _.each(split_settings[0], function(setting) { %>
|
<% _.each(split_settings[0], function(setting) { %>
|
||||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
|
||||||
<%= getFormGroup(keypath, setting, values, false) %>
|
|
||||||
<% }); %>
|
|
||||||
<% if (!_.isEmpty(split_settings[1])) { %>
|
|
||||||
<% $("#advanced-toggle-button").show() %>
|
|
||||||
<% _.each(split_settings[1], function(setting) { %>
|
|
||||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||||
<%= getFormGroup(keypath, setting, values, true) %>
|
<%= getFormGroup(keypath, setting, values, false) %>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
<% }%>
|
<% if (!_.isEmpty(split_settings[1])) { %>
|
||||||
|
<% $("#advanced-toggle-button").show() %>
|
||||||
|
<% _.each(split_settings[1], function(setting) { %>
|
||||||
|
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||||
|
<%= getFormGroup(keypath, setting, values, true) %>
|
||||||
|
<% }); %>
|
||||||
|
<% }%>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<% } %>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</script>
|
</script>
|
||||||
<div id="panels"></div>
|
<div id="panels"></div>
|
||||||
|
@ -85,8 +101,9 @@
|
||||||
<script src='/js/underscore-min.js'></script>
|
<script src='/js/underscore-min.js'></script>
|
||||||
<script src='/js/underscore-keypath.min.js'></script>
|
<script src='/js/underscore-keypath.min.js'></script>
|
||||||
<script src='/js/bootbox.min.js'></script>
|
<script src='/js/bootbox.min.js'></script>
|
||||||
<script src='js/bootstrap-switch.min.js'></script>
|
<script src='/js/sha256.js'></script>
|
||||||
<script src='js/settings.js'></script>
|
|
||||||
<script src='js/form2js.min.js'></script>
|
<script src='js/form2js.min.js'></script>
|
||||||
<script src='js/sha256.js'></script>
|
<script src='js/bootstrap-switch.min.js'></script>
|
||||||
|
<script src='/js/shared.js'></script>
|
||||||
|
<script src='js/settings.js'></script>
|
||||||
<!--#include virtual="page-end.html"-->
|
<!--#include virtual="page-end.html"-->
|
||||||
|
|
File diff suppressed because it is too large
Load diff
89
domain-server/resources/web/wizard/css/style.css
Normal file
89
domain-server/resources/web/wizard/css/style.css
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
label {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
color: #373A3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
line-height: 26px;
|
||||||
|
font-size: 24px;
|
||||||
|
|
||||||
|
color: #373A3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-description {
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
color: #818A91;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-info {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
color: #373A3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
#admin-row {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-question {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-account-btn {
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 205px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#place-name-group {
|
||||||
|
margin-top: 42px;
|
||||||
|
margin-bottom: 140px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#place-name-link {
|
||||||
|
line-height: 38px;
|
||||||
|
font-size: 32px;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
color: #373A3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
#place-name-edit {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#change-place-name {
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rez-options-row {
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#verify-password-row {
|
||||||
|
margin-bottom: 33px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#checkmark-image {
|
||||||
|
margin-top: 66px;
|
||||||
|
margin-bottom: 59px;
|
||||||
|
width: 169px;
|
||||||
|
height: 169px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#visit-domain-row {
|
||||||
|
margin-bottom: 68px;
|
||||||
|
}
|
29
domain-server/resources/web/wizard/header.html
Normal file
29
domain-server/resources/web/wizard/header.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>domain-server</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||||
|
<link href="/css/style.css" rel="stylesheet" media="screen">
|
||||||
|
<link href="/wizard/css/style.css" rel="stylesheet" media="screen">
|
||||||
|
<link href="/css/sweetalert.css" rel="stylesheet" media="screen">
|
||||||
|
<link href="/css/bootstrap-switch.min.css" rel="stylesheet" media="screen">
|
||||||
|
|
||||||
|
<script src='/js/sweetalert.min.js'></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
|
<a class="navbar-brand step-info" href="#">Setup Wizard (Domain Server Settings)</a>
|
||||||
|
|
||||||
|
<div class="navbar-form navbar-right">
|
||||||
|
<button id="skip-wizard-button" type="button" class="btn btn-default" style="display:none;">Skip Wizard</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.container-fluid -->
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container">
|
229
domain-server/resources/web/wizard/index.shtml
Normal file
229
domain-server/resources/web/wizard/index.shtml
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
<!--#include virtual="wizard/header.html"-->
|
||||||
|
<div class="wizard-step desktop-only col-md-6 col-centered" style="display: none;">
|
||||||
|
<h4 class="step-title"></h4>
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-12">
|
||||||
|
<span class='step-description'>By connecting your High Fidelity Account you will be granting access to your account information.</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-12">
|
||||||
|
<a id="connect-account-btn" role="button" class="btn btn-primary btn-md btn-block" target="_blank">Connect your High Fidelity account</a>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-3">
|
||||||
|
<button type="button" class="btn btn-md btn-block btn-default next-button">Skip</button>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-step col-md-8 col-centered" style="display: none;">
|
||||||
|
<h4 class="step-title"></h4>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<span class='step-description'>
|
||||||
|
<a target='_blank' href='https://docs.highfidelity.com/create-and-explore/start-working-in-your-sandbox/place-names'>Place names</a> are similar to web addresses. Users who want to visit your domain can
|
||||||
|
enter its Place Name in High Fidelity's Interface. You can choose a Place Name for your domain.</br>
|
||||||
|
People can also use your <b>domain's IP address (shown below)</b> to visit your High Fidelity domain.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="centered-hack-parent">
|
||||||
|
<div id="place-name-group" class="centered-hack">
|
||||||
|
<p id="place-name-link"></p>
|
||||||
|
<div id="place-name-edit">
|
||||||
|
<span class='glyphicon glyphicon-pencil'></span>
|
||||||
|
<a href="#" id="change-place-name">Choose a custom Place Name instead</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-3">
|
||||||
|
<button type="button" class="btn btn-md btn-block btn-default back-button">Back</button>
|
||||||
|
</dd>
|
||||||
|
<dd class="col-md-3 col-md-offset-6">
|
||||||
|
<button type="button" class="btn btn-md btn-block btn-primary next-button">Next</button>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-step col-md-9 col-centered" style="display: none;">
|
||||||
|
<h4 class="step-title"></h4>
|
||||||
|
<div class="row">
|
||||||
|
<p id="permissions-description" class="col-md-12 step-info"><b>Localhost</b> has been granted administrator privileges to this domain. (Localhost is any</br>user on the same machine as the High Fidelity Server)</p>
|
||||||
|
</div>
|
||||||
|
<div id="admin-row" class="row">
|
||||||
|
<p class="col-md-6">
|
||||||
|
<span id="admin-description" class="step-info"><b>Add your High Fidelity username</b> and any other usernames to grant administrator privileges.</span>
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle="tooltip" title="Users who will have all the permissions for this domain."></span>
|
||||||
|
</p>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="admin-usernames" type="text" class="form-control">
|
||||||
|
<span class="help-block text-right">separate by commas (user1, user2,..)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<span class="step-description">Grant basic permissions to other users. You can change these later.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<p id="connect-question" class="step-info">
|
||||||
|
Who can connect to your domain?
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='You can set this to allow a user to connect to this domain.'></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<p class="col-md-2">
|
||||||
|
<label>
|
||||||
|
<input id="connect-none" name="connect-radio" type="radio" value="none" checked> None
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Only the admins of this domain'></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p class="col-md-3">
|
||||||
|
<label>
|
||||||
|
<input id="connect-friends" name="connect-radio" type="radio" value="friends"> Friends
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are your Friends in High Fidelity'></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p class="col-md-5">
|
||||||
|
<label>
|
||||||
|
<input id="connect-logged-in" name="connect-radio" type="radio" value="logged-in"> Users logged in to High Fidelity
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are currently logged into High Fidelity'></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p class="col-md-2">
|
||||||
|
<label>
|
||||||
|
<input id="connect-everyone" name="connect-radio" type="radio" value="everyone"> Everyone
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title="Users who aren't logged into High Fidelity"></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<p class="step-info">
|
||||||
|
Who can rez items in your domain?
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='You can set this to allow a user to create entities in this domain.'></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="rez-options-row" class="row">
|
||||||
|
<p class="col-md-2">
|
||||||
|
<label>
|
||||||
|
<input id="rez-none" name="rez-radio" type="radio" value="none" checked> None
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Only the admins of this domain'></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p class="col-md-3">
|
||||||
|
<label>
|
||||||
|
<input id="rez-friends" name="rez-radio" type="radio" value="friends"> Friends
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are your Friends in High Fidelity'></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p class="col-md-5">
|
||||||
|
<label>
|
||||||
|
<input id="rez-logged-in" name="rez-radio" type="radio" value="logged-in"> Users logged in to High Fidelity
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title='Users who are currently logged into High Fidelity'></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p class="col-md-2">
|
||||||
|
<label>
|
||||||
|
<input id="rez-everyone" name="rez-radio" type="radio" value="everyone"> Everyone
|
||||||
|
<span class='glyphicon glyphicon-info-sign' data-toggle='tooltip' title="Users who aren't logged into High Fidelity"></span>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 col-md-offset-9">
|
||||||
|
<button id="save-permissions" type="button" class="btn btn-md btn-block btn-primary">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-step cloud-only col-md-7 col-centered" style="display: none;">
|
||||||
|
<h4 class="step-title"></h4>
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-12">
|
||||||
|
<span class='step-description'>
|
||||||
|
Your server settings are currently accessible without a username and password.
|
||||||
|
Adding credentials will ensure that only authorized users have access to modify the settings.
|
||||||
|
</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<p class="col-md-12 step-info">Create a username and password to secure the access to your domain server settings.</p>
|
||||||
|
</div>
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-md-4 step-info">Username</dt>
|
||||||
|
<dd class="col-md-8">
|
||||||
|
<input id="http_username" type="text" class="form-control">
|
||||||
|
<span class='help-block'>This does not have to be your High Fidelity username</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-md-4 step-info">Enter password</dt>
|
||||||
|
<dd class="col-md-8">
|
||||||
|
<input id="http_password" type="password" class="form-control">
|
||||||
|
<span class='help-block'>This should not be the same as your High Fidelity password</span>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<dl id="verify-password-row" class="row">
|
||||||
|
<dt class="col-md-4 step-info">Re-enter password</dt>
|
||||||
|
<dd class="col-md-8">
|
||||||
|
<input id="verify_http_password" type="password" class="form-control">
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-3 col-md-offset-9">
|
||||||
|
<button id="save-username-password" type="button" class="btn btn-md btn-block btn-primary">Finish</button>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wizard-step cloud-only col-md-7 col-centered" style="display: none;">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4 col-centered">
|
||||||
|
<img id="checkmark-image" src="../images/checkmark.svg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<p class="step-info">Congratulations! You have successfully setup and configured your cloud hosted domain.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="visit-domain-row" class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label><input id="go-to-domain" class="form-check-input" type="checkbox"> Visit domain in VR now</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<dl class="row">
|
||||||
|
<dd class="col-md-5 col-md-offset-7">
|
||||||
|
<button id="explore-settings" type="button" class="btn btn-md btn-block btn-primary">Explore all domain server settings</button>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--#include virtual="footer.html"-->
|
||||||
|
<script src='/js/underscore-min.js'></script>
|
||||||
|
<script src='/js/bootbox.min.js'></script>
|
||||||
|
<script src='/js/sha256.js'></script>
|
||||||
|
<script src='/js/shared.js'></script>
|
||||||
|
<script src='js/wizard.js'></script>
|
||||||
|
<!--#include virtual="page-end.html"-->
|
471
domain-server/resources/web/wizard/js/wizard.js
Normal file
471
domain-server/resources/web/wizard/js/wizard.js
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
var Metaverse = {
|
||||||
|
accessToken: null
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
Strings.ADD_PLACE_NOT_CONNECTED_MESSAGE = "You must have an access token to query your High Fidelity places.<br><br>" +
|
||||||
|
"Please go back and connect your account.";
|
||||||
|
|
||||||
|
$('#connect-account-btn').attr('href', URLs.METAVERSE_URL + "/user/tokens/new?for_domain_server=true");
|
||||||
|
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
|
||||||
|
$('body').on('click', '.next-button', function() {
|
||||||
|
goToNextStep();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '.back-button', function() {
|
||||||
|
goToPreviousStep();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '#skip-wizard-button', function() {
|
||||||
|
skipWizard();
|
||||||
|
})
|
||||||
|
|
||||||
|
$('body').on('click', '#connect-account-btn', function() {
|
||||||
|
$(this).blur();
|
||||||
|
prepareAccessTokenPrompt(function(accessToken) {
|
||||||
|
Metaverse.accessToken = accessToken;
|
||||||
|
saveAccessToken();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '#save-permissions', function() {
|
||||||
|
savePermissions();
|
||||||
|
});
|
||||||
|
|
||||||
|
function triggerSaveUsernamePassword(event) {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
$("#save-username-password").click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$("#http_username").keyup(triggerSaveUsernamePassword);
|
||||||
|
$("#http_password").keyup(triggerSaveUsernamePassword);
|
||||||
|
$("#verify_http_password").keyup(triggerSaveUsernamePassword);
|
||||||
|
$('body').on('click', '#save-username-password', function() {
|
||||||
|
saveUsernamePassword();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '#change-place-name', function() {
|
||||||
|
chooseFromHighFidelityPlaces(Settings.data.values.metaverse.access_token, "/0,-10,0", function(placeName) {
|
||||||
|
updatePlaceNameLink(placeName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('body').on('click', '#explore-settings', function() {
|
||||||
|
exploreSettings();
|
||||||
|
});
|
||||||
|
|
||||||
|
reloadSettings(function(success) {
|
||||||
|
if (success) {
|
||||||
|
setupWizardSteps();
|
||||||
|
updatePlaceNameDisplay();
|
||||||
|
updateUsernameDisplay();
|
||||||
|
} else {
|
||||||
|
swal({
|
||||||
|
title: '',
|
||||||
|
type: 'error',
|
||||||
|
text: "There was a problem loading the domain settings.\nPlease refresh the page to try again.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupWizardSteps() {
|
||||||
|
var stepsCompleted = Settings.data.values.wizard.steps_completed;
|
||||||
|
var steps = null;
|
||||||
|
|
||||||
|
if (Settings.data.values.wizard.cloud_domain) {
|
||||||
|
$('.desktop-only').remove();
|
||||||
|
$('.wizard-step').find('.back-button').hide();
|
||||||
|
|
||||||
|
steps = $('.wizard-step');
|
||||||
|
$(steps).each(function(i) {
|
||||||
|
$(this).children(".step-title").text("Step " + (i + 1) + " of " + (steps.length - 1));
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#permissions-description').html('You <span id="username-display"></span>have been assigned administrator privileges to this domain.');
|
||||||
|
$('#admin-description').html('Add more High Fidelity usernames to grant administrator privileges.');
|
||||||
|
} else {
|
||||||
|
$('.cloud-only').remove();
|
||||||
|
$('#save-permissions').text("Finish");
|
||||||
|
|
||||||
|
steps = $('.wizard-step');
|
||||||
|
$(steps).each(function(i) {
|
||||||
|
$(this).children(".step-title").text("Step " + (i + 1) + " of " + steps.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (stepsCompleted == 0) {
|
||||||
|
$('#skip-wizard-button').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentStep = steps[stepsCompleted];
|
||||||
|
$(currentStep).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlaceNameLink(address) {
|
||||||
|
if (address) {
|
||||||
|
$('#place-name-link').html('Your domain is reachable at: <a target="_blank" href="' + URLs.PLACE_URL + '/' + address + '">' + address + '</a>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePlaceNameDisplay() {
|
||||||
|
if (Settings.data.values.metaverse.id) {
|
||||||
|
$.getJSON(URLs.METAVERSE_URL + '/api/v1/domains/' + Settings.data.values.metaverse.id, function(data) {
|
||||||
|
|
||||||
|
if (data.status === 'success') {
|
||||||
|
if (data.domain.default_place_name) {
|
||||||
|
// Place name
|
||||||
|
updatePlaceNameLink(data.domain.default_place_name);
|
||||||
|
} else if (data.domain.name) {
|
||||||
|
// Temporary name
|
||||||
|
updatePlaceNameLink(data.domain.name);
|
||||||
|
} else if (data.domain.network_address) {
|
||||||
|
if (data.domain.network_port !== 40102) {
|
||||||
|
// IP:PORT
|
||||||
|
updatePlaceNameLink(data.domain.network_address + ':' + data.domain.network_port);
|
||||||
|
} else {
|
||||||
|
// IP
|
||||||
|
updatePlaceNameLink(data.domain.network_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Request Failed');
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
console.warn('Request Failed');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('No metaverse domain ID!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUsernameDisplay() {
|
||||||
|
var permissions = Settings.data.values.security.permissions;
|
||||||
|
if (permissions.length > 0) {
|
||||||
|
$('#username-display').html('<b>(' + permissions[0].permissions_id + ')</b> ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadSettings(callback) {
|
||||||
|
$.getJSON('/settings.json', function(data){
|
||||||
|
Settings.data = data;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
// call the callback now that settings are loaded
|
||||||
|
callback(true);
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
if (callback) {
|
||||||
|
// call the failure object since settings load failed
|
||||||
|
callback(false)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function postSettings(jsonSettings, callback) {
|
||||||
|
console.log("----- SAVING ------");
|
||||||
|
console.log(JSON.stringify(jsonSettings));
|
||||||
|
|
||||||
|
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||||
|
$.ajax('/settings.json', {
|
||||||
|
data: JSON.stringify(jsonSettings),
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'POST'
|
||||||
|
}).done(function(data){
|
||||||
|
if (data.status == "success") {
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
reloadSettings();
|
||||||
|
} else {
|
||||||
|
swal("Error", Strings.LOADING_SETTINGS_ERROR)
|
||||||
|
reloadSettings();
|
||||||
|
}
|
||||||
|
}).fail(function(){
|
||||||
|
swal("Error", Strings.LOADING_SETTINGS_ERROR)
|
||||||
|
reloadSettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextStep() {
|
||||||
|
$('#skip-wizard-button').hide();
|
||||||
|
|
||||||
|
var currentStep = $('body').find('.wizard-step:visible');
|
||||||
|
var nextStep = currentStep.next('.wizard-step');
|
||||||
|
|
||||||
|
var formJSON = {
|
||||||
|
"wizard": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextStep.length > 0) {
|
||||||
|
currentStep.hide();
|
||||||
|
nextStep.show();
|
||||||
|
|
||||||
|
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1;
|
||||||
|
|
||||||
|
postSettings({
|
||||||
|
"wizard": {
|
||||||
|
"steps_completed": currentStepNumber.toString()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
postSettings({
|
||||||
|
"wizard": {
|
||||||
|
"steps_completed": "0",
|
||||||
|
"completed_once": true
|
||||||
|
}
|
||||||
|
}, redirectToSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToPreviousStep() {
|
||||||
|
var currentStep = $('body').find('.wizard-step:visible');
|
||||||
|
var previousStep = currentStep.prev('.wizard-step');
|
||||||
|
|
||||||
|
var formJSON = {
|
||||||
|
"wizard": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousStep.length > 0) {
|
||||||
|
currentStep.hide();
|
||||||
|
previousStep.show();
|
||||||
|
|
||||||
|
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) - 1;
|
||||||
|
|
||||||
|
postSettings({
|
||||||
|
"wizard": {
|
||||||
|
"steps_completed": currentStepNumber.toString()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function skipWizard() {
|
||||||
|
postSettings({
|
||||||
|
"wizard": {
|
||||||
|
"steps_completed": "0",
|
||||||
|
"completed_once": true
|
||||||
|
}
|
||||||
|
}, redirectToSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectToSettings() {
|
||||||
|
var redirectURL = "/settings" + location.search;
|
||||||
|
if (Settings.data.values.wizard.cloud_domain) {
|
||||||
|
if (location.search.length > 0) {
|
||||||
|
redirectURL += "&";
|
||||||
|
} else {
|
||||||
|
redirectURL += "?";
|
||||||
|
}
|
||||||
|
redirectURL += "cloud-wizard-exit";
|
||||||
|
}
|
||||||
|
location.href = redirectURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveAccessToken() {
|
||||||
|
var formJSON = {
|
||||||
|
"metaverse": {}
|
||||||
|
}
|
||||||
|
if (Metaverse.accessToken) {
|
||||||
|
formJSON.metaverse.access_token = Metaverse.accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove focus from the button
|
||||||
|
$(this).blur();
|
||||||
|
|
||||||
|
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||||
|
postSettings(formJSON, goToNextStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSettingDescriptionForKey(groupKey, settingKey) {
|
||||||
|
for (var i in Settings.data.descriptions) {
|
||||||
|
var group = Settings.data.descriptions[i];
|
||||||
|
if (group.name === groupKey) {
|
||||||
|
for (var j in group.settings) {
|
||||||
|
var setting = group.settings[j];
|
||||||
|
if (setting.name === settingKey) {
|
||||||
|
return setting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function savePermissions() {
|
||||||
|
var localhostPermissions = (Settings.data.values.wizard.cloud_domain !== true)
|
||||||
|
var anonymousCanConnect = false;
|
||||||
|
var friendsCanConnect = false;
|
||||||
|
var loggedInCanConnect = false;
|
||||||
|
var anonymousCanRez = false;
|
||||||
|
var friendsCanRez = false;
|
||||||
|
var loggedInCanRez = false;
|
||||||
|
|
||||||
|
var connectValue = $('input[name=connect-radio]:checked').val();
|
||||||
|
var rezValue = $('input[name=rez-radio]:checked').val();
|
||||||
|
|
||||||
|
switch (connectValue) {
|
||||||
|
case "friends":
|
||||||
|
friendsCanConnect = true;
|
||||||
|
break;
|
||||||
|
case "logged-in":
|
||||||
|
friendsCanConnect = true;
|
||||||
|
loggedInCanConnect = true;
|
||||||
|
break;
|
||||||
|
case "everyone":
|
||||||
|
anonymousCanConnect = true;
|
||||||
|
friendsCanConnect = true;
|
||||||
|
loggedInCanConnect = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rezValue) {
|
||||||
|
case "friends":
|
||||||
|
friendsCanRez = true;
|
||||||
|
break;
|
||||||
|
case "logged-in":
|
||||||
|
friendsCanRez = true;
|
||||||
|
loggedInCanRez = true;
|
||||||
|
break;
|
||||||
|
case "everyone":
|
||||||
|
anonymousCanRez = true;
|
||||||
|
friendsCanRez = true;
|
||||||
|
loggedInCanRez = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var admins = $('#admin-usernames').val().split(',');
|
||||||
|
|
||||||
|
var existingAdmins = Settings.data.values.security.permissions.map(function(value) {
|
||||||
|
return value.permissions_id;
|
||||||
|
});
|
||||||
|
admins = admins.concat(existingAdmins);
|
||||||
|
|
||||||
|
// Filter out unique values
|
||||||
|
admins = _.uniq(admins.map(function(username) {
|
||||||
|
return username.trim();
|
||||||
|
})).filter(function(username) {
|
||||||
|
return username !== "";
|
||||||
|
});
|
||||||
|
|
||||||
|
var formJSON = {
|
||||||
|
"security": {
|
||||||
|
"standard_permissions": [
|
||||||
|
{
|
||||||
|
"id_can_connect": anonymousCanConnect,
|
||||||
|
"id_can_rez": anonymousCanRez,
|
||||||
|
"id_can_rez_certified": anonymousCanRez,
|
||||||
|
"id_can_rez_tmp": anonymousCanRez,
|
||||||
|
"id_can_rez_tmp_certified": anonymousCanRez,
|
||||||
|
"permissions_id": "anonymous"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id_can_connect": friendsCanConnect,
|
||||||
|
"id_can_rez": friendsCanRez,
|
||||||
|
"id_can_rez_certified": friendsCanRez,
|
||||||
|
"id_can_rez_tmp": friendsCanRez,
|
||||||
|
"id_can_rez_tmp_certified": friendsCanRez,
|
||||||
|
"permissions_id": "friends"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id_can_connect": loggedInCanConnect,
|
||||||
|
"id_can_rez": loggedInCanRez,
|
||||||
|
"id_can_rez_certified": loggedInCanRez,
|
||||||
|
"id_can_rez_tmp": loggedInCanRez,
|
||||||
|
"id_can_rez_tmp_certified": loggedInCanRez,
|
||||||
|
"permissions_id": "logged-in"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id_can_adjust_locks": localhostPermissions,
|
||||||
|
"id_can_connect": localhostPermissions,
|
||||||
|
"id_can_connect_past_max_capacity": localhostPermissions,
|
||||||
|
"id_can_kick": localhostPermissions,
|
||||||
|
"id_can_replace_content": localhostPermissions,
|
||||||
|
"id_can_rez": localhostPermissions,
|
||||||
|
"id_can_rez_certified": localhostPermissions,
|
||||||
|
"id_can_rez_tmp": localhostPermissions,
|
||||||
|
"id_can_rez_tmp_certified": localhostPermissions,
|
||||||
|
"id_can_write_to_asset_server": localhostPermissions,
|
||||||
|
"permissions_id": "localhost"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (admins.length > 0) {
|
||||||
|
formJSON.security.permissions = [];
|
||||||
|
|
||||||
|
var permissionsDesc = getSettingDescriptionForKey("security", "permissions");
|
||||||
|
for (var i in admins) {
|
||||||
|
var admin = admins[i];
|
||||||
|
var perms = {};
|
||||||
|
for (var i in permissionsDesc.columns) {
|
||||||
|
var name = permissionsDesc.columns[i].name;
|
||||||
|
if (name === "permissions_id") {
|
||||||
|
perms[name] = admin;
|
||||||
|
} else {
|
||||||
|
perms[name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formJSON.security.permissions.push(perms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove focus from the button
|
||||||
|
$(this).blur();
|
||||||
|
|
||||||
|
postSettings(formJSON, goToNextStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveUsernamePassword() {
|
||||||
|
var username = $("#http_username").val();
|
||||||
|
var password = $("#http_password").val();
|
||||||
|
var verify_password = $("#verify_http_password").val();
|
||||||
|
|
||||||
|
if (username.length == 0) {
|
||||||
|
bootbox.alert({ "message": "You must set a username!", "title": "Username Error" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length == 0) {
|
||||||
|
bootbox.alert({ "message": "You must set a password!", "title": "Password Error" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password != verify_password) {
|
||||||
|
bootbox.alert({ "message": "Passwords must match!", "title": "Password Error" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1;
|
||||||
|
|
||||||
|
var formJSON = {
|
||||||
|
"security": {
|
||||||
|
"http_username": username,
|
||||||
|
"http_password": sha256_digest(password)
|
||||||
|
},
|
||||||
|
"wizard": {
|
||||||
|
"steps_completed": currentStepNumber.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove focus from the button
|
||||||
|
$(this).blur();
|
||||||
|
|
||||||
|
// POST the form JSON to the domain-server settings.json endpoint so the settings are saved
|
||||||
|
postSettings(formJSON, function() {
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function exploreSettings() {
|
||||||
|
if ($('#go-to-domain').is(":checked")) {
|
||||||
|
var link = $('#place-name-link a:first');
|
||||||
|
if (link.length > 0) {
|
||||||
|
window.open(link.attr("href"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goToNextStep();
|
||||||
|
}
|
|
@ -814,9 +814,15 @@ void DomainGatekeeper::processICEPeerInformationPacket(QSharedPointer<ReceivedMe
|
||||||
|
|
||||||
void DomainGatekeeper::processICEPingPacket(QSharedPointer<ReceivedMessage> message) {
|
void DomainGatekeeper::processICEPingPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID());
|
|
||||||
|
|
||||||
limitedNodeList->sendPacket(std::move(pingReplyPacket), message->getSenderSockAddr());
|
// before we respond to this ICE ping packet, make sure we have a peer in the list that matches
|
||||||
|
QUuid icePeerID = QUuid::fromRfc4122({ message->getRawMessage(), NUM_BYTES_RFC4122_UUID });
|
||||||
|
|
||||||
|
if (_icePeers.contains(icePeerID)) {
|
||||||
|
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID());
|
||||||
|
|
||||||
|
limitedNodeList->sendPacket(std::move(pingReplyPacket), message->getSenderSockAddr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer<ReceivedMessage> message) {
|
void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include "DomainServerNodeData.h"
|
#include "DomainServerNodeData.h"
|
||||||
#include "NodeConnectionData.h"
|
#include "NodeConnectionData.h"
|
||||||
|
|
||||||
|
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||||
|
|
||||||
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
||||||
|
|
||||||
#if USE_STABLE_GLOBAL_SERVICES
|
#if USE_STABLE_GLOBAL_SERVICES
|
||||||
|
@ -54,6 +56,82 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com";
|
||||||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
|
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||||
|
const QString& metaversePath,
|
||||||
|
const QString& requestSubobjectKey,
|
||||||
|
std::initializer_list<QString> requiredData,
|
||||||
|
std::initializer_list<QString> optionalData,
|
||||||
|
bool requireAccessToken) {
|
||||||
|
|
||||||
|
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||||
|
if (accessTokenVariant == nullptr && requireAccessToken) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject subobject;
|
||||||
|
|
||||||
|
auto params = connection->parseUrlEncodedForm();
|
||||||
|
|
||||||
|
for (auto& key : requiredData) {
|
||||||
|
auto it = params.find(key);
|
||||||
|
if (it == params.end()) {
|
||||||
|
auto error = "Bad request, expected param '" + key + "'";
|
||||||
|
connection->respond(HTTPConnection::StatusCode400, error.toLatin1());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
subobject.insert(key, it.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& key : optionalData) {
|
||||||
|
auto it = params.find(key);
|
||||||
|
if (it != params.end()) {
|
||||||
|
subobject.insert(key, it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject root;
|
||||||
|
root.insert(requestSubobjectKey, subobject);
|
||||||
|
QJsonDocument doc { root };
|
||||||
|
|
||||||
|
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + metaversePath };
|
||||||
|
|
||||||
|
QNetworkRequest req(url);
|
||||||
|
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
|
if (accessTokenVariant != nullptr) {
|
||||||
|
auto accessTokenHeader = QString("Bearer ") + accessTokenVariant->toString();
|
||||||
|
req.setRawHeader("Authorization", accessTokenHeader.toLatin1());
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkReply* reply;
|
||||||
|
auto method = connection->requestOperation();
|
||||||
|
if (method == QNetworkAccessManager::GetOperation) {
|
||||||
|
reply = NetworkAccessManager::getInstance().get(req);
|
||||||
|
} else if (method == QNetworkAccessManager::PostOperation) {
|
||||||
|
reply = NetworkAccessManager::getInstance().post(req, doc.toJson());
|
||||||
|
} else if (method == QNetworkAccessManager::PutOperation) {
|
||||||
|
reply = NetworkAccessManager::getInstance().put(req, doc.toJson());
|
||||||
|
} else {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400, "Error forwarding request, unsupported method");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
auto data = reply->readAll();
|
||||||
|
qDebug() << "Got error response from metaverse server (" << reply->url() << "): " << data << reply->errorString();
|
||||||
|
connection->respond(HTTPConnection::StatusCode400, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
QCoreApplication(argc, argv),
|
QCoreApplication(argc, argv),
|
||||||
_gatekeeper(this),
|
_gatekeeper(this),
|
||||||
|
@ -614,8 +692,6 @@ void DomainServer::setupNodeListAndAssignments() {
|
||||||
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
|
nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
|
||||||
|
|
||||||
bool DomainServer::resetAccountManagerAccessToken() {
|
bool DomainServer::resetAccountManagerAccessToken() {
|
||||||
if (!_oauthProviderURL.isEmpty()) {
|
if (!_oauthProviderURL.isEmpty()) {
|
||||||
// check for an access-token in our settings, can optionally be overidden by env value
|
// check for an access-token in our settings, can optionally be overidden by env value
|
||||||
|
@ -1731,6 +1807,8 @@ QString DomainServer::pathForRedirect(QString path) const {
|
||||||
return "http://" + _hostname + ":" + QString::number(_httpManager.serverPort()) + path;
|
return "http://" + _hostname + ":" + QString::number(_httpManager.serverPort()) + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const QString URI_OAUTH = "/oauth";
|
const QString URI_OAUTH = "/oauth";
|
||||||
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||||
const QString JSON_MIME_TYPE = "application/json";
|
const QString JSON_MIME_TYPE = "application/json";
|
||||||
|
@ -1740,15 +1818,23 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
const QString URI_SETTINGS = "/settings";
|
const QString URI_SETTINGS = "/settings";
|
||||||
const QString URI_ENTITY_FILE_UPLOAD = "/content/upload";
|
const QString URI_ENTITY_FILE_UPLOAD = "/content/upload";
|
||||||
const QString URI_RESTART = "/restart";
|
const QString URI_RESTART = "/restart";
|
||||||
|
const QString URI_API_PLACES = "/api/places";
|
||||||
|
const QString URI_API_DOMAINS = "/api/domains";
|
||||||
|
const QString URI_API_DOMAINS_ID = "/api/domains/";
|
||||||
|
|
||||||
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
// allow sub-handlers to handle requests that do not require authentication
|
auto getSetting = [this](QString keyPath, QVariant& value) -> bool {
|
||||||
if (_settingsManager.handlePublicHTTPRequest(connection, url)) {
|
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||||
|
QVariant* var = valueForKeyPath(settingsMap, keyPath);
|
||||||
|
if (var == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = *var;
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
// check if this is a request for a scripted assignment (with a temp unique UUID)
|
// check if this is a request for a scripted assignment (with a temp unique UUID)
|
||||||
const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING);
|
const QString ASSIGNMENT_REGEX_STRING = QString("\\%1\\/(%2)\\/?$").arg(URI_ASSIGNMENT).arg(UUID_REGEX_STRING);
|
||||||
|
@ -1810,6 +1896,31 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we should redirect/prevent access to the wizard
|
||||||
|
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||||
|
const QString URI_WIZARD = "/wizard/";
|
||||||
|
const QString WIZARD_COMPLETED_ONCE_KEY_PATH = "wizard.completed_once";
|
||||||
|
const QVariant* wizardCompletedOnce = valueForKeyPath(_settingsManager.getSettingsMap(), WIZARD_COMPLETED_ONCE_KEY_PATH);
|
||||||
|
const bool completedOnce = wizardCompletedOnce && wizardCompletedOnce->toBool();
|
||||||
|
|
||||||
|
if (url.path() != URI_WIZARD && url.path().endsWith('/') && !completedOnce) {
|
||||||
|
// First visit, redirect to the wizard
|
||||||
|
QUrl redirectedURL = url;
|
||||||
|
redirectedURL.setPath(URI_WIZARD);
|
||||||
|
|
||||||
|
Headers redirectHeaders;
|
||||||
|
redirectHeaders.insert("Location", redirectedURL.toEncoded());
|
||||||
|
|
||||||
|
connection->respond(HTTPConnection::StatusCode302,
|
||||||
|
QByteArray(), HTTPConnection::DefaultContentType, redirectHeaders);
|
||||||
|
return true;
|
||||||
|
} else if (url.path() == URI_WIZARD && completedOnce) {
|
||||||
|
// Wizard already completed, return 404
|
||||||
|
connection->respond(HTTPConnection::StatusCode404, "Resource not found.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||||
if (url.path() == "/assignments.json") {
|
if (url.path() == "/assignments.json") {
|
||||||
// user is asking for json list of assignments
|
// user is asking for json list of assignments
|
||||||
|
@ -1899,6 +2010,13 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
connection->respond(HTTPConnection::StatusCode200);
|
connection->respond(HTTPConnection::StatusCode200);
|
||||||
restart();
|
restart();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (url.path() == URI_API_DOMAINS) {
|
||||||
|
return forwardMetaverseAPIRequest(connection, "/api/v1/domains", "");
|
||||||
|
} else if (url.path().startsWith(URI_API_DOMAINS_ID)) {
|
||||||
|
auto id = url.path().mid(URI_API_DOMAINS_ID.length());
|
||||||
|
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + id, "", {}, {}, false);
|
||||||
|
} else if (url.path() == URI_API_PLACES) {
|
||||||
|
return forwardMetaverseAPIRequest(connection, "/api/v1/user/places", "");
|
||||||
} else {
|
} else {
|
||||||
// check if this is for json stats for a node
|
// check if this is for json stats for a node
|
||||||
const QString NODE_JSON_REGEX_STRING = QString("\\%1\\/(%2).json\\/?$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
const QString NODE_JSON_REGEX_STRING = QString("\\%1\\/(%2).json\\/?$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
||||||
|
@ -1978,8 +2096,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
// this is an entity file upload, ask the HTTPConnection to parse the data
|
// this is an entity file upload, ask the HTTPConnection to parse the data
|
||||||
QList<FormData> formData = connection->parseFormData();
|
QList<FormData> formData = connection->parseFormData();
|
||||||
|
|
||||||
Headers redirectHeaders;
|
|
||||||
|
|
||||||
if (formData.size() > 0 && formData[0].second.size() > 0) {
|
if (formData.size() > 0 && formData[0].second.size() > 0) {
|
||||||
// invoke our method to hand the new octree file off to the octree server
|
// invoke our method to hand the new octree file off to the octree server
|
||||||
QMetaObject::invokeMethod(this, "handleOctreeFileReplacement",
|
QMetaObject::invokeMethod(this, "handleOctreeFileReplacement",
|
||||||
|
@ -1993,7 +2109,98 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
} else if (url.path() == "/domain_settings") {
|
||||||
|
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||||
|
if (!accessTokenVariant) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (url.path() == URI_API_DOMAINS) {
|
||||||
|
|
||||||
|
return forwardMetaverseAPIRequest(connection, "/api/v1/domains", "domain", { "label" });
|
||||||
}
|
}
|
||||||
|
} else if (connection->requestOperation() == QNetworkAccessManager::PutOperation) {
|
||||||
|
if (url.path() == URI_API_DOMAINS) {
|
||||||
|
QVariant domainSetting;
|
||||||
|
if (!getSetting(METAVERSE_DOMAIN_ID_KEY_PATH, domainSetting)) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400, "Domain id has not been set");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto domainID = domainSetting.toString();
|
||||||
|
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + domainID, "domain",
|
||||||
|
{ }, { "network_address", "network_port", "label" });
|
||||||
|
} else if (url.path() == URI_API_PLACES) {
|
||||||
|
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||||
|
if (!accessTokenVariant->isValid()) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto params = connection->parseUrlEncodedForm();
|
||||||
|
|
||||||
|
auto it = params.find("place_id");
|
||||||
|
if (it == params.end()) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
QString place_id = it.value();
|
||||||
|
|
||||||
|
it = params.find("path");
|
||||||
|
if (it == params.end()) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
QString path = it.value();
|
||||||
|
|
||||||
|
it = params.find("domain_id");
|
||||||
|
QString domainID;
|
||||||
|
if (it == params.end()) {
|
||||||
|
QVariant domainSetting;
|
||||||
|
if (!getSetting(METAVERSE_DOMAIN_ID_KEY_PATH, domainSetting)) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
domainID = domainSetting.toString();
|
||||||
|
} else {
|
||||||
|
domainID = it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject root {
|
||||||
|
{
|
||||||
|
"place",
|
||||||
|
QJsonObject({
|
||||||
|
{ "pointee_query", domainID },
|
||||||
|
{ "path", path }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
QJsonDocument doc(root);
|
||||||
|
|
||||||
|
|
||||||
|
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/v1/places/" + place_id };
|
||||||
|
|
||||||
|
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||||
|
|
||||||
|
QNetworkRequest req(url);
|
||||||
|
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
QNetworkReply* reply = NetworkAccessManager::getInstance().put(req, doc.toJson());
|
||||||
|
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
qDebug() << "Got error response from metaverse server: " << reply->readAll();
|
||||||
|
connection->respond(HTTPConnection::StatusCode500,
|
||||||
|
"Error communicating with Metaverse");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
|
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
|
||||||
const QString ALL_NODE_DELETE_REGEX_STRING = QString("\\%1\\/?$").arg(URI_NODES);
|
const QString ALL_NODE_DELETE_REGEX_STRING = QString("\\%1\\/?$").arg(URI_NODES);
|
||||||
const QString NODE_DELETE_REGEX_STRING = QString("\\%1\\/(%2)\\/$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
const QString NODE_DELETE_REGEX_STRING = QString("\\%1\\/(%2)\\/$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
||||||
|
@ -2037,7 +2244,6 @@ static const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID";
|
||||||
static const QString STATE_QUERY_KEY = "state";
|
static const QString STATE_QUERY_KEY = "state";
|
||||||
|
|
||||||
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
||||||
qDebug() << "HTTPS request received at" << url.toString();
|
|
||||||
if (url.path() == URI_OAUTH) {
|
if (url.path() == URI_OAUTH) {
|
||||||
|
|
||||||
QUrlQuery codeURLQuery(url);
|
QUrlQuery codeURLQuery(url);
|
||||||
|
@ -2298,6 +2504,8 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
|
||||||
profileURL.setPath("/api/v1/user/profile");
|
profileURL.setPath("/api/v1/user/profile");
|
||||||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||||
|
|
||||||
|
qDebug() << "Sending profile request to: " << profileURL;
|
||||||
|
|
||||||
QNetworkRequest profileRequest(profileURL);
|
QNetworkRequest profileRequest(profileURL);
|
||||||
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||||
|
|
|
@ -187,6 +187,13 @@ private:
|
||||||
|
|
||||||
HTTPSConnection* connectionFromReplyWithState(QNetworkReply* reply);
|
HTTPSConnection* connectionFromReplyWithState(QNetworkReply* reply);
|
||||||
|
|
||||||
|
bool forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||||
|
const QString& metaversePath,
|
||||||
|
const QString& requestSubobject,
|
||||||
|
std::initializer_list<QString> requiredData = { },
|
||||||
|
std::initializer_list<QString> optionalData = { },
|
||||||
|
bool requireAccessToken = true);
|
||||||
|
|
||||||
SubnetList _acSubnetWhitelist;
|
SubnetList _acSubnetWhitelist;
|
||||||
|
|
||||||
std::vector<QString> _replicatedUsernames;
|
std::vector<QString> _replicatedUsernames;
|
||||||
|
|
|
@ -310,6 +310,16 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
||||||
_standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canRezTemporaryCertifiedEntities);
|
_standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canRezTemporaryCertifiedEntities);
|
||||||
packPermissions();
|
packPermissions();
|
||||||
}
|
}
|
||||||
|
if (oldVersion < 2.0) {
|
||||||
|
const QString WIZARD_COMPLETED_ONCE = "wizard.completed_once";
|
||||||
|
|
||||||
|
QVariant* wizardCompletedOnce = _configMap.valueForKeyPath(WIZARD_COMPLETED_ONCE, true);
|
||||||
|
|
||||||
|
*wizardCompletedOnce = QVariant(true);
|
||||||
|
|
||||||
|
// write the new settings to the json file
|
||||||
|
persistToFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unpackPermissions();
|
unpackPermissions();
|
||||||
|
@ -960,29 +970,6 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) {
|
|
||||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH_JSON) {
|
|
||||||
// this is a GET operation for our settings
|
|
||||||
|
|
||||||
// check if there is a query parameter for settings affecting a particular type of assignment
|
|
||||||
const QString SETTINGS_TYPE_QUERY_KEY = "type";
|
|
||||||
QUrlQuery settingsQuery(url);
|
|
||||||
QString typeValue = settingsQuery.queryItemValue(SETTINGS_TYPE_QUERY_KEY);
|
|
||||||
|
|
||||||
if (!typeValue.isEmpty()) {
|
|
||||||
QJsonObject responseObject = responseObjectForType(typeValue);
|
|
||||||
|
|
||||||
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(responseObject).toJson(), "application/json");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
||||||
if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH_JSON) {
|
if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH_JSON) {
|
||||||
// this is a POST operation to change one or more settings
|
// this is a POST operation to change one or more settings
|
||||||
|
@ -1214,6 +1201,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
static const QString SECURITY_ROOT_KEY = "security";
|
static const QString SECURITY_ROOT_KEY = "security";
|
||||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||||
static const QString BROADCASTING_KEY = "broadcasting";
|
static const QString BROADCASTING_KEY = "broadcasting";
|
||||||
|
static const QString WIZARD_KEY = "wizard";
|
||||||
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
||||||
|
|
||||||
auto& settingsVariant = _configMap.getConfig();
|
auto& settingsVariant = _configMap.getConfig();
|
||||||
|
@ -1266,7 +1254,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
|
|
||||||
if (!matchingDescriptionObject.isEmpty()) {
|
if (!matchingDescriptionObject.isEmpty()) {
|
||||||
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
||||||
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != SETTINGS_PATHS_KEY ) {
|
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||||
|
rootKey != SETTINGS_PATHS_KEY && rootKey != WIZARD_KEY) {
|
||||||
needRestart = true;
|
needRestart = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1282,8 +1271,9 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
if (!matchingDescriptionObject.isEmpty()) {
|
if (!matchingDescriptionObject.isEmpty()) {
|
||||||
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
||||||
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
||||||
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != DESCRIPTION_ROOT_KEY)
|
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||||
|| settingKey == AC_SUBNET_WHITELIST_KEY) {
|
rootKey != DESCRIPTION_ROOT_KEY && rootKey != WIZARD_KEY) ||
|
||||||
|
settingKey == AC_SUBNET_WHITELIST_KEY) {
|
||||||
needRestart = true;
|
needRestart = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -43,7 +43,6 @@ class DomainServerSettingsManager : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DomainServerSettingsManager();
|
DomainServerSettingsManager();
|
||||||
bool handlePublicHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
|
||||||
bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
||||||
|
|
||||||
void setupConfigMap(const QStringList& argumentList);
|
void setupConfigMap(const QStringList& argumentList);
|
||||||
|
|
|
@ -14,13 +14,25 @@ Item {
|
||||||
readonly property var originalAttachments: MyAvatar.getAttachmentsVariant();
|
readonly property var originalAttachments: MyAvatar.getAttachmentsVariant();
|
||||||
property var attachments: [];
|
property var attachments: [];
|
||||||
|
|
||||||
Component.onCompleted: {
|
function reload(){
|
||||||
for (var i = 0; i < originalAttachments.length; ++i) {
|
content.attachments = [];
|
||||||
var attachment = originalAttachments[i];
|
var currentAttachments = MyAvatar.getAttachmentsVariant();
|
||||||
|
listView.model.clear();
|
||||||
|
for (var i = 0; i < currentAttachments.length; ++i) {
|
||||||
|
var attachment = currentAttachments[i];
|
||||||
content.attachments.push(attachment);
|
content.attachments.push(attachment);
|
||||||
listView.model.append({});
|
listView.model.append({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: MyAvatar
|
||||||
|
onAttachmentsChanged: reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
reload()
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: pane.width
|
width: pane.width
|
||||||
|
|
|
@ -219,7 +219,7 @@ Item {
|
||||||
|
|
||||||
function setShown(value) {
|
function setShown(value) {
|
||||||
if (value === true) {
|
if (value === true) {
|
||||||
HMD.openTablet()
|
HMD.openTablet(HMD.tabletContextualMode) // pass in current contextual mode flag to maintain flag (otherwise uses default false argument)
|
||||||
} else {
|
} else {
|
||||||
HMD.closeTablet()
|
HMD.closeTablet()
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ Item {
|
||||||
|
|
||||||
BaseWebView {
|
BaseWebView {
|
||||||
id: webview
|
id: webview
|
||||||
url: (Account.metaverseServerURL + "/marketplace?category=avatars)"
|
url: (Account.metaverseServerURL + "/marketplace?category=avatars")
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
|
|
|
@ -1452,6 +1452,7 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Avatar::setAttachmentData(attachmentData);
|
Avatar::setAttachmentData(attachmentData);
|
||||||
|
emit attachmentsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getSkeletonPosition() const {
|
glm::vec3 MyAvatar::getSkeletonPosition() const {
|
||||||
|
|
|
@ -619,6 +619,7 @@ signals:
|
||||||
void skeletonChanged();
|
void skeletonChanged();
|
||||||
void dominantHandChanged(const QString& hand);
|
void dominantHandChanged(const QString& hand);
|
||||||
void sensorToWorldScaleChanged(float sensorToWorldScale);
|
void sensorToWorldScaleChanged(float sensorToWorldScale);
|
||||||
|
void attachmentsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -100,10 +100,21 @@ void HMDScriptingInterface::deactivateHMDHandMouse() {
|
||||||
|
|
||||||
void HMDScriptingInterface::closeTablet() {
|
void HMDScriptingInterface::closeTablet() {
|
||||||
_showTablet = false;
|
_showTablet = false;
|
||||||
|
_tabletContextualMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HMDScriptingInterface::openTablet() {
|
void HMDScriptingInterface::openTablet(bool contextualMode) {
|
||||||
_showTablet = true;
|
_showTablet = true;
|
||||||
|
_tabletContextualMode = contextualMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDScriptingInterface::toggleShouldShowTablet() {
|
||||||
|
setShouldShowTablet(!getShouldShowTablet());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HMDScriptingInterface::setShouldShowTablet(bool value) {
|
||||||
|
_showTablet = value;
|
||||||
|
_tabletContextualMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
|
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
|
||||||
Q_PROPERTY(glm::quat orientation READ getOrientation)
|
Q_PROPERTY(glm::quat orientation READ getOrientation)
|
||||||
Q_PROPERTY(bool mounted READ isMounted NOTIFY mountedChanged)
|
Q_PROPERTY(bool mounted READ isMounted NOTIFY mountedChanged)
|
||||||
Q_PROPERTY(bool showTablet READ getShouldShowTablet)
|
Q_PROPERTY(bool showTablet READ getShouldShowTablet)
|
||||||
|
Q_PROPERTY(bool tabletContextualMode READ getTabletContextualMode)
|
||||||
Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID)
|
Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID)
|
||||||
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID)
|
Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID)
|
||||||
Q_PROPERTY(QUuid homeButtonHighlightID READ getCurrentHomeButtonHightlightID WRITE setCurrentHomeButtonHightlightID)
|
Q_PROPERTY(QUuid homeButtonHighlightID READ getCurrentHomeButtonHightlightID WRITE setCurrentHomeButtonHightlightID)
|
||||||
|
@ -75,7 +76,7 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void closeTablet();
|
Q_INVOKABLE void closeTablet();
|
||||||
|
|
||||||
Q_INVOKABLE void openTablet();
|
Q_INVOKABLE void openTablet(bool contextualMode = false);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
bool shouldShowHandControllersChanged();
|
bool shouldShowHandControllersChanged();
|
||||||
|
@ -88,9 +89,10 @@ public:
|
||||||
|
|
||||||
bool isMounted() const;
|
bool isMounted() const;
|
||||||
|
|
||||||
void toggleShouldShowTablet() { _showTablet = !_showTablet; }
|
void toggleShouldShowTablet();
|
||||||
void setShouldShowTablet(bool value) { _showTablet = value; }
|
void setShouldShowTablet(bool value);
|
||||||
bool getShouldShowTablet() const { return _showTablet; }
|
bool getShouldShowTablet() const { return _showTablet; }
|
||||||
|
bool getTabletContextualMode() const { return _tabletContextualMode; }
|
||||||
|
|
||||||
void setCurrentTabletFrameID(QUuid tabletID) { _tabletUIID = tabletID; }
|
void setCurrentTabletFrameID(QUuid tabletID) { _tabletUIID = tabletID; }
|
||||||
QUuid getCurrentTabletFrameID() const { return _tabletUIID; }
|
QUuid getCurrentTabletFrameID() const { return _tabletUIID; }
|
||||||
|
@ -106,6 +108,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _showTablet { false };
|
bool _showTablet { false };
|
||||||
|
bool _tabletContextualMode { false };
|
||||||
QUuid _tabletUIID; // this is the entityID of the tablet frame
|
QUuid _tabletUIID; // this is the entityID of the tablet frame
|
||||||
QUuid _tabletScreenID; // this is the overlayID which is part of (a child of) the tablet-ui.
|
QUuid _tabletScreenID; // this is the overlayID which is part of (a child of) the tablet-ui.
|
||||||
QUuid _homeButtonID;
|
QUuid _homeButtonID;
|
||||||
|
|
|
@ -222,6 +222,7 @@ void Web3DOverlay::setupQmlSurface() {
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get<SoundCache>().data());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
_webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
_webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
|
||||||
|
_webSurface->getSurfaceContext()->setContextProperty("Render", AbstractViewStateInterface::instance()->getRenderEngine()->getConfiguration().get());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
|
_webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "HTTPConnection.h"
|
#include "HTTPConnection.h"
|
||||||
#include "EmbeddedWebserverLogging.h"
|
#include "EmbeddedWebserverLogging.h"
|
||||||
#include "HTTPManager.h"
|
#include "HTTPManager.h"
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
const char* HTTPConnection::StatusCode200 = "200 OK";
|
const char* HTTPConnection::StatusCode200 = "200 OK";
|
||||||
const char* HTTPConnection::StatusCode301 = "301 Moved Permanently";
|
const char* HTTPConnection::StatusCode301 = "301 Moved Permanently";
|
||||||
|
@ -52,10 +53,31 @@ HTTPConnection::~HTTPConnection() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHash<QString, QString> HTTPConnection::parseUrlEncodedForm() {
|
||||||
|
// make sure we have the correct MIME type
|
||||||
|
QList<QByteArray> elements = _requestHeaders.value("Content-Type").split(';');
|
||||||
|
|
||||||
|
QString contentType = elements.at(0).trimmed();
|
||||||
|
if (contentType != "application/x-www-form-urlencoded") {
|
||||||
|
return QHash<QString, QString>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrlQuery form { _requestContent };
|
||||||
|
QHash<QString, QString> pairs;
|
||||||
|
for (auto pair : form.queryItems()) {
|
||||||
|
pairs[QUrl::fromPercentEncoding(pair.first.toLatin1())] = QUrl::fromPercentEncoding(pair.second.toLatin1());
|
||||||
|
}
|
||||||
|
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
|
||||||
QList<FormData> HTTPConnection::parseFormData() const {
|
QList<FormData> HTTPConnection::parseFormData() const {
|
||||||
// make sure we have the correct MIME type
|
// make sure we have the correct MIME type
|
||||||
QList<QByteArray> elements = _requestHeaders.value("Content-Type").split(';');
|
QList<QByteArray> elements = _requestHeaders.value("Content-Type").split(';');
|
||||||
if (elements.at(0).trimmed() != "multipart/form-data") {
|
|
||||||
|
QString contentType = elements.at(0).trimmed();
|
||||||
|
|
||||||
|
if (contentType != "multipart/form-data") {
|
||||||
return QList<FormData>();
|
return QList<FormData>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,10 @@ public:
|
||||||
/// Parses the request content as form data, returning a list of header/content pairs.
|
/// Parses the request content as form data, returning a list of header/content pairs.
|
||||||
QList<FormData> parseFormData () const;
|
QList<FormData> parseFormData () const;
|
||||||
|
|
||||||
|
/// Parses the request content as a url encoded form, returning a hash of key/value pairs.
|
||||||
|
/// Duplicate keys are not supported.
|
||||||
|
QHash<QString, QString> parseUrlEncodedForm();
|
||||||
|
|
||||||
/// Sends a response and closes the connection.
|
/// Sends a response and closes the connection.
|
||||||
void respond (const char* code, const QByteArray& content = QByteArray(),
|
void respond (const char* code, const QByteArray& content = QByteArray(),
|
||||||
const char* contentType = DefaultContentType,
|
const char* contentType = DefaultContentType,
|
||||||
|
|
|
@ -100,7 +100,11 @@ EntityRendererPointer EntityTreeRenderer::renderableForEntityId(const EntityItem
|
||||||
|
|
||||||
render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const {
|
render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const {
|
||||||
auto renderable = renderableForEntityId(id);
|
auto renderable = renderableForEntityId(id);
|
||||||
return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID;
|
if (renderable) {
|
||||||
|
return renderable->getRenderItemID();
|
||||||
|
} else {
|
||||||
|
return render::Item::INVALID_ITEM_ID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
|
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
|
||||||
|
|
|
@ -557,10 +557,10 @@ void NodeList::pingPunchForDomainServer() {
|
||||||
flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendPingsToDS);
|
flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendPingsToDS);
|
||||||
|
|
||||||
// send the ping packet to the local and public sockets for this node
|
// send the ping packet to the local and public sockets for this node
|
||||||
auto localPingPacket = constructICEPingPacket(PingType::Local, _sessionUUID);
|
auto localPingPacket = constructICEPingPacket(PingType::Local, _domainHandler.getICEClientID());
|
||||||
sendPacket(std::move(localPingPacket), _domainHandler.getICEPeer().getLocalSocket());
|
sendPacket(std::move(localPingPacket), _domainHandler.getICEPeer().getLocalSocket());
|
||||||
|
|
||||||
auto publicPingPacket = constructICEPingPacket(PingType::Public, _sessionUUID);
|
auto publicPingPacket = constructICEPingPacket(PingType::Public, _domainHandler.getICEClientID());
|
||||||
sendPacket(std::move(publicPingPacket), _domainHandler.getICEPeer().getPublicSocket());
|
sendPacket(std::move(publicPingPacket), _domainHandler.getICEPeer().getPublicSocket());
|
||||||
|
|
||||||
_domainHandler.getICEPeer().incrementConnectionAttempts();
|
_domainHandler.getICEPeer().incrementConnectionAttempts();
|
||||||
|
|
|
@ -72,6 +72,8 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::MicrophoneAudioWithEcho:
|
case PacketType::MicrophoneAudioWithEcho:
|
||||||
case PacketType::AudioStreamStats:
|
case PacketType::AudioStreamStats:
|
||||||
return static_cast<PacketVersion>(AudioVersion::HighDynamicRangeVolume);
|
return static_cast<PacketVersion>(AudioVersion::HighDynamicRangeVolume);
|
||||||
|
case PacketType::ICEPing:
|
||||||
|
return static_cast<PacketVersion>(IcePingVersion::SendICEPeerID);
|
||||||
default:
|
default:
|
||||||
return 17;
|
return 17;
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,4 +278,8 @@ enum class MessageDataVersion : PacketVersion {
|
||||||
TextOrBinaryData = 18
|
TextOrBinaryData = 18
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class IcePingVersion : PacketVersion {
|
||||||
|
SendICEPeerID = 18
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//
|
//
|
||||||
// ConfigSlider.qml
|
// ConfigSlider.qml
|
||||||
// examples/utilities/tools/render
|
|
||||||
//
|
//
|
||||||
// Created by Zach Pomerantz on 2/8/2016
|
// Created by Zach Pomerantz on 2/8/2016
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
@ -8,12 +7,21 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
import QtQuick 2.5
|
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 1.4 as Original
|
||||||
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
|
import "qrc:///qml/styles-uit"
|
||||||
|
import "qrc:///qml/controls-uit" as HifiControls
|
||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
HifiConstants { id: hifi }
|
||||||
id: root
|
id: root
|
||||||
width: 400
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
height: 24
|
height: 24
|
||||||
property bool integral: false
|
property bool integral: false
|
||||||
property var config
|
property var config
|
||||||
|
@ -28,22 +36,21 @@ Item {
|
||||||
bindingControl.when = true;
|
bindingControl.when = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
HifiControls.Label {
|
||||||
id: labelControl
|
id: labelControl
|
||||||
text: root.label
|
text: root.label
|
||||||
|
enabled: true
|
||||||
anchors.left: root.left
|
anchors.left: root.left
|
||||||
anchors.leftMargin: 8
|
anchors.right: root.horizontalCenter
|
||||||
anchors.top: root.top
|
anchors.verticalCenter: root.verticalCenter
|
||||||
anchors.topMargin: 7
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
HifiControls.Label {
|
||||||
id: labelValue
|
id: labelValue
|
||||||
text: sliderControl.value.toFixed(root.integral ? 0 : 2)
|
text: sliderControl.value.toFixed(root.integral ? 0 : 2)
|
||||||
anchors.left: root.left
|
anchors.right: root.right
|
||||||
anchors.leftMargin: 200
|
anchors.bottom: root.bottom
|
||||||
anchors.top: root.top
|
anchors.bottomMargin: 0
|
||||||
anchors.topMargin: 15
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Binding {
|
Binding {
|
||||||
|
@ -54,14 +61,13 @@ Item {
|
||||||
when: false
|
when: false
|
||||||
}
|
}
|
||||||
|
|
||||||
Slider {
|
HifiControls.Slider {
|
||||||
id: sliderControl
|
id: sliderControl
|
||||||
stepSize: root.integral ? 1.0 : 0.0
|
stepSize: root.integral ? 1.0 : 0.0
|
||||||
width: root.width-130
|
anchors.left: root.horizontalCenter
|
||||||
height: 20
|
|
||||||
anchors.right: root.right
|
anchors.right: root.right
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: 0
|
||||||
anchors.top: root.top
|
anchors.top: root.top
|
||||||
anchors.topMargin: 3
|
anchors.topMargin: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
//
|
|
||||||
// debugDeferredLighting.js
|
|
||||||
//
|
|
||||||
// Created by Sam Gateau on 6/6/2016
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
// Set up the qml ui
|
|
||||||
var qml = Script.resolvePath('deferredLighting.qml');
|
|
||||||
var window = new OverlayWindow({
|
|
||||||
title: 'Lighting',
|
|
||||||
source: qml,
|
|
||||||
width: 400, height:400,
|
|
||||||
});
|
|
||||||
window.setPosition(Window.innerWidth - 420, 50);
|
|
||||||
window.closed.connect(function() { Script.stop(); });
|
|
||||||
|
|
||||||
|
|
||||||
var DDB = Render.RenderDeferredTask.DebugDeferredBuffer;
|
|
||||||
DDB.enabled = true;
|
|
||||||
DDB.mode = 0;
|
|
||||||
|
|
||||||
// Debug buffer sizing
|
|
||||||
var resizing = false;
|
|
||||||
Controller.mousePressEvent.connect(function (e) {
|
|
||||||
if (shouldStartResizing(e.x)) {
|
|
||||||
resizing = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Controller.mouseReleaseEvent.connect(function() { resizing = false; });
|
|
||||||
Controller.mouseMoveEvent.connect(function (e) { resizing && setDebugBufferSize(e.x); });
|
|
||||||
Script.scriptEnding.connect(function () { DDB.enabled = false; });
|
|
||||||
|
|
||||||
function shouldStartResizing(eventX) {
|
|
||||||
var x = Math.abs(eventX - Window.innerWidth * (1.0 + DDB.size.x) / 2.0);
|
|
||||||
var mode = DDB.mode;
|
|
||||||
return mode !== 0 && x < 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setDebugBufferSize(x) {
|
|
||||||
x = (2.0 * (x / Window.innerWidth) - 1.0); // scale
|
|
||||||
x = Math.min(Math.max(-1, x), 1); // clamp
|
|
||||||
DDB.size = { x: x, y: -1, z: 1, w: 1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -7,215 +7,268 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import "configSlider"
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
Column {
|
import "qrc:///qml/styles-uit"
|
||||||
spacing: 8
|
import "qrc:///qml/controls-uit" as HifiControls
|
||||||
property var mainViewTask: Render.getConfig("RenderMainView")
|
import "configSlider"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
HifiConstants { id: hifi;}
|
||||||
|
id: render;
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
Row {
|
color: hifi.colors.baseGray;
|
||||||
spacing: 8
|
property var mainViewTask: Render.getConfig("RenderMainView")
|
||||||
Column {
|
|
||||||
spacing: 10
|
|
||||||
Repeater {
|
|
||||||
model: [
|
|
||||||
"Unlit:LightingModel:enableUnlit",
|
|
||||||
"Emissive:LightingModel:enableEmissive",
|
|
||||||
"Lightmap:LightingModel:enableLightmap",
|
|
||||||
"Background:LightingModel:enableBackground",
|
|
||||||
"ssao:AmbientOcclusion:enabled",
|
|
||||||
"Textures:LightingModel:enableMaterialTexturing"
|
|
||||||
]
|
|
||||||
CheckBox {
|
|
||||||
text: modelData.split(":")[0]
|
|
||||||
checked: mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 10
|
|
||||||
Repeater {
|
|
||||||
model: [
|
|
||||||
"Obscurance:LightingModel:enableObscurance",
|
|
||||||
"Scattering:LightingModel:enableScattering",
|
|
||||||
"Diffuse:LightingModel:enableDiffuse",
|
|
||||||
"Specular:LightingModel:enableSpecular",
|
|
||||||
"Albedo:LightingModel:enableAlbedo",
|
|
||||||
"Wireframe:LightingModel:enableWireframe"
|
|
||||||
]
|
|
||||||
CheckBox {
|
|
||||||
text: modelData.split(":")[0]
|
|
||||||
checked: mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 10
|
|
||||||
Repeater {
|
|
||||||
model: [
|
|
||||||
"Ambient:LightingModel:enableAmbientLight",
|
|
||||||
"Directional:LightingModel:enableDirectionalLight",
|
|
||||||
"Point:LightingModel:enablePointLight",
|
|
||||||
"Spot:LightingModel:enableSpotLight",
|
|
||||||
"Light Contour:LightingModel:showLightContour",
|
|
||||||
"Zone Stack:DrawZoneStack:enabled",
|
|
||||||
"Shadow:RenderShadowTask:enabled"
|
|
||||||
]
|
|
||||||
CheckBox {
|
|
||||||
text: modelData.split(":")[0]
|
|
||||||
checked: mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Column {
|
Column {
|
||||||
spacing: 10
|
spacing: 5
|
||||||
Repeater {
|
anchors.left: parent.left
|
||||||
model: [ "Tone Mapping Exposure:ToneMapping:exposure:5.0:-5.0"
|
anchors.right: parent.right
|
||||||
]
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
ConfigSlider {
|
//padding: hifi.dimensions.contentMargin.x
|
||||||
label: qsTr(modelData.split(":")[0])
|
HifiControls.Label {
|
||||||
integral: false
|
text: "Shading"
|
||||||
config: mainViewTask.getConfig(modelData.split(":")[1])
|
}
|
||||||
property: modelData.split(":")[2]
|
Row {
|
||||||
max: modelData.split(":")[3]
|
anchors.left: parent.left
|
||||||
min: modelData.split(":")[4]
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
spacing: 20
|
||||||
|
Column {
|
||||||
|
spacing: 10
|
||||||
|
// padding: 10
|
||||||
|
Repeater {
|
||||||
|
model: [
|
||||||
|
"Unlit:LightingModel:enableUnlit",
|
||||||
|
"Emissive:LightingModel:enableEmissive",
|
||||||
|
"Lightmap:LightingModel:enableLightmap",
|
||||||
|
"Background:LightingModel:enableBackground",
|
||||||
|
"ssao:AmbientOcclusion:enabled",
|
||||||
|
"Textures:LightingModel:enableMaterialTexturing"
|
||||||
|
]
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: modelData.split(":")[0]
|
||||||
|
checked: render.mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 10
|
||||||
|
Repeater {
|
||||||
|
model: [
|
||||||
|
"Obscurance:LightingModel:enableObscurance",
|
||||||
|
"Scattering:LightingModel:enableScattering",
|
||||||
|
"Diffuse:LightingModel:enableDiffuse",
|
||||||
|
"Specular:LightingModel:enableSpecular",
|
||||||
|
"Albedo:LightingModel:enableAlbedo",
|
||||||
|
"Wireframe:LightingModel:enableWireframe"
|
||||||
|
]
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: modelData.split(":")[0]
|
||||||
|
checked: render.mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 10
|
||||||
|
Repeater {
|
||||||
|
model: [
|
||||||
|
"Ambient:LightingModel:enableAmbientLight",
|
||||||
|
"Directional:LightingModel:enableDirectionalLight",
|
||||||
|
"Point:LightingModel:enablePointLight",
|
||||||
|
"Spot:LightingModel:enableSpotLight",
|
||||||
|
"Light Contour:LightingModel:showLightContour",
|
||||||
|
"Zone Stack:DrawZoneStack:enabled",
|
||||||
|
"Shadow:RenderShadowTask:enabled"
|
||||||
|
]
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: modelData.split(":")[0]
|
||||||
|
checked: render.mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Separator {}
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
spacing: 10
|
||||||
|
Repeater {
|
||||||
|
model: [ "Tone Mapping Exposure:ToneMapping:exposure:5.0:-5.0"
|
||||||
|
]
|
||||||
|
ConfigSlider {
|
||||||
|
label: qsTr(modelData.split(":")[0])
|
||||||
|
integral: false
|
||||||
|
config: render.mainViewTask.getConfig(modelData.split(":")[1])
|
||||||
|
property: modelData.split(":")[2]
|
||||||
|
max: modelData.split(":")[3]
|
||||||
|
min: modelData.split(":")[4]
|
||||||
|
|
||||||
Row {
|
anchors.left: parent.left
|
||||||
Label {
|
anchors.right: parent.right
|
||||||
text: "Tone Mapping Curve"
|
}
|
||||||
anchors.left: root.left
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBox {
|
Item {
|
||||||
anchors.right: root.right
|
height: childrenRect.height
|
||||||
currentIndex: 1
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
HifiControls.Label {
|
||||||
|
text: "Tone Mapping Curve"
|
||||||
|
anchors.left: parent.left
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.ComboBox {
|
||||||
|
anchors.right: parent.right
|
||||||
|
currentIndex: 1
|
||||||
|
model: ListModel {
|
||||||
|
id: cbItems
|
||||||
|
ListElement { text: "RGB"; color: "Yellow" }
|
||||||
|
ListElement { text: "SRGB"; color: "Green" }
|
||||||
|
ListElement { text: "Reinhard"; color: "Yellow" }
|
||||||
|
ListElement { text: "Filmic"; color: "White" }
|
||||||
|
}
|
||||||
|
width: 200
|
||||||
|
onCurrentIndexChanged: { render.mainViewTask.getConfig("ToneMapping")["curve"] = currentIndex }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Separator {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: childrenRect.height
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
id: framebuffer
|
||||||
|
|
||||||
|
HifiControls.Label {
|
||||||
|
text: "Debug Framebuffer"
|
||||||
|
anchors.left: parent.left
|
||||||
|
}
|
||||||
|
|
||||||
|
property var config: render.mainViewTask.getConfig("DebugDeferredBuffer")
|
||||||
|
|
||||||
|
function setDebugMode(mode) {
|
||||||
|
framebuffer.config.enabled = (mode != 0);
|
||||||
|
framebuffer.config.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.ComboBox {
|
||||||
|
anchors.right: parent.right
|
||||||
|
currentIndex: 0
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
id: cbItems
|
id: cbItemsFramebuffer
|
||||||
ListElement { text: "RGB"; color: "Yellow" }
|
ListElement { text: "Off"; color: "Yellow" }
|
||||||
ListElement { text: "SRGB"; color: "Green" }
|
ListElement { text: "Depth"; color: "Green" }
|
||||||
ListElement { text: "Reinhard"; color: "Yellow" }
|
ListElement { text: "Albedo"; color: "Yellow" }
|
||||||
ListElement { text: "Filmic"; color: "White" }
|
ListElement { text: "Normal"; color: "White" }
|
||||||
|
ListElement { text: "Roughness"; color: "White" }
|
||||||
|
ListElement { text: "Metallic"; color: "White" }
|
||||||
|
ListElement { text: "Emissive"; color: "White" }
|
||||||
|
ListElement { text: "Unlit"; color: "White" }
|
||||||
|
ListElement { text: "Occlusion"; color: "White" }
|
||||||
|
ListElement { text: "Lightmap"; color: "White" }
|
||||||
|
ListElement { text: "Scattering"; color: "White" }
|
||||||
|
ListElement { text: "Lighting"; color: "White" }
|
||||||
|
ListElement { text: "Shadow"; color: "White" }
|
||||||
|
ListElement { text: "Linear Depth"; color: "White" }
|
||||||
|
ListElement { text: "Half Linear Depth"; color: "White" }
|
||||||
|
ListElement { text: "Half Normal"; color: "White" }
|
||||||
|
ListElement { text: "Mid Curvature"; color: "White" }
|
||||||
|
ListElement { text: "Mid Normal"; color: "White" }
|
||||||
|
ListElement { text: "Low Curvature"; color: "White" }
|
||||||
|
ListElement { text: "Low Normal"; color: "White" }
|
||||||
|
ListElement { text: "Curvature Occlusion"; color: "White" }
|
||||||
|
ListElement { text: "Debug Scattering"; color: "White" }
|
||||||
|
ListElement { text: "Ambient Occlusion"; color: "White" }
|
||||||
|
ListElement { text: "Ambient Occlusion Blurred"; color: "White" }
|
||||||
|
ListElement { text: "Custom"; color: "White" }
|
||||||
}
|
}
|
||||||
width: 200
|
width: 200
|
||||||
onCurrentIndexChanged: { mainViewTask.getConfig("ToneMapping")["curve"] = currentIndex }
|
onCurrentIndexChanged: { framebuffer.setDebugMode(currentIndex) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {}
|
||||||
|
Row {
|
||||||
|
spacing: 10
|
||||||
|
Column {
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Opaques"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawOpaqueBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawOpaqueBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Transparents"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawTransparentBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawTransparentBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Opaques in Front"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawOverlayInFrontOpaqueBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawOverlayInFrontOpaqueBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Transparents in Front"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawOverlayInFrontTransparentBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawOverlayInFrontTransparentBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Opaques in HUD"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawOverlayHUDOpaqueBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawOverlayHUDOpaqueBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Transparents in HUD"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawOverlayHUDTransparentBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawOverlayHUDTransparentBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
spacing: 10
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Metas"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawMetaBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawMetaBounds")["enabled"] = checked }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Lights"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawLightBounds")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("DrawLightBounds")["enabled"] = checked; }
|
||||||
|
}
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
|
text: "Zones"
|
||||||
|
checked: render.mainViewTask.getConfig("DrawZones")["enabled"]
|
||||||
|
onCheckedChanged: { render.mainViewTask.getConfig("ZoneRenderer")["enabled"] = checked; render.mainViewTask.getConfig("DrawZones")["enabled"] = checked; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row {
|
//}
|
||||||
id: framebuffer
|
|
||||||
spacing: 10
|
|
||||||
|
|
||||||
Label {
|
|
||||||
text: "Debug Framebuffer"
|
|
||||||
anchors.left: root.left
|
|
||||||
}
|
|
||||||
|
|
||||||
property var config: mainViewTask.getConfig("DebugDeferredBuffer")
|
|
||||||
|
|
||||||
function setDebugMode(mode) {
|
|
||||||
framebuffer.config.enabled = (mode != 0);
|
|
||||||
framebuffer.config.mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComboBox {
|
|
||||||
anchors.right: root.right
|
|
||||||
currentIndex: 0
|
|
||||||
model: ListModel {
|
|
||||||
id: cbItemsFramebuffer
|
|
||||||
ListElement { text: "Off"; color: "Yellow" }
|
|
||||||
ListElement { text: "Depth"; color: "Green" }
|
|
||||||
ListElement { text: "Albedo"; color: "Yellow" }
|
|
||||||
ListElement { text: "Normal"; color: "White" }
|
|
||||||
ListElement { text: "Roughness"; color: "White" }
|
|
||||||
ListElement { text: "Metallic"; color: "White" }
|
|
||||||
ListElement { text: "Emissive"; color: "White" }
|
|
||||||
ListElement { text: "Unlit"; color: "White" }
|
|
||||||
ListElement { text: "Occlusion"; color: "White" }
|
|
||||||
ListElement { text: "Lightmap"; color: "White" }
|
|
||||||
ListElement { text: "Scattering"; color: "White" }
|
|
||||||
ListElement { text: "Lighting"; color: "White" }
|
|
||||||
ListElement { text: "Shadow"; color: "White" }
|
|
||||||
ListElement { text: "Linear Depth"; color: "White" }
|
|
||||||
ListElement { text: "Half Linear Depth"; color: "White" }
|
|
||||||
ListElement { text: "Half Normal"; color: "White" }
|
|
||||||
ListElement { text: "Mid Curvature"; color: "White" }
|
|
||||||
ListElement { text: "Mid Normal"; color: "White" }
|
|
||||||
ListElement { text: "Low Curvature"; color: "White" }
|
|
||||||
ListElement { text: "Low Normal"; color: "White" }
|
|
||||||
ListElement { text: "Curvature Occlusion"; color: "White" }
|
|
||||||
ListElement { text: "Debug Scattering"; color: "White" }
|
|
||||||
ListElement { text: "Ambient Occlusion"; color: "White" }
|
|
||||||
ListElement { text: "Ambient Occlusion Blurred"; color: "White" }
|
|
||||||
ListElement { text: "Custom"; color: "White" }
|
|
||||||
}
|
|
||||||
width: 200
|
|
||||||
onCurrentIndexChanged: { framebuffer.setDebugMode(currentIndex) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
Column {
|
|
||||||
|
|
||||||
CheckBox {
|
|
||||||
text: "Opaques"
|
|
||||||
checked: mainViewTask.getConfig("DrawOpaqueBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawOpaqueBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Transparents"
|
|
||||||
checked: mainViewTask.getConfig("DrawTransparentBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawTransparentBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Opaques in Front"
|
|
||||||
checked: mainViewTask.getConfig("DrawOverlayInFrontOpaqueBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayInFrontOpaqueBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Transparents in Front"
|
|
||||||
checked: mainViewTask.getConfig("DrawOverlayInFrontTransparentBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayInFrontTransparentBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Opaques in HUD"
|
|
||||||
checked: mainViewTask.getConfig("DrawOverlayHUDOpaqueBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayHUDOpaqueBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Transparents in HUD"
|
|
||||||
checked: mainViewTask.getConfig("DrawOverlayHUDTransparentBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawOverlayHUDTransparentBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Column {
|
|
||||||
CheckBox {
|
|
||||||
text: "Metas"
|
|
||||||
checked: mainViewTask.getConfig("DrawMetaBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawMetaBounds")["enabled"] = checked }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Lights"
|
|
||||||
checked: mainViewTask.getConfig("DrawLightBounds")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("DrawLightBounds")["enabled"] = checked; }
|
|
||||||
}
|
|
||||||
CheckBox {
|
|
||||||
text: "Zones"
|
|
||||||
checked: mainViewTask.getConfig("DrawZones")["enabled"]
|
|
||||||
onCheckedChanged: { mainViewTask.getConfig("ZoneRenderer")["enabled"] = checked; mainViewTask.getConfig("DrawZones")["enabled"] = checked; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
102
scripts/developer/utilities/render/luci.js
Normal file
102
scripts/developer/utilities/render/luci.js
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
//
|
||||||
|
// Luci.js
|
||||||
|
// tablet-engine app
|
||||||
|
//
|
||||||
|
// Copyright 2017 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
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var TABLET_BUTTON_NAME = "LUCI";
|
||||||
|
var QMLAPP_URL = Script.resolvePath("./deferredLighting.qml");
|
||||||
|
var ICON_URL = Script.resolvePath("../../../system/assets/images/luci-i.svg");
|
||||||
|
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/luci-a.svg");
|
||||||
|
|
||||||
|
|
||||||
|
var onLuciScreen = false;
|
||||||
|
|
||||||
|
function onClicked() {
|
||||||
|
if (onLuciScreen) {
|
||||||
|
tablet.gotoHomeScreen();
|
||||||
|
} else {
|
||||||
|
tablet.loadQMLSource(QMLAPP_URL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
var button = tablet.addButton({
|
||||||
|
text: TABLET_BUTTON_NAME,
|
||||||
|
icon: ICON_URL,
|
||||||
|
activeIcon: ACTIVE_ICON_URL,
|
||||||
|
sortOrder: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasEventBridge = false;
|
||||||
|
|
||||||
|
function wireEventBridge(on) {
|
||||||
|
if (!tablet) {
|
||||||
|
print("Warning in wireEventBridge(): 'tablet' undefined!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (on) {
|
||||||
|
if (!hasEventBridge) {
|
||||||
|
tablet.fromQml.connect(fromQml);
|
||||||
|
hasEventBridge = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hasEventBridge) {
|
||||||
|
tablet.fromQml.disconnect(fromQml);
|
||||||
|
hasEventBridge = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onScreenChanged(type, url) {
|
||||||
|
if (url === QMLAPP_URL) {
|
||||||
|
onLuciScreen = true;
|
||||||
|
} else {
|
||||||
|
onLuciScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.editProperties({isActive: onLuciScreen});
|
||||||
|
wireEventBridge(onLuciScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromQml(message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
button.clicked.connect(onClicked);
|
||||||
|
tablet.screenChanged.connect(onScreenChanged);
|
||||||
|
|
||||||
|
var moveDebugCursor = false;
|
||||||
|
Controller.mousePressEvent.connect(function (e) {
|
||||||
|
if (e.isMiddleButton) {
|
||||||
|
moveDebugCursor = true;
|
||||||
|
setDebugCursor(e.x, e.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Controller.mouseReleaseEvent.connect(function() { moveDebugCursor = false; });
|
||||||
|
Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); });
|
||||||
|
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
if (onLuciScreen) {
|
||||||
|
tablet.gotoHomeScreen();
|
||||||
|
}
|
||||||
|
button.clicked.disconnect(onClicked);
|
||||||
|
tablet.screenChanged.disconnect(onScreenChanged);
|
||||||
|
tablet.removeButton(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
function setDebugCursor(x, y) {
|
||||||
|
nx = (x / Window.innerWidth);
|
||||||
|
ny = 1.0 - ((y) / (Window.innerHeight - 32));
|
||||||
|
|
||||||
|
Render.getConfig("RenderMainView").getConfig("Antialiasing").debugCursorTexcoord = { x: nx, y: ny };
|
||||||
|
}
|
||||||
|
|
||||||
|
}());
|
10
scripts/system/assets/images/luci-a.svg
Normal file
10
scripts/system/assets/images/luci-a.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<path d="M18.5,36.5c-6.8-2.2-6.8-11.8-0.1-14.1l12.1-4.1c-2.6-2.4-6.1-3.8-9.9-3.8c-8.2,0-14.8,6.6-14.8,14.8
|
||||||
|
c0,8.2,6.6,14.8,14.8,14.8c3.7,0,7.1-1.4,9.7-3.7L18.5,36.5z"/>
|
||||||
|
<path d="M31.9,17.9c-0.5,0.2-0.9,0.3-1.3,0.5c2.9,2.7,4.8,6.6,4.8,10.9c0,4.4-1.9,8.3-4.9,11c0.5,0.2,1,0.5,1.6,0.7l5.9,2.4
|
||||||
|
c3.1,1,6.2-1.3,6.2-4.5V13.2L31.9,17.9z"/>
|
||||||
|
<circle cx="40" cy="6.6" r="3.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 721 B |
13
scripts/system/assets/images/luci-i.svg
Normal file
13
scripts/system/assets/images/luci-i.svg
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<path class="st0" d="M18.5,36.5c-6.8-2.2-6.8-11.8-0.1-14.1l12.1-4.1c-2.6-2.4-6.1-3.8-9.9-3.8c-8.2,0-14.8,6.6-14.8,14.8
|
||||||
|
c0,8.2,6.6,14.8,14.8,14.8c3.7,0,7.1-1.4,9.7-3.7L18.5,36.5z"/>
|
||||||
|
<path class="st0" d="M31.9,17.9c-0.5,0.2-0.9,0.3-1.3,0.5c2.9,2.7,4.8,6.6,4.8,10.9c0,4.4-1.9,8.3-4.9,11c0.5,0.2,1,0.5,1.6,0.7
|
||||||
|
l5.9,2.4c3.1,1,6.2-1.3,6.2-4.5V13.2L31.9,17.9z"/>
|
||||||
|
<circle class="st0" cx="40" cy="6.6" r="3.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 811 B |
|
@ -124,7 +124,9 @@
|
||||||
print("TABLET in showTabletUI, already rezzed");
|
print("TABLET in showTabletUI, already rezzed");
|
||||||
}
|
}
|
||||||
var tabletProperties = {};
|
var tabletProperties = {};
|
||||||
UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties);
|
if (!HMD.tabletContextualMode) { // contextual mode forces tablet in place -> don't update attachment
|
||||||
|
UIWebTablet.calculateTabletAttachmentProperties(activeHand, true, tabletProperties);
|
||||||
|
}
|
||||||
tabletProperties.visible = true;
|
tabletProperties.visible = true;
|
||||||
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
||||||
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
|
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
|
||||||
|
|
Loading…
Reference in a new issue