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 += ""
+
+ // Rows
+ var row_num = 1
+ _.each(setting_value, function(row, name) {
+ html += ""
+ if (setting.numbered === true) {
+ html += "" + row_num + " | "
+ }
+ html += "" + name + " | "
+ _.each(setting.columns, function(col) {
+ html += ""
+ if (row.hasOwnProperty(col.name)) {
+ html += row[col.name]
+ }
+ 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 += "
"
+
+ 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;