Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels

This commit is contained in:
Andrzej Kapolka 2014-10-08 11:51:10 -07:00
commit 049a00b85b
41 changed files with 4230 additions and 156 deletions

View file

@ -1,4 +1,4 @@
The project embraces distributed development and if you'd like to help, we'll pay you -- find out more at Worklist.net. If you find a small bug and have a fix, pull requests are welcome. If you'd like to get paid for your work, make sure you report the bug via a job on Worklist.net. The project embraces distributed development and if you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net). If you find a small bug and have a fix, pull requests are welcome. If you'd like to get paid for your work, make sure you report the bug via a job on Worklist.net.
We're hiring! We're looking for skilled developers; send your resume to hiring@highfidelity.io We're hiring! We're looking for skilled developers; send your resume to hiring@highfidelity.io
@ -16,7 +16,7 @@ Contributing
git checkout -b new_branch_name git checkout -b new_branch_name
``` ```
4. Code 4. Code
* Follow the [coding standard](https://github.com/highfidelity/hifi/wiki/Coding-Standard) * Follow the [coding standard](http://docs.highfidelity.io/v1.0/docs/coding-standard)
5. Commit 5. Commit
* Use [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) * Use [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
6. Update your branch 6. Update your branch
@ -38,11 +38,11 @@ Contributing
Reporting Bugs Reporting Bugs
=== ===
1. Always update to the latest code on master, it is possible the bug has already been fixed! 1. Always update to the latest code on master, we make many merges every day and it is possible the bug has already been fixed!
2. Search the [repository issues](https://github.com/highfidelity/hifi/issues) to make sure that somebody has not already reported the same bug. 2. Search jobs [on Worklist](https://worklist.net) to make sure that somebody has not already reported the same bug.
3. Open an [issue on GitHub](https://github.com/highfidelity/hifi/issues) including information about your system and how to reproduce the bug. 3. Add a [job on Worklist](https://worklist.net/job/add) including information about your system and how to reproduce the bug.
Requesting a feature Requesting a feature
=== ===
1. Search the [repository issues](https://github.com/highfidelity/hifi/issues) to make sure that somebody has not already requested the same feature. If you find a matching request, feel free to add any additional comments to the existing issue. 1. Search the [the Worklist](https://worklist.net) to make sure that somebody has not already requested the same feature. If you find a matching request, feel free to add any additional comments to the existing issue.
2. Submit an [issue on GitHub](https://github.com/highfidelity/hifi/issues) that is tagged as a feature. 2. Add a [job on Worklist](https://worklist.net/job/add) that is labeled as a Feature (and select any other appropriate Labels) and includes a detailed description of your request.

View file

@ -3,10 +3,10 @@ lab experimenting with Virtual Worlds and VR.
In this repository you'll find the source to many of the components in our In this repository you'll find the source to many of the components in our
alpha-stage virtual world. The project embraces distributed development alpha-stage virtual world. The project embraces distributed development
and if you'd like to help, we'll pay you -- find out more at Worklist.net. and if you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net).
If you find a small bug and have a fix, pull requests are welcome. If you'd If you find a small bug and have a fix, pull requests are welcome. If you'd
like to get paid for your work, make sure you report the bug via a job on like to get paid for your work, make sure you report the bug via a job on
Worklist.net. [Worklist.net](https://worklist.net).
We're hiring! We're looking for skilled developers; We're hiring! We're looking for skilled developers;
send your resume to hiring@highfidelity.io send your resume to hiring@highfidelity.io
@ -14,6 +14,10 @@ send your resume to hiring@highfidelity.io
##### Chat with us ##### Chat with us
Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi! Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi!
Documentation
=========
Documentation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project).
Build Instructions Build Instructions
========= =========
All information required to build is found in the [build guide](BUILD.md). All information required to build is found in the [build guide](BUILD.md).

View file

@ -206,7 +206,7 @@ void Agent::run() {
scriptURL = QUrl(_payload); scriptURL = QUrl(_payload);
} }
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL)); QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL));
QNetworkDiskCache* cache = new QNetworkDiskCache(); QNetworkDiskCache* cache = new QNetworkDiskCache();

View file

@ -59,6 +59,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_POOL_OPTION = "pool";
const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet";
const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a";
const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p";
Assignment::Type requestAssignmentType = Assignment::AllTypes; Assignment::Type requestAssignmentType = Assignment::AllTypes;
@ -87,17 +88,29 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) :
// create a NodeList as an unassigned client // create a NodeList as an unassigned client
NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned); 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 // check for an overriden assignment server hostname
if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) { if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) {
_assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); _assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString();
// set the custom assignment socket on our NodeList // change the hostname for our assignment server
HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerSocket.getPort());
nodeList->setAssignmentServerSocket(customAssignmentSocket);
} }
nodeList->setAssignmentServerSocket(assignmentServerSocket);
qDebug() << "Assignment server socket is" << assignmentServerSocket;
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
qDebug() << "Waiting for assignment -" << _requestAssignment; qDebug() << "Waiting for assignment -" << _requestAssignment;

View file

@ -364,7 +364,6 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l
const float ZERO_DB = 1.0f; const float ZERO_DB = 1.0f;
const float NEGATIVE_ONE_DB = 0.891f; const float NEGATIVE_ONE_DB = 0.891f;
const float NEGATIVE_THREE_DB = 0.708f; const float NEGATIVE_THREE_DB = 0.708f;
const float NEGATIVE_SIX_DB = 0.501f;
const float FILTER_GAIN_AT_0 = ZERO_DB; // source is in front const float FILTER_GAIN_AT_0 = ZERO_DB; // source is in front
const float FILTER_GAIN_AT_90 = NEGATIVE_ONE_DB; // source is incident to left or right ear const float FILTER_GAIN_AT_90 = NEGATIVE_ONE_DB; // source is incident to left or right ear

View file

@ -940,7 +940,7 @@ void OctreeServer::run() {
qDebug("--statusHost=%s", statusHost); qDebug("--statusHost=%s", statusHost);
_statusHost = statusHost; _statusHost = statusHost;
} else { } else {
_statusHost = QHostAddress(getHostOrderLocalAddress()).toString(); _statusHost = getLocalAddress().toString();
} }
qDebug("statusHost=%s", qPrintable(_statusHost)); qDebug("statusHost=%s", qPrintable(_statusHost));

View file

@ -33,6 +33,14 @@
"label": "None: use the network information I have entered for this domain at data.highfidelity.io" "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.<br/>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
} }
] ]
}, },

View file

@ -46,6 +46,11 @@ var viewHelpers = {
form_group += "<input type='hidden' name='" + setting_name + "' value='" + setting_value + "'>" form_group += "<input type='hidden' name='" + setting_name + "' value='" + setting_value + "'>"
} else { } else {
if (input_type == 'integer') {
input_type = "text"
}
form_group += "<input type='" + input_type + "' class='form-control' name='" + setting_name + form_group += "<input type='" + input_type + "' class='form-control' name='" + setting_name +
"' placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") + "' placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
"' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>" "' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>"
@ -292,7 +297,7 @@ function chooseFromHighFidelityDomains(clickedButton) {
modal_buttons["success"] = { modal_buttons["success"] = {
label: 'Create new domain', label: 'Create new domain',
callback: function() { callback: function() {
window.open("https://data.highfidelity.io/domains", '_blank'); window.open("https://data.highfidelity.io/user/domains", '_blank');
} }
} }
modal_body = "<p>You do not have any domains in your High Fidelity account." + modal_body = "<p>You do not have any domains in your High Fidelity account." +

View file

@ -57,6 +57,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
setApplicationName("domain-server"); setApplicationName("domain-server");
QSettings::setDefaultFormat(QSettings::IniFormat); 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()); _settingsManager.setupConfigMap(arguments());
installNativeEventFilter(&_shutdownEventListener); installNativeEventFilter(&_shutdownEventListener);
@ -82,10 +86,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
void DomainServer::restart() { void DomainServer::restart() {
qDebug() << "domain-server is restarting."; qDebug() << "domain-server is restarting.";
// make sure all static instances are reset
LimitedNodeList::getInstance()->reset();
AccountManager::getInstance(true);
exit(DomainServer::EXIT_CODE_REBOOT); exit(DomainServer::EXIT_CODE_REBOOT);
} }
@ -189,17 +189,20 @@ bool DomainServer::optionallySetupOAuth() {
const QString DOMAIN_CONFIG_ID_KEY = "id"; 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) { void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
const QString CUSTOM_PORT_OPTION = "port"; const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
unsigned short domainServerPort = DEFAULT_DOMAIN_SERVER_PORT;
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
unsigned short domainServerPort = (unsigned short) localPortValue.toUInt();
QVariantMap& settingsMap = _settingsManager.getSettingsMap(); QVariantMap& settingsMap = _settingsManager.getSettingsMap();
if (settingsMap.contains(CUSTOM_PORT_OPTION)) {
domainServerPort = (unsigned short) settingsMap.value(CUSTOM_PORT_OPTION).toUInt();
}
unsigned short domainServerDTLSPort = 0; unsigned short domainServerDTLSPort = 0;
if (_isUsingDTLS) { if (_isUsingDTLS) {
@ -310,12 +313,7 @@ bool DomainServer::optionallySetupAssignmentPayment() {
return true; 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() { void DomainServer::setupAutomaticNetworking() {
const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking";
if (!didSetupAccountManagerWithAccessToken()) { if (!didSetupAccountManagerWithAccessToken()) {
qDebug() << "Cannot setup domain-server automatic networking without an access token."; 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); connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates);
iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); 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); connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer);
// tell the data server which type of automatic networking we are using // tell the data server which type of automatic networking we are using

View file

@ -254,11 +254,14 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
QString settingType = groupObject[SETTING_DESCRIPTION_TYPE_KEY].toString(); QString settingType = groupObject[SETTING_DESCRIPTION_TYPE_KEY].toString();
const QString INPUT_DOUBLE_TYPE = "double"; const QString INPUT_DOUBLE_TYPE = "double";
const QString INPUT_INTEGER_TYPE = "int";
// make sure the resulting json value has the right type // make sure the resulting json value has the right type
if (settingType == INPUT_DOUBLE_TYPE) { if (settingType == INPUT_DOUBLE_TYPE) {
settingsVariant[key] = rootValue.toString().toDouble(); settingsVariant[key] = rootValue.toString().toDouble();
} else if (settingType == INPUT_INTEGER_TYPE) {
settingsVariant[key] = rootValue.toString().toInt();
} else { } else {
settingsVariant[key] = rootValue.toString(); settingsVariant[key] = rootValue.toString();
} }

View file

@ -1215,19 +1215,44 @@ var toolBar = (function () {
Overlays.editOverlay(loadFileMenuItem, { visible: active }); Overlays.editOverlay(loadFileMenuItem, { visible: active });
} }
var RESIZE_INTERVAL = 50;
var RESIZE_TIMEOUT = 20000;
var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL;
function addModel(url) { function addModel(url) {
var position; var position;
position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE));
if (position.x > 0 && position.y > 0 && position.z > 0) { if (position.x > 0 && position.y > 0 && position.z > 0) {
Entities.addEntity({ var entityId = Entities.addEntity({
type: "Model", type: "Model",
position: position, position: position,
dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION },
modelURL: url modelURL: url
}); });
print("Model added: " + url); print("Model added: " + url);
var checkCount = 0;
function resize() {
var entityProperties = Entities.getEntityProperties(entityId);
var naturalDimensions = entityProperties.naturalDimensions;
checkCount++;
if (naturalDimensions.x == 0 && naturalDimensions.y == 0 && naturalDimensions.z == 0) {
if (checkCount < RESIZE_MAX_CHECKS) {
Script.setTimeout(resize, RESIZE_INTERVAL);
} else {
print("Resize failed: timed out waiting for model (" + url + ") to load");
}
} else {
entityProperties.dimensions = naturalDimensions;
Entities.editEntity(entityId, entityProperties);
}
}
Script.setTimeout(resize, RESIZE_INTERVAL);
} else { } else {
print("Can't add model: Model would be out of bounds."); print("Can't add model: Model would be out of bounds.");
} }

View file

@ -30,8 +30,6 @@ var leapHands = (function () {
CALIBRATING = 1, CALIBRATING = 1,
CALIBRATED = 2, CALIBRATED = 2,
CALIBRATION_TIME = 1000, // milliseconds CALIBRATION_TIME = 1000, // milliseconds
PI = 3.141593,
isWindows,
avatarScale, avatarScale,
avatarFaceModelURL, avatarFaceModelURL,
avatarSkeletonModelURL, avatarSkeletonModelURL,
@ -132,9 +130,6 @@ var leapHands = (function () {
if (hands[0].controller.isActive() && hands[1].controller.isActive()) { if (hands[0].controller.isActive() && hands[1].controller.isActive()) {
leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; 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 { } else {
calibrationStatus = UNCALIBRATED; calibrationStatus = UNCALIBRATED;
return; return;
@ -318,11 +313,7 @@ var leapHands = (function () {
j, j,
side, side,
handOffset, handOffset,
handRoll,
handPitch,
handYaw,
handRotation, handRotation,
wristAbsRotation,
locRotation, locRotation,
cameraOrientation, cameraOrientation,
inverseAvatarOrientation; inverseAvatarOrientation;
@ -361,20 +352,22 @@ var leapHands = (function () {
handOffset.x = -handOffset.x; handOffset.x = -handOffset.x;
// Hand rotation in camera coordinates ... // Hand rotation in camera coordinates ...
// TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. handRotation = wrists[h].controller.getAbsRotation();
handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; handRotation = {
wristAbsRotation = wrists[h].controller.getAbsRotation(); x: handRotation.z,
handPitch = 2.0 * wristAbsRotation.x - PI / 2.0; y: handRotation.y,
handYaw = 2.0 * -wristAbsRotation.y; z: handRotation.x,
// TODO: Roll values only work if hand is upside down; Leap Motion controller code needs investigating. w: handRotation.w
handRoll = PI + handRoll; };
if (h === 0) { if (h === 0) {
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), handRotation.x = -handRotation.x;
Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); 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 { } else {
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), handRotation.z = -handRotation.z;
Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); 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 ... // Hand rotation in avatar coordinates ...
@ -392,25 +385,22 @@ var leapHands = (function () {
z: hands[h].zeroPosition.z - handOffset.z z: hands[h].zeroPosition.z - handOffset.z
}; };
// TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. handRotation = wrists[h].controller.getAbsRotation();
handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; handRotation = {
wristAbsRotation = wrists[h].controller.getAbsRotation(); x: handRotation.z,
handPitch = 2.0 * -wristAbsRotation.x; y: handRotation.y,
handYaw = 2.0 * wristAbsRotation.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) { if (h === 0) {
handRotation.x = -handRotation.x;
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }),
Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); handRotation);
} else { } else {
handRotation.z = -handRotation.z;
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }),
Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); handRotation);
} }
} }

View file

@ -169,7 +169,14 @@ SelectionDisplay = (function () {
alpha: 0.2, alpha: 0.2,
solid: true, solid: true,
visible: false, 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", { var rotateOverlayOuter = Overlays.addOverlay("circle3d", {
@ -179,7 +186,15 @@ SelectionDisplay = (function () {
alpha: 0.2, alpha: 0.2,
solid: true, solid: true,
visible: false, 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", { var rotateOverlayCurrent = Overlays.addOverlay("circle3d", {
@ -571,7 +586,7 @@ SelectionDisplay = (function () {
innerRadius: 0.9, innerRadius: 0.9,
startAt: 0, startAt: 0,
endAt: 360, endAt: 360,
alpha: outerAlpha alpha: outerAlpha,
}); });
Overlays.editOverlay(rotateOverlayCurrent, Overlays.editOverlay(rotateOverlayCurrent,
@ -584,7 +599,7 @@ SelectionDisplay = (function () {
size: outerRadius, size: outerRadius,
startAt: 0, startAt: 0,
endAt: 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 // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden

View file

@ -8,4 +8,4 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
var HIFI_PUBLIC_BUCKET = "https://s3.amazonaws.com/hifi-public/"; HIFI_PUBLIC_BUCKET = "https://s3.amazonaws.com/hifi-public/";

View file

@ -64,8 +64,8 @@ var text = Overlays.addOverlay("text", {
y: 100, y: 100,
width: 150, width: 150,
height: 50, height: 50,
color: { red: 0, green: 0, blue: 0}, backgroundColor: { red: 255, green: 255, blue: 255},
textColor: { red: 255, green: 0, blue: 0}, color: { red: 255, green: 0, blue: 0},
topMargin: 4, topMargin: 4,
leftMargin: 4, leftMargin: 4,
text: "Here is some text.\nAnd a second line." text: "Here is some text.\nAnd a second line."

3851
examples/walk.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -350,7 +350,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkDiskCache* cache = new QNetworkDiskCache(); QNetworkDiskCache* cache = new QNetworkDiskCache();
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
networkAccessManager.setCache(cache); networkAccessManager.setCache(cache);

View file

@ -28,7 +28,7 @@ FileLogger::FileLogger(QObject* parent) :
setExtraDebugging(false); setExtraDebugging(false);
_fileName = FileUtils::standardPath(LOGS_DIRECTORY); _fileName = FileUtils::standardPath(LOGS_DIRECTORY);
QHostAddress clientAddress = QHostAddress(getHostOrderLocalAddress()); QHostAddress clientAddress = getLocalAddress();
QDateTime now = QDateTime::currentDateTime(); QDateTime now = QDateTime::currentDateTime();
_fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT))); _fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT)));
} }

View file

@ -1238,7 +1238,7 @@ void Menu::toggleLocationList() {
if (!_userLocationsDialog) { if (!_userLocationsDialog) {
JavascriptObjectMap locationObjectMap; JavascriptObjectMap locationObjectMap;
locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance()); locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance());
_userLocationsDialog = DataWebDialog::dialogForPath("/locations", locationObjectMap); _userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap);
} }
if (!_userLocationsDialog->isVisible()) { if (!_userLocationsDialog->isVisible()) {
@ -1282,7 +1282,7 @@ void Menu::nameLocation() {
if (!_newLocationDialog) { if (!_newLocationDialog) {
JavascriptObjectMap locationObjectMap; JavascriptObjectMap locationObjectMap;
locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance()); locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance());
_newLocationDialog = DataWebDialog::dialogForPath("/locations/new", locationObjectMap); _newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap);
} }
if (!_newLocationDialog->isVisible()) { if (!_newLocationDialog->isVisible()) {

View file

@ -117,7 +117,7 @@ void ScriptsModel::requestRemoteFiles(QString marker) {
} }
url.setQuery(query); url.setQuery(query);
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.get(request); QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));

View file

@ -49,8 +49,8 @@ const float PITCH_SPEED = 100.0f; // degrees/sec
const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions
const float COLLISION_RADIUS_SCALE = 0.125f; const float COLLISION_RADIUS_SCALE = 0.125f;
const float MIN_KEYBOARD_CONTROL_SPEED = 1.5f; const float MIN_KEYBOARD_CONTROL_SPEED = 0.50f;
const float MAX_WALKING_SPEED = 3.0f * MIN_KEYBOARD_CONTROL_SPEED; const float MAX_WALKING_SPEED = 4.5f;
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic // TODO: normalize avatar speed for standard avatar size, then scale all motion logic
// to properly follow avatar size. // to properly follow avatar size.
@ -1262,21 +1262,19 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe
// Compute the target keyboard velocity (which ramps up slowly, and damps very quickly) // Compute the target keyboard velocity (which ramps up slowly, and damps very quickly)
// the max magnitude of which depends on what we're doing: // the max magnitude of which depends on what we're doing:
float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED;
float motorLength = glm::length(_keyboardMotorVelocity); float motorLength = glm::length(_keyboardMotorVelocity);
float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED;
float speedGrowthTimescale = 2.0f;
float speedIncreaseFactor = 1.8f;
motorLength *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor;
if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) { if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) {
// an active keyboard motor should never be slower than this // an active keyboard motor should never be slower than this
_keyboardMotorVelocity = _scale * MIN_KEYBOARD_CONTROL_SPEED * direction; motorLength = _scale * MIN_KEYBOARD_CONTROL_SPEED;
motorEfficiency = 1.0f; motorEfficiency = 1.0f;
} else { } else if (motorLength > finalMaxMotorSpeed) {
float KEYBOARD_MOTOR_LENGTH_TIMESCALE = 2.0f; motorLength = finalMaxMotorSpeed;
float INCREASE_FACTOR = 1.8f;
motorLength *= 1.0f + glm::clamp(deltaTime / KEYBOARD_MOTOR_LENGTH_TIMESCALE, 0.0f, 1.0f) * INCREASE_FACTOR;
if (motorLength > finalMaxMotorSpeed) {
motorLength = finalMaxMotorSpeed;
}
_keyboardMotorVelocity = motorLength * direction;
} }
_keyboardMotorVelocity = motorLength * direction;
_isPushing = true; _isPushing = true;
} }
} else { } else {

View file

@ -26,7 +26,7 @@ AddressBarDialog::AddressBarDialog() :
void AddressBarDialog::setupUI() { void AddressBarDialog::setupUI() {
const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; 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 QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;";
const int ADDRESSBAR_MIN_WIDTH = 200; const int ADDRESSBAR_MIN_WIDTH = 200;

View file

@ -26,7 +26,7 @@
const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "attachments" }; const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "attachments" };
static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com"; static const QString S3_URL = "https://s3.amazonaws.com/hifi-public";
static const QString PUBLIC_URL = "http://public.highfidelity.io"; static const QString PUBLIC_URL = "http://public.highfidelity.io";
static const QString MODELS_LOCATION = "models/"; static const QString MODELS_LOCATION = "models/";
@ -221,7 +221,7 @@ void ModelHandler::update() {
} }
for (int i = 0; i < _model.rowCount(); ++i) { for (int i = 0; i < _model.rowCount(); ++i) {
QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); QUrl url(_model.item(i,0)->data(Qt::UserRole).toString());
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.head(request); QNetworkReply* reply = networkAccessManager.head(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));
@ -272,7 +272,7 @@ void ModelHandler::queryNewFiles(QString marker) {
// Download // Download
url.setQuery(query); url.setQuery(query);
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = networkAccessManager.get(request); QNetworkReply* reply = networkAccessManager.get(request);
connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); connect(reply, SIGNAL(finished()), SLOT(downloadFinished()));

View file

@ -150,7 +150,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished);
} }
} else { } else {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading included script at" << scriptPath; qDebug() << "Downloading included script at" << scriptPath;
QEventLoop loop; QEventLoop loop;

View file

@ -21,8 +21,15 @@ Circle3DOverlay::Circle3DOverlay() :
_startAt(0.0f), _startAt(0.0f),
_endAt(360.0f), _endAt(360.0f),
_outerRadius(1.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() { Circle3DOverlay::~Circle3DOverlay() {
@ -142,6 +149,66 @@ void Circle3DOverlay::render() {
glVertex2f(lastOuterPoint.x, lastOuterPoint.y); glVertex2f(lastOuterPoint.x, lastOuterPoint.y);
glEnd(); 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();
glPopMatrix(); glPopMatrix();
@ -173,6 +240,55 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) {
if (innerRadius.isValid()) { if (innerRadius.isValid()) {
setInnerRadius(innerRadius.toVariant().toFloat()); 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();
}
}
} }

View file

@ -26,17 +26,38 @@ public:
float getEndAt() const { return _endAt; } float getEndAt() const { return _endAt; }
float getOuterRadius() const { return _outerRadius; } float getOuterRadius() const { return _outerRadius; }
float getInnerRadius() const { return _innerRadius; } 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 setStartAt(float value) { _startAt = value; }
void setEndAt(float value) { _endAt = value; } void setEndAt(float value) { _endAt = value; }
void setOuterRadius(float value) { _outerRadius = value; } void setOuterRadius(float value) { _outerRadius = value; }
void setInnerRadius(float value) { _innerRadius = 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: protected:
float _startAt; float _startAt;
float _endAt; float _endAt;
float _outerRadius; float _outerRadius;
float _innerRadius; float _innerRadius;
bool _hasTickMarks;
float _majorTickMarksAngle;
float _minorTickMarksAngle;
float _majorTickMarksLength;
float _minorTickMarksLength;
xColor _majorTickMarksColor;
xColor _minorTickMarksColor;
}; };

View file

@ -37,7 +37,7 @@ ImageOverlay::~ImageOverlay() {
// TODO: handle setting image multiple times, how do we manage releasing the bound texture? // TODO: handle setting image multiple times, how do we manage releasing the bound texture?
void ImageOverlay::setImageURL(const QUrl& url) { void ImageOverlay::setImageURL(const QUrl& url) {
_isLoaded = false; _isLoaded = false;
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished); connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished);
} }

View file

@ -78,7 +78,7 @@ Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) :
// assume we have a QApplication or QCoreApplication instance and use the // assume we have a QApplication or QCoreApplication instance and use the
// QNetworkAccess manager to grab the raw audio file at the given URL // 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(); qDebug() << "Requesting audio file" << sampleURL.toDisplayString();

View file

@ -1048,7 +1048,7 @@ void AvatarData::setBillboardFromURL(const QString &billboardURL) {
QNetworkRequest billboardRequest; QNetworkRequest billboardRequest;
billboardRequest.setUrl(QUrl(billboardURL)); billboardRequest.setUrl(QUrl(billboardURL));
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* networkReply = networkAccessManager.get(billboardRequest); QNetworkReply* networkReply = networkAccessManager.get(billboardRequest);
connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply())); connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply()));
} }
@ -1113,7 +1113,7 @@ void AvatarData::updateJointMappings() {
_jointNames.clear(); _jointNames.clear();
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL)); QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL));
connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply()));
} }

View file

@ -385,7 +385,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") {
// Download file if necessary // Download file if necessary
qDebug() << "Downloading recording at" << url; qDebug() << "Downloading recording at" << url;
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
QEventLoop loop; QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));

View file

@ -187,7 +187,7 @@ void AccountManager::invokedRequest(const QString& path,
const JSONCallbackParameters& callbackParams, const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest; QNetworkRequest networkRequest;
@ -359,7 +359,7 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken)
void AccountManager::requestAccessToken(const QString& login, const QString& password) { void AccountManager::requestAccessToken(const QString& login, const QString& password) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request; QNetworkRequest request;
@ -431,7 +431,7 @@ void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error)
} }
void AccountManager::requestProfile() { void AccountManager::requestProfile() {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QUrl profileURL = _authURL; QUrl profileURL = _authURL;
profileURL.setPath("/api/v1/users/profile"); profileURL.setPath("/api/v1/users/profile");

View file

@ -90,7 +90,7 @@ void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hos
void DomainHandler::setUUID(const QUuid& uuid) { void DomainHandler::setUUID(const QUuid& uuid) {
if (uuid != _uuid) { if (uuid != _uuid) {
_uuid = uuid; _uuid = uuid;
qDebug() << "Domain uuid changed to" << uuidStringWithoutCurlyBraces(_uuid); qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid);
} }
} }

View file

@ -90,32 +90,29 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) {
return dataStream; return dataStream;
} }
quint32 getHostOrderLocalAddress() { QHostAddress getLocalAddress() {
static int localAddress = 0; QHostAddress localAddress;
if (localAddress == 0) { foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) {
foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { if (networkInterface.flags() & QNetworkInterface::IsUp
if (networkInterface.flags() & QNetworkInterface::IsUp && networkInterface.flags() & QNetworkInterface::IsRunning
&& networkInterface.flags() & QNetworkInterface::IsRunning && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) {
&& networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { // we've decided that this is the active NIC
// we've decided that this is the active NIC // enumerate it's addresses to grab the IPv4 address
// enumerate it's addresses to grab the IPv4 address foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) {
foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { // make sure it's an IPv4 address that isn't the loopback
// make sure it's an IPv4 address that isn't the loopback if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
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();
// set our localAddress and break out break;
localAddress = entry.ip().toIPv4Address();
break;
}
} }
} }
}
if (localAddress != 0) {
break; if (!localAddress.isNull()) {
} break;
} }
} }

View file

@ -58,7 +58,7 @@ private:
uint qHash(const HifiSockAddr& key, uint seed); uint qHash(const HifiSockAddr& key, uint seed);
quint32 getHostOrderLocalAddress(); QHostAddress getLocalAddress();
Q_DECLARE_METATYPE(HifiSockAddr) Q_DECLARE_METATYPE(HifiSockAddr)

View file

@ -70,6 +70,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
_nodeHashMutex(QMutex::Recursive), _nodeHashMutex(QMutex::Recursive),
_nodeSocket(this), _nodeSocket(this),
_dtlsSocket(NULL), _dtlsSocket(NULL),
_localSockAddr(),
_publicSockAddr(), _publicSockAddr(),
_numCollectedPackets(0), _numCollectedPackets(0),
_numCollectedBytes(0), _numCollectedBytes(0),
@ -89,6 +90,15 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
const int LARGER_BUFFER_SIZE = 1048576; const int LARGER_BUFFER_SIZE = 1048576;
changeSocketBufferSizes(LARGER_BUFFER_SIZE); 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(); _packetStatTimer.start();
} }
@ -570,12 +580,19 @@ void LimitedNodeList::sendSTUNRequest() {
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES); memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
// lookup the IP for the STUN server // 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), _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
stunSockAddr.getAddress(), stunSockAddr.getPort()); stunSockAddr.getAddress(), stunSockAddr.getPort());
} }
void LimitedNodeList::rebindNodeSocket() {
quint16 oldPort = _nodeSocket.localPort();
_nodeSocket.close();
_nodeSocket.bind(QHostAddress::AnyIPv4, oldPort);
}
bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) { bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
// check the cookie to make sure this is actually a STUN response // check the cookie to make sure this is actually a STUN response
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS // and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
@ -652,6 +669,23 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
return false; 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, void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
QUuid headerID, const QUuid& connectionRequestID) { QUuid headerID, const QUuid& connectionRequestID) {
@ -662,7 +696,7 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock
QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID);
QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append);
iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); iceDataStream << _publicSockAddr << _localSockAddr;
if (!connectionRequestID.isNull()) { if (!connectionRequestID.isNull()) {
iceDataStream << connectionRequestID; iceDataStream << connectionRequestID;

View file

@ -69,6 +69,8 @@ public:
const QUuid& getSessionUUID() const { return _sessionUUID; } const QUuid& getSessionUUID() const { return _sessionUUID; }
void setSessionUUID(const QUuid& sessionUUID); void setSessionUUID(const QUuid& sessionUUID);
void rebindNodeSocket();
QUdpSocket& getNodeSocket() { return _nodeSocket; } QUdpSocket& getNodeSocket() { return _nodeSocket; }
QUdpSocket& getDTLSSocket(); QUdpSocket& getDTLSSocket();
@ -127,11 +129,15 @@ public slots:
void removeSilentNodes(); void removeSilentNodes();
void updateLocalSockAddr();
void killNodeWithUUID(const QUuid& nodeUUID); void killNodeWithUUID(const QUuid& nodeUUID);
signals: signals:
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
void nodeAdded(SharedNodePointer); void nodeAdded(SharedNodePointer);
void nodeKilled(SharedNodePointer); void nodeKilled(SharedNodePointer);
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
protected: protected:
static std::auto_ptr<LimitedNodeList> _sharedInstance; static std::auto_ptr<LimitedNodeList> _sharedInstance;
@ -153,6 +159,7 @@ protected:
QMutex _nodeHashMutex; QMutex _nodeHashMutex;
QUdpSocket _nodeSocket; QUdpSocket _nodeSocket;
QUdpSocket* _dtlsSocket; QUdpSocket* _dtlsSocket;
HifiSockAddr _localSockAddr;
HifiSockAddr _publicSockAddr; HifiSockAddr _publicSockAddr;
int _numCollectedPackets; int _numCollectedPackets;
int _numCollectedBytes; int _numCollectedBytes;

View file

@ -13,15 +13,12 @@
#include "NetworkAccessManager.h" #include "NetworkAccessManager.h"
QThreadStorage<NetworkAccessManager*> networkAccessManagers; QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
NetworkAccessManager& NetworkAccessManager::getInstance() { QNetworkAccessManager& NetworkAccessManager::getInstance() {
if (!networkAccessManagers.hasLocalData()) { if (!networkAccessManagers.hasLocalData()) {
networkAccessManagers.setLocalData(new NetworkAccessManager()); networkAccessManagers.setLocalData(new QNetworkAccessManager());
} }
return *networkAccessManagers.localData(); return *networkAccessManagers.localData();
} }
NetworkAccessManager::NetworkAccessManager() {
}

View file

@ -15,13 +15,10 @@
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
/// Wrapper around QNetworkAccessManager to restrict at one instance by thread /// Wrapper around QNetworkAccessManager to restrict at one instance by thread
class NetworkAccessManager : public QNetworkAccessManager { class NetworkAccessManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static NetworkAccessManager& getInstance(); static QNetworkAccessManager& getInstance();
private:
NetworkAccessManager();
}; };
#endif // hifi_NetworkAccessManager_h #endif // hifi_NetworkAccessManager_h

View file

@ -302,9 +302,7 @@ void NodeList::sendDomainServerCheckIn() {
QDataStream packetStream(&domainServerPacket, QIODevice::Append); QDataStream packetStream(&domainServerPacket, QIODevice::Append);
// pack our data to send to the domain-server // pack our data to send to the domain-server
packetStream << _ownerType << _publicSockAddr packetStream << _ownerType << _publicSockAddr << _localSockAddr << (quint8) _nodeTypesOfInterest.size();
<< HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort())
<< (quint8) _nodeTypesOfInterest.size();
// copy over the bytes for node types of interest, if required // copy over the bytes for node types of interest, if required
foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) {
@ -420,13 +418,7 @@ void NodeList::sendAssignment(Assignment& assignment) {
packetStream << assignment; packetStream << assignment;
static HifiSockAddr DEFAULT_ASSIGNMENT_SOCKET(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, DEFAULT_DOMAIN_SERVER_PORT); _nodeSocket.writeDatagram(packet, _assignmentServerSocket.getAddress(), _assignmentServerSocket.getPort());
const HifiSockAddr* assignmentServerSocket = _assignmentServerSocket.isNull()
? &DEFAULT_ASSIGNMENT_SOCKET
: &_assignmentServerSocket;
_nodeSocket.writeDatagram(packet, assignmentServerSocket->getAddress(), assignmentServerSocket->getPort());
} }
void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) {

View file

@ -59,6 +59,9 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();
nodeList->setOwnerType(nodeType); nodeList->setOwnerType(nodeType);
// this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread
nodeList->rebindNodeSocket();
QTimer* domainServerTimer = new QTimer(this); QTimer* domainServerTimer = new QTimer(this);
connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);

View file

@ -157,7 +157,7 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL,
emit errorMessage("ERROR Loading file:" + fileName); emit errorMessage("ERROR Loading file:" + fileName);
} }
} else { } else {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading script at" << url; qDebug() << "Downloading script at" << url;
QEventLoop loop; QEventLoop loop;
@ -681,8 +681,8 @@ void ScriptEngine::include(const QString& includeFile) {
QUrl url = resolveInclude(includeFile); QUrl url = resolveInclude(includeFile);
QString includeContents; QString includeContents;
if (url.scheme() == "http" || url.scheme() == "ftp") { if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
qDebug() << "Downloading included script at" << includeFile; qDebug() << "Downloading included script at" << includeFile;
QEventLoop loop; QEventLoop loop;