diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ea49b90852..140742ce88 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -206,7 +206,7 @@ void Agent::run() { scriptURL = QUrl(_payload); } - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL)); QNetworkDiskCache* cache = new QNetworkDiskCache(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 24b6127d63..b30cd355d1 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -59,6 +59,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; + const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p"; Assignment::Type requestAssignmentType = Assignment::AllTypes; @@ -87,17 +88,29 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // create a NodeList as an unassigned client NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned); + + unsigned short assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT; + + // check for an overriden assignment server port + if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) { + assignmentServerPort = + argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt(); + } + + HifiSockAddr assignmentServerSocket(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, assignmentServerPort); // check for an overriden assignment server hostname if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) { _assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); - // set the custom assignment socket on our NodeList - HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); - - nodeList->setAssignmentServerSocket(customAssignmentSocket); + // change the hostname for our assignment server + assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerSocket.getPort()); } + + nodeList->setAssignmentServerSocket(assignmentServerSocket); + qDebug() << "Assignment server socket is" << assignmentServerSocket; + // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required qDebug() << "Waiting for assignment -" << _requestAssignment; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 5833d8a764..42af8ff1b9 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -940,7 +940,7 @@ void OctreeServer::run() { qDebug("--statusHost=%s", statusHost); _statusHost = statusHost; } else { - _statusHost = QHostAddress(getHostOrderLocalAddress()).toString(); + _statusHost = getLocalAddress().toString(); } qDebug("statusHost=%s", qPrintable(_statusHost)); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 2fbe33a4e1..30d843c7eb 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -33,6 +33,14 @@ "label": "None: use the network information I have entered for this domain at data.highfidelity.io" } ] + }, + { + "name": "local_port", + "label": "Local UDP Port", + "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to run multiple full automatic networking domain-servers in the same network.", + "default": "40102", + "type": "int", + "advanced": true } ] }, @@ -51,6 +59,19 @@ "type": "password", "help": "Password used for basic HTTP authentication. Leave this blank if you do not want to change it.", "value-hidden": true + }, + { + "name": "allowed_users", + "type": "table", + "label": "Allowed Users", + "help": "A list of usernames for the High Fidelity users you want to allow into your domain. Users not found in this list will not be allowed to connect.", + "numbered": false, + "can_add": true, + "can_delete": true, + "key": { + "name": "username", + "label": "Username" + } } ] }, @@ -59,10 +80,44 @@ "label": "Audio", "assignment-types": [0], "settings": [ + { + "name": "zones", + "type": "table", + "label": "Zones", + "help": "In this table you can define a set of zones in which you can specify various audio properties.", + "numbered": false, + "can_add": true, + "can_delete": true, + "key": { + "name": "name", + "label": "Name", + "placeholder": "Zone name" + }, + "columns": [ + { + "name": "x_range", + "label": "X range", + "can_set": true, + "placeholder": "0-16384" + }, + { + "name": "y_range", + "label": "Y range", + "can_set": true, + "placeholder": "0-16384" + }, + { + "name": "z_range", + "label": "Z range", + "can_set": true, + "placeholder": "0-16384" + } + ] + }, { "name": "enable_filter", "type": "checkbox", - "label": "Enable Positional Filter", + "label": "Positional filter", "help": "positional audio stream uses lowpass filter", "default": true }, diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 60f493593a..4c365ed110 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -74,3 +74,12 @@ span.port { width: 100%; margin-bottom: 15px; } + +td.buttons { + width: 14px; +} + +td.buttons .glyphicon { + display: block; + text-align: center; +} diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index b964887d19..311a25dacd 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -25,10 +25,12 @@ var viewHelpers = { form_group += "" form_group += "
" form_group += ""; form_group += "
" + } else if (setting.type === 'table') { + form_group += makeTable(setting, setting_name, setting_value); } else { input_type = _.has(setting, 'type') ? setting.type : "text" @@ -39,13 +41,18 @@ var viewHelpers = { _.each(setting.options, function(option) { form_group += "" + (option.value == setting_value ? 'selected' : '') + ">" + option.label + "" }) form_group += "" form_group += "" } else { + + if (input_type == 'integer') { + input_type = "text" + } + form_group += "" @@ -69,17 +76,101 @@ $(document).ready(function(){ */ $('[data-clampedwidth]').each(function () { - var elem = $(this); - var parentPanel = elem.data('clampedwidth'); - var resizeFn = function () { - var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth')); - elem.css('width', sideBarNavWidth); - }; + var elem = $(this); + var parentPanel = elem.data('clampedwidth'); + var resizeFn = function () { + var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth')); + elem.css('width', sideBarNavWidth); + }; - resizeFn(); - $(window).resize(resizeFn); + resizeFn(); + $(window).resize(resizeFn); }) - + + $('#settings-form').on('click', '.add-row', function(){ + var row = $(this).parents("tr") + var data = row.parent().children(".row-data") + + // Check key spaces + var name = row.children(".key").children("input").val() + if (name.indexOf(' ') !== -1) { + showAlertMessage("Key contains spaces", false) + return + } + // Check keys with the same name + var equals = false; + _.each(data.children(".key"), function(element) { + if ($(element).text() === name) { + equals = true + return + } + }) + if (equals) { + showAlertMessage("Two keys cannot be identical.", false) + return + } + + // Check empty fields + var empty = false; + _.each(row.children(".row-data").children("input"), function(element) { + if ($(element).val().length === 0) { + empty = true + return + } + }) + if (empty) { + showAlertMessage("Empty field(s)") + return + } + + var input_clone = row.clone() + // Change input row to data row + var full_name = row.parents("table").attr("name") + "." + name + row.attr("class", "row-data") + + _.each(row.children(), function(element) { + if ($(element).hasClass("number")) { // Index row + var numbers = data.children(".number") + if (numbers.length > 0) { + $(element).html(parseInt(numbers.last().text()) + 1) + } else { + $(element).html(1) + } + } else if ($(element).hasClass("buttons")) { // Change buttons + var prevSpan = $(element).parent().prev().children(".buttons").children("span") + var span = $(element).children("span") + if (prevSpan.hasClass("del-row")) { + span.removeClass("glyphicon-ok add-row") + span.addClass("glyphicon-remove del-row") + } else { + span.remove() + } + } else if ($(element).hasClass("key")) { + var input = $(element).children("input") + $(element).html(input.val()) + input.remove() + } else if($(element).hasClass("row-data")) { // Hide inputs + var input = $(element).children("input") + input.attr("type", "hidden") + input.attr("name", full_name + "." + $(element).attr("name")) + input.attr("value", input.val()) + input.attr("data-changed", "true") + + $(element).html($(element).html() + input.val()) + } else { + console.log("Unknown table element") + } + }) + row.parent().append(input_clone) + showAlertMessage("Row added", true) + }) + + $('#settings-form').on('click', '.del-row', function(){ + var row = $(this).parents("tr") + row.empty() + row.html(""); + }) + $('#settings-form').on('change', 'input', function(){ // this input was changed, add the changed data attribute to it $(this).attr('data-changed', true) @@ -89,7 +180,7 @@ $(document).ready(function(){ $('#advanced-toggle-button').click(function(){ Settings.showAdvanced = !Settings.showAdvanced - var advancedSelector = $('.advanced-setting') + var advancedSelector = $('.advanced-setting') if (Settings.showAdvanced) { advancedSelector.show() @@ -188,6 +279,78 @@ $('body').on('click', '.save-button', function(e){ return false; }); +function makeTable(setting, setting_name, setting_value) { + var html = "" + html += "" + setting.help + "" + html += "" + + // Column names + html += "" + if (setting.number === true) { + html += "" // Row number + } + html += "" // Key + _.each(setting.columns, function(col) { + html += "" // Data + }) + if (setting.can_delete === true || setting.can_add === true) { + html += "" // Buttons + } + html += "" + + // Rows + var row_num = 1 + _.each(setting_value, function(row, name) { + html += "" + if (setting.numbered === true) { + html += "" + } + html += "" + _.each(setting.columns, function(col) { + html += "" + }) + if (setting.can_delete === true) { + html += "" + } else if (setting.can_add === true) { + html += "" + } + html += "" + row_num++ + }) + + // Inputs + if (setting.can_add === true) { + html += makeTableInputs(setting) + } + + html += "
#" + setting.key.label + "" + col.label + "+/-
" + row_num + "" + name + "" + if (row.hasOwnProperty(col.name)) { + html += row[col.name] + } + html += "
" + + return html; +} + +function makeTableInputs(setting) { + var html = "" + if (setting.numbered === true) { + html += "" + } + html += "\ + \ + " + _.each(setting.columns, function(col) { + html += "\ + \ + " + }) + html += "" + html += "" + + return html +} + function badgeSidebarForDifferences(changedInput) { // figure out which group this input is in var panelParentID = changedInput.closest('.panel').attr('id') @@ -237,7 +400,7 @@ function showRestartModal() { }, 1000); } -function cleanupFormValues(node) { +function cleanupFormValues(node) { if (node.type && node.type === 'checkbox') { return { name: node.name, value: node.checked ? true : false }; } else { diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 61310cad75..fa7a0fe012 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -57,6 +57,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); + // make sure we have a fresh AccountManager instance + // (need this since domain-server can restart itself and maintain static variables) + AccountManager::getInstance(true); + _settingsManager.setupConfigMap(arguments()); installNativeEventFilter(&_shutdownEventListener); @@ -82,10 +86,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : void DomainServer::restart() { qDebug() << "domain-server is restarting."; - // make sure all static instances are reset - LimitedNodeList::getInstance()->reset(); - AccountManager::getInstance(true); - exit(DomainServer::EXIT_CODE_REBOOT); } @@ -189,17 +189,20 @@ bool DomainServer::optionallySetupOAuth() { const QString DOMAIN_CONFIG_ID_KEY = "id"; +const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; +const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; +const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; +const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; + void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { - const QString CUSTOM_PORT_OPTION = "port"; - unsigned short domainServerPort = DEFAULT_DOMAIN_SERVER_PORT; + const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; + + QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION); + unsigned short domainServerPort = (unsigned short) localPortValue.toUInt(); QVariantMap& settingsMap = _settingsManager.getSettingsMap(); - if (settingsMap.contains(CUSTOM_PORT_OPTION)) { - domainServerPort = (unsigned short) settingsMap.value(CUSTOM_PORT_OPTION).toUInt(); - } - unsigned short domainServerDTLSPort = 0; if (_isUsingDTLS) { @@ -310,12 +313,7 @@ bool DomainServer::optionallySetupAssignmentPayment() { return true; } -const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; -const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; -const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; - void DomainServer::setupAutomaticNetworking() { - const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; if (!didSetupAccountManagerWithAccessToken()) { qDebug() << "Cannot setup domain-server automatic networking without an access token."; @@ -357,7 +355,8 @@ void DomainServer::setupAutomaticNetworking() { connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates); iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); - // call our sendHeartbeaToIceServer immediately anytime a public address changes + // call our sendHeartbeaToIceServer immediately anytime a local or public socket changes + connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); // tell the data server which type of automatic networking we are using diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 28b1151f2d..6a63168579 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -29,6 +29,7 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings const QString DESCRIPTION_SETTINGS_KEY = "settings"; const QString SETTING_DEFAULT_KEY = "default"; const QString DESCRIPTION_NAME_KEY = "name"; +const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; DomainServerSettingsManager::DomainServerSettingsManager() : _descriptionArray(), @@ -232,63 +233,92 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty return responseObject; } +bool DomainServerSettingsManager::settingExists(const QString& groupName, const QString& settingName, + const QJsonArray& descriptionArray, QJsonValue& settingDescription) { + foreach(const QJsonValue& groupValue, descriptionArray) { + QJsonObject groupObject = groupValue.toObject(); + if (groupObject[DESCRIPTION_NAME_KEY].toString() == groupName) { + + foreach(const QJsonValue& settingValue, groupObject[DESCRIPTION_SETTINGS_KEY].toArray()) { + QJsonObject settingObject = settingValue.toObject(); + if (settingObject[DESCRIPTION_NAME_KEY].toString() == settingName) { + settingDescription = settingObject[SETTING_DEFAULT_KEY]; + return true; + } + } + } + } + settingDescription = QJsonValue::Undefined; + return false; +} -const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; +void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap, + const QJsonValue& settingDescription) { + if (newValue.isString()) { + if (newValue.toString().isEmpty()) { + // this is an empty value, clear it in settings variant so the default is sent + settingMap.remove(key); + } else { + // make sure the resulting json value has the right type + const QString settingType = settingDescription.toObject()[SETTING_DESCRIPTION_TYPE_KEY].toString(); + const QString INPUT_DOUBLE_TYPE = "double"; + const QString INPUT_INTEGER_TYPE = "int"; + + if (settingType == INPUT_DOUBLE_TYPE) { + settingMap[key] = newValue.toString().toDouble(); + } else if (settingType == INPUT_INTEGER_TYPE) { + settingMap[key] = newValue.toString().toInt(); + } else { + settingMap[key] = newValue.toString(); + } + } + } else if (newValue.isBool()) { + settingMap[key] = newValue.toBool(); + } else if (newValue.isObject()) { + if (!settingMap.contains(key)) { + // we don't have a map below this key yet, so set it up now + settingMap[key] = QVariantMap(); + } + + QVariantMap& thisMap = *reinterpret_cast(settingMap[key].data()); + foreach(const QString childKey, newValue.toObject().keys()) { + updateSetting(childKey, newValue.toObject()[childKey], thisMap, settingDescription.toObject()[key]); + } + + if (settingMap[key].toMap().isEmpty()) { + // we've cleared all of the settings below this value, so remove this one too + settingMap.remove(key); + } + } +} void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, - QJsonArray descriptionArray) { - foreach(const QString& key, postedObject.keys()) { + const QJsonArray& descriptionArray) { + // Iterate on the setting groups + foreach(const QString& groupKey, postedObject.keys()) { + QJsonValue groupValue = postedObject[groupKey]; - QJsonValue rootValue = postedObject[key]; + if (!settingsVariant.contains(groupKey)) { + // we don't have a map below this key yet, so set it up now + settingsVariant[groupKey] = QVariantMap(); + } - // we don't continue if this key is not present in our descriptionObject - foreach(const QJsonValue& groupValue, descriptionArray) { - if (groupValue.toObject()[DESCRIPTION_NAME_KEY].toString() == key) { - QJsonObject groupObject = groupValue.toObject(); - if (rootValue.isString()) { - if (rootValue.toString().isEmpty()) { - // this is an empty value, clear it in settings variant so the default is sent - settingsVariant.remove(key); - } else { - QString settingType = groupObject[SETTING_DESCRIPTION_TYPE_KEY].toString(); - - const QString INPUT_DOUBLE_TYPE = "double"; - - // make sure the resulting json value has the right type - - if (settingType == INPUT_DOUBLE_TYPE) { - settingsVariant[key] = rootValue.toString().toDouble(); - } else { - settingsVariant[key] = rootValue.toString(); - } - } - } else if (rootValue.isBool()) { - settingsVariant[key] = rootValue.toBool(); - } else if (rootValue.isObject()) { - // there's a JSON Object to explore, so attempt to recurse into it - QJsonObject nextDescriptionObject = groupObject; - - if (nextDescriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) { - if (!settingsVariant.contains(key)) { - // we don't have a map below this key yet, so set it up now - settingsVariant[key] = QVariantMap(); - } - - QVariantMap& thisMap = *reinterpret_cast(settingsVariant[key].data()); - - recurseJSONObjectAndOverwriteSettings(rootValue.toObject(), - thisMap, - nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toArray()); - - if (thisMap.isEmpty()) { - // we've cleared all of the settings below this value, so remove this one too - settingsVariant.remove(key); - } - } - } + // Iterate on the settings + foreach(const QString& settingKey, groupValue.toObject().keys()) { + QJsonValue settingValue = groupValue.toObject()[settingKey]; + + QJsonValue thisDescription; + if (settingExists(groupKey, settingKey, descriptionArray, thisDescription)) { + QVariantMap& thisMap = *reinterpret_cast(settingsVariant[groupKey].data()); + updateSetting(settingKey, settingValue, thisMap, thisDescription); } } + + if (settingsVariant[groupKey].toMap().empty()) { + // we've cleared all of the settings below this value, so remove this one too + settingsVariant.remove(groupKey); + } } } diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index c2e8a7d90d..a21e0dc93a 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -32,7 +32,11 @@ public: private: QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, - QJsonArray descriptionArray); + const QJsonArray& descriptionArray); + bool settingExists(const QString& groupName, const QString& settingName, + const QJsonArray& descriptionArray, QJsonValue& settingDescription); + void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap, + const QJsonValue& settingDescription); void persistToFile(); QJsonArray _descriptionArray; diff --git a/examples/leapHands.js b/examples/leapHands.js index 1095a9f4dc..222c0e4cf1 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -30,8 +30,6 @@ var leapHands = (function () { CALIBRATING = 1, CALIBRATED = 2, CALIBRATION_TIME = 1000, // milliseconds - PI = 3.141593, - isWindows, avatarScale, avatarFaceModelURL, avatarSkeletonModelURL, @@ -132,9 +130,6 @@ var leapHands = (function () { if (hands[0].controller.isActive() && hands[1].controller.isActive()) { leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; - - // TODO: Temporary detection of Windows to work around Leap Controller problem. - isWindows = (hands[1].controller.getAbsRotation().z > (0.25 * PI)); } else { calibrationStatus = UNCALIBRATED; return; @@ -318,11 +313,7 @@ var leapHands = (function () { j, side, handOffset, - handRoll, - handPitch, - handYaw, handRotation, - wristAbsRotation, locRotation, cameraOrientation, inverseAvatarOrientation; @@ -361,20 +352,22 @@ var leapHands = (function () { handOffset.x = -handOffset.x; // Hand rotation in camera coordinates ... - // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. - handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; - wristAbsRotation = wrists[h].controller.getAbsRotation(); - handPitch = 2.0 * wristAbsRotation.x - PI / 2.0; - handYaw = 2.0 * -wristAbsRotation.y; - // TODO: Roll values only work if hand is upside down; Leap Motion controller code needs investigating. - handRoll = PI + handRoll; + handRotation = wrists[h].controller.getAbsRotation(); + handRotation = { + x: handRotation.z, + y: handRotation.y, + z: handRotation.x, + w: handRotation.w + }; if (h === 0) { - handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + handRotation.x = -handRotation.x; + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 }), handRotation); } else { - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + handRotation.z = -handRotation.z; + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); + handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation); } // Hand rotation in avatar coordinates ... @@ -392,25 +385,22 @@ var leapHands = (function () { z: hands[h].zeroPosition.z - handOffset.z }; - // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. - handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; - wristAbsRotation = wrists[h].controller.getAbsRotation(); - handPitch = 2.0 * -wristAbsRotation.x; - handYaw = 2.0 * wristAbsRotation.y; + handRotation = wrists[h].controller.getAbsRotation(); + handRotation = { + x: handRotation.z, + y: handRotation.y, + z: handRotation.x, + w: handRotation.w + }; - // TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down. - // Approximate fix is to add a fudge factor. - if (h === 1 && isWindows) { - handRoll = handRoll + 0.6 * PI; - } - - // Hand position and orientation ... if (h === 0) { + handRotation.x = -handRotation.x; handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + handRotation); } else { + handRotation.z = -handRotation.z; handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + handRotation); } } diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index e07fb752e5..d9cf2c54fd 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -169,7 +169,14 @@ SelectionDisplay = (function () { alpha: 0.2, solid: true, visible: false, - rotation: yawOverlayRotation + rotation: yawOverlayRotation, + hasTickMarks: true, + majorTickMarksAngle: 12.5, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + majorTickMarksColor: { red: 0, green: 0, blue: 0 }, + minorTickMarksColor: { red: 0, green: 0, blue: 0 }, }); var rotateOverlayOuter = Overlays.addOverlay("circle3d", { @@ -179,7 +186,15 @@ SelectionDisplay = (function () { alpha: 0.2, solid: true, visible: false, - rotation: yawOverlayRotation + rotation: yawOverlayRotation, + + hasTickMarks: true, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + majorTickMarksColor: { red: 0, green: 0, blue: 0 }, + minorTickMarksColor: { red: 0, green: 0, blue: 0 }, }); var rotateOverlayCurrent = Overlays.addOverlay("circle3d", { @@ -571,7 +586,7 @@ SelectionDisplay = (function () { innerRadius: 0.9, startAt: 0, endAt: 360, - alpha: outerAlpha + alpha: outerAlpha, }); Overlays.editOverlay(rotateOverlayCurrent, @@ -584,7 +599,7 @@ SelectionDisplay = (function () { size: outerRadius, startAt: 0, endAt: 0, - innerRadius: 0.9 + innerRadius: 0.9, }); // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c90a5ade9f..718360864a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -349,7 +349,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkDiskCache* cache = new QNetworkDiskCache(); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); networkAccessManager.setCache(cache); diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index cb3d43925d..4808842036 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -28,7 +28,7 @@ FileLogger::FileLogger(QObject* parent) : setExtraDebugging(false); _fileName = FileUtils::standardPath(LOGS_DIRECTORY); - QHostAddress clientAddress = QHostAddress(getHostOrderLocalAddress()); + QHostAddress clientAddress = getLocalAddress(); QDateTime now = QDateTime::currentDateTime(); _fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT))); } diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index 8bea122338..b95b6ae735 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -117,7 +117,7 @@ void ScriptsModel::requestRemoteFiles(QString marker) { } url.setQuery(query); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 26505af0be..dbc29be71a 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -26,7 +26,7 @@ AddressBarDialog::AddressBarDialog() : void AddressBarDialog::setupUI() { const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; - const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, @user, #location"; + const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z"; const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;"; const int ADDRESSBAR_MIN_WIDTH = 200; @@ -45,13 +45,6 @@ void AddressBarDialog::setupUI() { const int DIALOG_HEIGHT = 62; const int DIALOG_INITIAL_WIDTH = 560; - setModal(true); -#ifndef Q_OS_MAC - setWindowModality(Qt::ApplicationModal); -#else - setWindowModality(Qt::WindowModal); -#endif - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setSizePolicy(sizePolicy); setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT)); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 916e067ae8..b3d8cb1e53 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -35,9 +35,6 @@ LoginDialog::LoginDialog(QWidget* parent) : _ui->infoLabel->setVisible(false); _ui->errorLabel->setVisible(false); - setModal(true); - setWindowModality(Qt::ApplicationModal); - connect(&AccountManager::getInstance(), &AccountManager::loginComplete, this, &LoginDialog::handleLoginCompleted); connect(&AccountManager::getInstance(), &AccountManager::loginFailed, diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index dffc02ee07..45911d9626 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -48,7 +48,7 @@ enum GridPlane { const glm::vec2 INVALID_VECTOR(FLT_MAX, FLT_MAX); MetavoxelEditor::MetavoxelEditor() : - QWidget(Application::getInstance()->getGLWidget(), Qt::Tool | Qt::WindowStaysOnTopHint) { + QWidget(Application::getInstance()->getGLWidget(), Qt::Tool) { setWindowTitle("Metavoxel Editor"); setAttribute(Qt::WA_DeleteOnClose); diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 0f89c44d23..7a76bc2d7d 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -221,7 +221,7 @@ void ModelHandler::update() { } for (int i = 0; i < _model.rowCount(); ++i) { QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.head(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); @@ -272,7 +272,7 @@ void ModelHandler::queryNewFiles(QString marker) { // Download url.setQuery(query); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp index 1473e4a6a0..b55c753061 100644 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ b/interface/src/ui/ScriptEditorWidget.cpp @@ -150,7 +150,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) { disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); } } else { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << scriptPath; QEventLoop loop; diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index cecec29130..6ff256d48e 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -21,8 +21,15 @@ Circle3DOverlay::Circle3DOverlay() : _startAt(0.0f), _endAt(360.0f), _outerRadius(1.0f), - _innerRadius(0.0f) + _innerRadius(0.0f), + _hasTickMarks(false), + _majorTickMarksAngle(0.0f), + _minorTickMarksAngle(0.0f), + _majorTickMarksLength(0.0f), + _minorTickMarksLength(0.0f) { + _majorTickMarksColor.red = _majorTickMarksColor.green = _majorTickMarksColor.blue = (unsigned char)0; + _minorTickMarksColor.red = _minorTickMarksColor.green = _minorTickMarksColor.blue = (unsigned char)0; } Circle3DOverlay::~Circle3DOverlay() { @@ -142,6 +149,66 @@ void Circle3DOverlay::render() { glVertex2f(lastOuterPoint.x, lastOuterPoint.y); glEnd(); } + + // draw our tick marks + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise + // we just draw a line... + if (getHasTickMarks()) { + glBegin(GL_LINES); + + // draw our major tick marks + if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { + + xColor color = getMajorTickMarksColor(); + glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + float angle = startAt; + float angleInRadians = glm::radians(angle); + float tickMarkLength = getMajorTickMarksLength(); + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; + float endRadius = startRadius + tickMarkLength; + + while (angle <= endAt) { + angleInRadians = glm::radians(angle); + + glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); + glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); + + glVertex2f(thisPointA.x, thisPointA.y); + glVertex2f(thisPointB.x, thisPointB.y); + + angle += getMajorTickMarksAngle(); + } + } + + // draw our minor tick marks + if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { + + xColor color = getMinorTickMarksColor(); + glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + float angle = startAt; + float angleInRadians = glm::radians(angle); + float tickMarkLength = getMinorTickMarksLength(); + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; + float endRadius = startRadius + tickMarkLength; + + while (angle <= endAt) { + angleInRadians = glm::radians(angle); + + glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); + glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); + + glVertex2f(thisPointA.x, thisPointA.y); + glVertex2f(thisPointB.x, thisPointB.y); + + angle += getMinorTickMarksAngle(); + } + } + + glEnd(); + } + glPopMatrix(); glPopMatrix(); @@ -173,6 +240,55 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) { if (innerRadius.isValid()) { setInnerRadius(innerRadius.toVariant().toFloat()); } + + QScriptValue hasTickMarks = properties.property("hasTickMarks"); + if (hasTickMarks.isValid()) { + setHasTickMarks(hasTickMarks.toVariant().toBool()); + } + + QScriptValue majorTickMarksAngle = properties.property("majorTickMarksAngle"); + if (majorTickMarksAngle.isValid()) { + setMajorTickMarksAngle(majorTickMarksAngle.toVariant().toFloat()); + } + + QScriptValue minorTickMarksAngle = properties.property("minorTickMarksAngle"); + if (minorTickMarksAngle.isValid()) { + setMinorTickMarksAngle(minorTickMarksAngle.toVariant().toFloat()); + } + + QScriptValue majorTickMarksLength = properties.property("majorTickMarksLength"); + if (majorTickMarksLength.isValid()) { + setMajorTickMarksLength(majorTickMarksLength.toVariant().toFloat()); + } + + QScriptValue minorTickMarksLength = properties.property("minorTickMarksLength"); + if (minorTickMarksLength.isValid()) { + setMinorTickMarksLength(minorTickMarksLength.toVariant().toFloat()); + } + + QScriptValue majorTickMarksColor = properties.property("majorTickMarksColor"); + if (majorTickMarksColor.isValid()) { + QScriptValue red = majorTickMarksColor.property("red"); + QScriptValue green = majorTickMarksColor.property("green"); + QScriptValue blue = majorTickMarksColor.property("blue"); + if (red.isValid() && green.isValid() && blue.isValid()) { + _majorTickMarksColor.red = red.toVariant().toInt(); + _majorTickMarksColor.green = green.toVariant().toInt(); + _majorTickMarksColor.blue = blue.toVariant().toInt(); + } + } + + QScriptValue minorTickMarksColor = properties.property("minorTickMarksColor"); + if (minorTickMarksColor.isValid()) { + QScriptValue red = minorTickMarksColor.property("red"); + QScriptValue green = minorTickMarksColor.property("green"); + QScriptValue blue = minorTickMarksColor.property("blue"); + if (red.isValid() && green.isValid() && blue.isValid()) { + _minorTickMarksColor.red = red.toVariant().toInt(); + _minorTickMarksColor.green = green.toVariant().toInt(); + _minorTickMarksColor.blue = blue.toVariant().toInt(); + } + } } diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index cea9db0384..791d951105 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -26,17 +26,38 @@ public: float getEndAt() const { return _endAt; } float getOuterRadius() const { return _outerRadius; } float getInnerRadius() const { return _innerRadius; } + bool getHasTickMarks() const { return _hasTickMarks; } + float getMajorTickMarksAngle() const { return _majorTickMarksAngle; } + float getMinorTickMarksAngle() const { return _minorTickMarksAngle; } + float getMajorTickMarksLength() const { return _majorTickMarksLength; } + float getMinorTickMarksLength() const { return _minorTickMarksLength; } + xColor getMajorTickMarksColor() const { return _majorTickMarksColor; } + xColor getMinorTickMarksColor() const { return _minorTickMarksColor; } void setStartAt(float value) { _startAt = value; } void setEndAt(float value) { _endAt = value; } void setOuterRadius(float value) { _outerRadius = value; } void setInnerRadius(float value) { _innerRadius = value; } + void setHasTickMarks(bool value) { _hasTickMarks = value; } + void setMajorTickMarksAngle(float value) { _majorTickMarksAngle = value; } + void setMinorTickMarksAngle(float value) { _minorTickMarksAngle = value; } + void setMajorTickMarksLength(float value) { _majorTickMarksLength = value; } + void setMinorTickMarksLength(float value) { _minorTickMarksLength = value; } + void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; } + void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; } protected: float _startAt; float _endAt; float _outerRadius; float _innerRadius; + bool _hasTickMarks; + float _majorTickMarksAngle; + float _minorTickMarksAngle; + float _majorTickMarksLength; + float _minorTickMarksLength; + xColor _majorTickMarksColor; + xColor _minorTickMarksColor; }; diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 8322b9bea4..2b4e1e2f56 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -37,7 +37,7 @@ ImageOverlay::~ImageOverlay() { // TODO: handle setting image multiple times, how do we manage releasing the bound texture? void ImageOverlay::setImageURL(const QUrl& url) { _isLoaded = false; - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished); } diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 6fa002a664..2266385425 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -78,7 +78,7 @@ Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) : // assume we have a QApplication or QCoreApplication instance and use the // QNetworkAccess manager to grab the raw audio file at the given URL - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); qDebug() << "Requesting audio file" << sampleURL.toDisplayString(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ef7083e3bf..62cde44909 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1048,7 +1048,7 @@ void AvatarData::setBillboardFromURL(const QString &billboardURL) { QNetworkRequest billboardRequest; billboardRequest.setUrl(QUrl(billboardURL)); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* networkReply = networkAccessManager.get(billboardRequest); connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply())); } @@ -1113,7 +1113,7 @@ void AvatarData::updateJointMappings() { _jointNames.clear(); if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL)); connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); } diff --git a/libraries/avatars/src/Recording.cpp b/libraries/avatars/src/Recording.cpp index 7465eb1aac..0d089a2bd2 100644 --- a/libraries/avatars/src/Recording.cpp +++ b/libraries/avatars/src/Recording.cpp @@ -385,7 +385,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { // Download file if necessary qDebug() << "Downloading recording at" << url; - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 7d924d02de..bb471442ea 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -187,7 +187,7 @@ void AccountManager::invokedRequest(const QString& path, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest; @@ -359,7 +359,7 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) void AccountManager::requestAccessToken(const QString& login, const QString& password) { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request; @@ -431,7 +431,7 @@ void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) } void AccountManager::requestProfile() { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QUrl profileURL = _authURL; profileURL.setPath("/api/v1/users/profile"); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 5714e6923d..760c9f4c04 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -90,7 +90,7 @@ void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hos void DomainHandler::setUUID(const QUuid& uuid) { if (uuid != _uuid) { _uuid = uuid; - qDebug() << "Domain uuid changed to" << uuidStringWithoutCurlyBraces(_uuid); + qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid); } } diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index d30f7944d7..97e9721356 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -90,32 +90,29 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) { return dataStream; } -quint32 getHostOrderLocalAddress() { +QHostAddress getLocalAddress() { - static int localAddress = 0; + QHostAddress localAddress; - if (localAddress == 0) { - foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { - if (networkInterface.flags() & QNetworkInterface::IsUp - && networkInterface.flags() & QNetworkInterface::IsRunning - && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { - // we've decided that this is the active NIC - // enumerate it's addresses to grab the IPv4 address - foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { - // make sure it's an IPv4 address that isn't the loopback - if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { - qDebug("Node's local address is %s", entry.ip().toString().toLocal8Bit().constData()); - - // set our localAddress and break out - localAddress = entry.ip().toIPv4Address(); - break; - } + foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { + if (networkInterface.flags() & QNetworkInterface::IsUp + && networkInterface.flags() & QNetworkInterface::IsRunning + && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { + // we've decided that this is the active NIC + // enumerate it's addresses to grab the IPv4 address + foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { + // make sure it's an IPv4 address that isn't the loopback + if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { + + // set our localAddress and break out + localAddress = entry.ip(); + break; } } - - if (localAddress != 0) { - break; - } + } + + if (!localAddress.isNull()) { + break; } } diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index 8a591a60b8..42f815390a 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -58,7 +58,7 @@ private: uint qHash(const HifiSockAddr& key, uint seed); -quint32 getHostOrderLocalAddress(); +QHostAddress getLocalAddress(); Q_DECLARE_METATYPE(HifiSockAddr) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0279c9b697..dd33c96d74 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -70,6 +70,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _nodeHashMutex(QMutex::Recursive), _nodeSocket(this), _dtlsSocket(NULL), + _localSockAddr(), _publicSockAddr(), _numCollectedPackets(0), _numCollectedBytes(0), @@ -89,6 +90,15 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short const int LARGER_BUFFER_SIZE = 1048576; changeSocketBufferSizes(LARGER_BUFFER_SIZE); + // check for local socket updates every so often + const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; + QTimer* localSocketUpdate = new QTimer(this); + connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr); + localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS); + + // check the local socket right now + updateLocalSockAddr(); + _packetStatTimer.start(); } @@ -570,7 +580,7 @@ void LimitedNodeList::sendSTUNRequest() { memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES); // lookup the IP for the STUN server - static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); + HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), stunSockAddr.getAddress(), stunSockAddr.getPort()); @@ -659,6 +669,23 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) { return false; } +void LimitedNodeList::updateLocalSockAddr() { + HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort()); + if (newSockAddr != _localSockAddr) { + + if (_localSockAddr.isNull()) { + qDebug() << "Local socket is" << newSockAddr; + } else { + qDebug() << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr; + } + + + _localSockAddr = newSockAddr; + + emit localSockAddrChanged(_localSockAddr); + } +} + void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, QUuid headerID, const QUuid& connectionRequestID) { @@ -669,7 +696,7 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); - iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); + iceDataStream << _publicSockAddr << _localSockAddr; if (!connectionRequestID.isNull()) { iceDataStream << connectionRequestID; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 406b851d0e..c416773201 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -129,11 +129,15 @@ public slots: void removeSilentNodes(); + void updateLocalSockAddr(); + void killNodeWithUUID(const QUuid& nodeUUID); signals: void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void nodeAdded(SharedNodePointer); void nodeKilled(SharedNodePointer); + + void localSockAddrChanged(const HifiSockAddr& localSockAddr); void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); protected: static std::auto_ptr _sharedInstance; @@ -155,6 +159,7 @@ protected: QMutex _nodeHashMutex; QUdpSocket _nodeSocket; QUdpSocket* _dtlsSocket; + HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; int _numCollectedPackets; int _numCollectedBytes; diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index e92760d303..841b7491c7 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -13,15 +13,12 @@ #include "NetworkAccessManager.h" -QThreadStorage networkAccessManagers; +QThreadStorage networkAccessManagers; -NetworkAccessManager& NetworkAccessManager::getInstance() { +QNetworkAccessManager& NetworkAccessManager::getInstance() { if (!networkAccessManagers.hasLocalData()) { - networkAccessManagers.setLocalData(new NetworkAccessManager()); + networkAccessManagers.setLocalData(new QNetworkAccessManager()); } return *networkAccessManagers.localData(); } - -NetworkAccessManager::NetworkAccessManager() { -} diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index 9594170518..d911d935dc 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -15,13 +15,10 @@ #include /// Wrapper around QNetworkAccessManager to restrict at one instance by thread -class NetworkAccessManager : public QNetworkAccessManager { +class NetworkAccessManager : public QObject { Q_OBJECT public: - static NetworkAccessManager& getInstance(); - -private: - NetworkAccessManager(); + static QNetworkAccessManager& getInstance(); }; #endif // hifi_NetworkAccessManager_h \ No newline at end of file diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 905fc06eeb..25531861ca 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -302,9 +302,7 @@ void NodeList::sendDomainServerCheckIn() { QDataStream packetStream(&domainServerPacket, QIODevice::Append); // pack our data to send to the domain-server - packetStream << _ownerType << _publicSockAddr - << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) - << (quint8) _nodeTypesOfInterest.size(); + packetStream << _ownerType << _publicSockAddr << _localSockAddr << (quint8) _nodeTypesOfInterest.size(); // copy over the bytes for node types of interest, if required foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { @@ -420,13 +418,7 @@ void NodeList::sendAssignment(Assignment& assignment) { packetStream << assignment; - static HifiSockAddr DEFAULT_ASSIGNMENT_SOCKET(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, DEFAULT_DOMAIN_SERVER_PORT); - - const HifiSockAddr* assignmentServerSocket = _assignmentServerSocket.isNull() - ? &DEFAULT_ASSIGNMENT_SOCKET - : &_assignmentServerSocket; - - _nodeSocket.writeDatagram(packet, assignmentServerSocket->getAddress(), assignmentServerSocket->getPort()); + _nodeSocket.writeDatagram(packet, _assignmentServerSocket.getAddress(), _assignmentServerSocket.getPort()); } void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index f45ae19939..51789aec3a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -157,7 +157,7 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, emit errorMessage("ERROR Loading file:" + fileName); } } else { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading script at" << url; QEventLoop loop; @@ -682,7 +682,7 @@ void ScriptEngine::include(const QString& includeFile) { QString includeContents; if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << includeFile; QEventLoop loop;