From 9112efaa36e7577641039c96295a8702deceb4ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 13:00:05 -0700 Subject: [PATCH 01/11] move username change to Login, add lastPosition and lastDomain --- interface/src/Application.cpp | 7 ++++ interface/src/Application.h | 4 ++- interface/src/Menu.cpp | 56 +++++++++++++++++++++++--------- interface/src/Menu.h | 2 ++ interface/src/avatar/Profile.cpp | 44 +++++++++++++++---------- interface/src/avatar/Profile.h | 20 ++++++++---- 6 files changed, 93 insertions(+), 40 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0d2566ca64..8d38343e3d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -102,6 +102,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _voxelImporter(_window), _wantToKillLocalVoxels(false), _audioScope(256, 200, true), + _profile(QString()), _mouseX(0), _mouseY(0), _touchAvgX(0.0f), @@ -456,6 +457,12 @@ void Application::updateProjectionMatrix() { glMatrixMode(GL_MODELVIEW); } +void Application::resetProfile(const QString& username) { + // call the destructor on the old profile and construct a new one + (&_profile)->~Profile(); + new (&_profile) Profile(username); +} + void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) { Application* self = getInstance(); diff --git a/interface/src/Application.h b/interface/src/Application.h index a4994d7f6c..6d3c653976 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -111,7 +111,6 @@ public: QGLWidget* getGLWidget() { return _glWidget; } MyAvatar* getAvatar() { return &_myAvatar; } - Profile* getProfile() { return &_profile; } Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } @@ -135,6 +134,9 @@ public: Avatar* getLookatTargetAvatar() const { return _lookatTargetAvatar; } + Profile* getProfile() { return &_profile; } + void resetProfile(const QString& username); + static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0f5e3fc58e..d3f9c66a26 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -67,6 +67,12 @@ Menu::Menu() : SLOT(aboutApp())))->setMenuRole(QAction::AboutRole); #endif + (addActionToQMenuAndActionHash(fileMenu, + MenuOption::Login, + 0, + this, + SLOT(login()))); + (addActionToQMenuAndActionHash(fileMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, @@ -746,6 +752,40 @@ QLineEdit* lineEditForDomainHostname() { return domainServerLineEdit; } + +void Menu::login() { + Application* applicationInstance = Application::getInstance(); + QDialog dialog(applicationInstance->getGLWidget()); + dialog.setWindowTitle("Login"); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + dialog.setLayout(layout); + + QFormLayout* form = new QFormLayout(); + layout->addLayout(form, 1); + + QString username = applicationInstance->getProfile()->getUsername(); + QLineEdit* usernameLineEdit = new QLineEdit(username); + usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); + form->addRow("Username:", usernameLineEdit); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); + dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttons); + + int ret = dialog.exec(); + applicationInstance->getWindow()->activateWindow(); + if (ret != QDialog::Accepted) { + return; + } + + if (usernameLineEdit->text() != username) { + // there has been a username change + // ask for a profile reset with the new username + applicationInstance->resetProfile(usernameLineEdit->text()); + } +} + void Menu::editPreferences() { Application* applicationInstance = Application::getInstance(); @@ -757,11 +797,6 @@ void Menu::editPreferences() { QFormLayout* form = new QFormLayout(); layout->addLayout(form, 1); - QString avatarUsername = applicationInstance->getProfile()->getUsername(); - QLineEdit* avatarUsernameEdit = new QLineEdit(avatarUsername); - avatarUsernameEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); - form->addRow("Username:", avatarUsernameEdit); - QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString()); avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH); form->addRow("Avatar URL:", avatarURL); @@ -814,17 +849,6 @@ void Menu::editPreferences() { QUrl faceModelURL(faceURLEdit->text()); - - if (avatarUsernameEdit->text() != avatarUsername) { - // there has been a username change - set the new UUID on the avatar instance - applicationInstance->getProfile()->setUsername(avatarUsernameEdit->text()); - - if (faceModelURL.toString() == faceURLString && !avatarUsernameEdit->text().isEmpty()) { - // if there was no change to the face model URL then ask the data-server for what it is - DataServerClient::getClientValueForKey(DataServerKey::FaceMeshURL); - } - } - if (faceModelURL.toString() != faceURLString) { // change the faceModelURL in the profile, it will also update this user's BlendFace applicationInstance->getProfile()->setFaceModelURL(faceModelURL); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f54d3767a1..c4146986c6 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -69,6 +69,7 @@ public slots: private slots: void aboutApp(); + void login(); void editPreferences(); void goToDomain(); void goToLocation(); @@ -174,6 +175,7 @@ namespace MenuOption { const QString ListenModePoint = "Listen Mode Point"; const QString ListenModeSingleSource = "Listen Mode Single Source"; const QString Log = "Log"; + const QString Login = "Login"; const QString LookAtIndicator = "Look-at Indicator"; const QString LookAtVectors = "Look-at Vectors"; const QString LowRes = "Lower Resolution While Moving"; diff --git a/interface/src/avatar/Profile.cpp b/interface/src/avatar/Profile.cpp index 7a0d86189f..360a97d2c1 100644 --- a/interface/src/avatar/Profile.cpp +++ b/interface/src/avatar/Profile.cpp @@ -11,26 +11,15 @@ #include "Profile.h" #include "DataServerClient.h" -Profile::Profile() : - _username(), +Profile::Profile(const QString &username) : + _username(username), _uuid(), - _faceModelURL() + _lastDomain(), + _lastPosition(0.0, 0.0, 0.0), + _faceModelURL() { - -} - -void Profile::clear() { - _username.clear(); - _uuid = QUuid(); - _faceModelURL.clear(); -} - -void Profile::setUsername(const QString &username) { - this->clear(); - _username = username; - if (!_username.isEmpty()) { - // we've been given a new username, ask the data-server for our UUID + // we've been given a new username, ask the data-server for profile DataServerClient::getClientValueForKey(DataServerKey::UUID); } } @@ -50,6 +39,27 @@ void Profile::setFaceModelURL(const QUrl& faceModelURL) { Q_ARG(QUrl, _faceModelURL)); } +void Profile::updatePositionInDomain(const QString& domain, const glm::vec3 position) { + if (!_username.isEmpty()) { + bool updateRequired = false; + + if (_lastDomain != domain) { + _lastDomain = domain; + updateRequired = true; + } + + if (_lastPosition != position) { + _lastPosition = position; + updateRequired = true; + } + + if (updateRequired) { + // either the domain or position or both have changed, time to send update to data-server + + } + } +} + void Profile::saveData(QSettings* settings) { settings->beginGroup("Profile"); diff --git a/interface/src/avatar/Profile.h b/interface/src/avatar/Profile.h index 34ffc5bd25..90b9f883ec 100644 --- a/interface/src/avatar/Profile.h +++ b/interface/src/avatar/Profile.h @@ -13,26 +13,34 @@ #include #include +#include + class Profile { public: - Profile(); + Profile(const QString& username); - void setUsername(const QString& username); - QString& getUsername() { return _username; } + const QString& getUsername() const { return _username; } void setUUID(const QUuid& uuid); - QUuid& getUUID() { return _uuid; } + const QUuid& getUUID() { return _uuid; } void setFaceModelURL(const QUrl& faceModelURL); - QUrl& getFaceModelURL() { return _faceModelURL; } + const QUrl& getFaceModelURL() const { return _faceModelURL; } - void clear(); + void updatePositionInDomain(const QString& domain, const glm::vec3 position); + + QString getLastDomain() const { return _lastDomain; } + const glm::vec3& getLastPosition() const { return _lastPosition; } + + void updateLastLocation(const glm::vec3 lastLocation); void saveData(QSettings* settings); void loadData(QSettings* settings); private: QString _username; QUuid _uuid; + QString _lastDomain; + glm::vec3 _lastPosition; QUrl _faceModelURL; }; From d3b95d19a1c79634c8ecaff98a14ae58b70b944a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 15:09:57 -0700 Subject: [PATCH 02/11] send the user's last domain and position to data-server --- interface/src/Application.cpp | 10 +++++++ interface/src/DataServerClient.h | 2 ++ interface/src/Menu.cpp | 7 +++-- interface/src/avatar/Profile.cpp | 45 +++++++++++++++++++++----------- interface/src/avatar/Profile.h | 5 ++-- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8d38343e3d..96249cee02 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -182,6 +182,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _settings = new QSettings(this); + // load user profile data + _profile.loadData(_settings); + // check if there is a saved domain server hostname // this must be done now instead of with the other setting checks to allow manual override with // --domain or --local options @@ -1166,6 +1169,9 @@ void Application::timer() { // ask the node list to check in with the domain server NodeList::getInstance()->sendDomainServerCheckIn(); + + // give the MyAvatar object position to the Profile so it can propagate to the data-server + _profile.updatePosition(_myAvatar.getPosition()); } static glm::vec3 getFaceVector(BoxFace face) { @@ -3516,9 +3522,13 @@ void Application::attachNewHeadToNode(Node* newNode) { void Application::domainChanged(QString domain) { qDebug("Application title set to: %s.\n", domain.toStdString().c_str()); _window->setWindowTitle(domain); + + // update the user's last domain in their Profile (which will propagate to data-server) + _profile.updateDomain(domain); } void Application::nodeAdded(Node* node) { + } void Application::nodeKilled(Node* node) { diff --git a/interface/src/DataServerClient.h b/interface/src/DataServerClient.h index e4f5290fd5..1b8df7c00c 100644 --- a/interface/src/DataServerClient.h +++ b/interface/src/DataServerClient.h @@ -31,7 +31,9 @@ private: }; namespace DataServerKey { + const char Domain[] = "domain"; const char FaceMeshURL[] = "mesh"; + const char Position[] = "position"; const char UUID[] = "uuid"; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d3f9c66a26..efc1c5b775 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -510,9 +510,10 @@ void Menu::loadSettings(QSettings* settings) { settings->endGroup(); scanMenuBar(&loadAction, settings); - Application::getInstance()->getProfile()->loadData(settings); Application::getInstance()->getAvatar()->loadData(settings); Application::getInstance()->getSwatch()->loadData(settings); + + // NodeList and profile settings are not loaded here because the Application will load them immediately on start } void Menu::saveSettings(QSettings* settings) { @@ -533,9 +534,11 @@ void Menu::saveSettings(QSettings* settings) { scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); - Application::getInstance()->getProfile()->saveData(settings); Application::getInstance()->getSwatch()->saveData(settings); + // save the user profile + Application::getInstance()->getProfile()->saveData(settings); + // ask the NodeList to save its data NodeList::getInstance()->saveData(settings); } diff --git a/interface/src/avatar/Profile.cpp b/interface/src/avatar/Profile.cpp index 360a97d2c1..7326edd9e6 100644 --- a/interface/src/avatar/Profile.cpp +++ b/interface/src/avatar/Profile.cpp @@ -39,24 +39,39 @@ void Profile::setFaceModelURL(const QUrl& faceModelURL) { Q_ARG(QUrl, _faceModelURL)); } -void Profile::updatePositionInDomain(const QString& domain, const glm::vec3 position) { - if (!_username.isEmpty()) { - bool updateRequired = false; +void Profile::updateDomain(const QString& domain) { + if (_lastDomain != domain) { + _lastDomain = domain; - if (_lastDomain != domain) { - _lastDomain = domain; - updateRequired = true; - } + // send the changed domain to the data-server + DataServerClient::putValueForKey(DataServerKey::Domain, domain.toLocal8Bit().constData()); + } +} + +void Profile::updatePosition(const glm::vec3 position) { + if (_lastPosition != position) { - if (_lastPosition != position) { - _lastPosition = position; - updateRequired = true; - } + static timeval lastPositionSend = {}; + const uint64_t DATA_SERVER_POSITION_UPDATE_INTERVAL_USECS = 5 * 1000 * 1000; + const float DATA_SERVER_POSITION_CHANGE_THRESHOLD_METERS = 1; - if (updateRequired) { - // either the domain or position or both have changed, time to send update to data-server - - } + if (usecTimestampNow() - usecTimestamp(&lastPositionSend) >= DATA_SERVER_POSITION_UPDATE_INTERVAL_USECS && + (fabsf(_lastPosition.x - position.x) >= DATA_SERVER_POSITION_CHANGE_THRESHOLD_METERS || + fabsf(_lastPosition.y - position.y) >= DATA_SERVER_POSITION_CHANGE_THRESHOLD_METERS || + fabsf(_lastPosition.z - position.z) >= DATA_SERVER_POSITION_CHANGE_THRESHOLD_METERS)) { + + // if it has been 5 seconds since the last position change and the user has moved >= the threshold + // in at least one of the axis then send the position update to the data-server + + _lastPosition = position; + + // update the lastPositionSend to now + gettimeofday(&lastPositionSend, NULL); + + // send the changed position to the data-server + QString positionString = QString("%1,%2,%3").arg(position.x).arg(position.y).arg(position.z); + DataServerClient::putValueForKey(DataServerKey::Position, positionString.toLocal8Bit().constData()); + } } } diff --git a/interface/src/avatar/Profile.h b/interface/src/avatar/Profile.h index 90b9f883ec..398d0204fb 100644 --- a/interface/src/avatar/Profile.h +++ b/interface/src/avatar/Profile.h @@ -27,13 +27,12 @@ public: void setFaceModelURL(const QUrl& faceModelURL); const QUrl& getFaceModelURL() const { return _faceModelURL; } - void updatePositionInDomain(const QString& domain, const glm::vec3 position); + void updateDomain(const QString& domain); + void updatePosition(const glm::vec3 position); QString getLastDomain() const { return _lastDomain; } const glm::vec3& getLastPosition() const { return _lastPosition; } - void updateLastLocation(const glm::vec3 lastLocation); - void saveData(QSettings* settings); void loadData(QSettings* settings); private: From f7a0dd514ed68bd8c7e9689a6e7e32dfd2099aff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 15:23:07 -0700 Subject: [PATCH 03/11] load NodeList and Profile settings with menu settings load --- interface/src/Application.cpp | 12 ++---------- interface/src/Menu.cpp | 8 ++------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 96249cee02..b3d30a4541 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -182,13 +182,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _settings = new QSettings(this); - // load user profile data - _profile.loadData(_settings); - - // check if there is a saved domain server hostname - // this must be done now instead of with the other setting checks to allow manual override with - // --domain or --local options - NodeList::getInstance()->loadData(_settings); + // call Menu getInstance static method to set up the menu + _window->setMenuBar(Menu::getInstance()); // Check to see if the user passed in a command line option for loading a local // Voxel File. @@ -210,9 +205,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : NodeList::getInstance()->startSilentNodeRemovalThread(); _window->setCentralWidget(_glWidget); - - // call Menu getInstance static method to set up the menu - _window->setMenuBar(Menu::getInstance()); _networkAccessManager = new QNetworkAccessManager(this); QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index efc1c5b775..4f4b94d5d0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -512,8 +512,8 @@ void Menu::loadSettings(QSettings* settings) { scanMenuBar(&loadAction, settings); Application::getInstance()->getAvatar()->loadData(settings); Application::getInstance()->getSwatch()->loadData(settings); - - // NodeList and profile settings are not loaded here because the Application will load them immediately on start + Application::getInstance()->getProfile()->loadData(settings); + NodeList::getInstance()->loadData(settings); } void Menu::saveSettings(QSettings* settings) { @@ -535,11 +535,7 @@ void Menu::saveSettings(QSettings* settings) { scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); Application::getInstance()->getSwatch()->saveData(settings); - - // save the user profile Application::getInstance()->getProfile()->saveData(settings); - - // ask the NodeList to save its data NodeList::getInstance()->saveData(settings); } From d66137e3143239fc30351fcf977eb4717c8105e7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 15:36:33 -0700 Subject: [PATCH 04/11] add a Go To User option to the menu --- interface/src/Menu.cpp | 30 ++++++++++++++++++++++++++++++ interface/src/Menu.h | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4f4b94d5d0..76478cb148 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -99,6 +99,11 @@ Menu::Menu() : Qt::CTRL | Qt::SHIFT | Qt::Key_L, this, SLOT(goToLocation())); + addActionToQMenuAndActionHash(fileMenu, + MenuOption::GoToUser, + Qt::CTRL | Qt::SHIFT | Qt::Key_U, + this, + SLOT(goToUser())); addDisabledActionAndSeparator(fileMenu, "Settings"); @@ -966,6 +971,31 @@ void Menu::goToLocation() { } } +void Menu::goToUser() { + Application* applicationInstance = Application::getInstance(); + QDialog dialog(applicationInstance->getGLWidget()); + dialog.setWindowTitle("Go To User"); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + dialog.setLayout(layout); + + QFormLayout* form = new QFormLayout(); + layout->addLayout(form, 1); + + QLineEdit* usernameLineEdit = new QLineEdit(); + usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); + form->addRow("", usernameLineEdit); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); + dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttons); + + int ret = dialog.exec(); + applicationInstance->getWindow()->activateWindow(); + if (ret != QDialog::Accepted) { + return; + } +} void Menu::bandwidthDetails() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c4146986c6..6eb1914d6e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -73,6 +73,7 @@ private slots: void editPreferences(); void goToDomain(); void goToLocation(); + void goToUser(); void bandwidthDetailsClosed(); void voxelStatsDetailsClosed(); void cycleFrustumRenderMode(); @@ -121,7 +122,6 @@ private: }; namespace MenuOption { - const QString AboutApp = "About Interface"; const QString AmbientOcclusion = "Ambient Occlusion"; const QString Avatars = "Avatars"; @@ -162,6 +162,7 @@ namespace MenuOption { const QString GlowMode = "Cycle Glow Mode"; const QString GoToDomain = "Go To Domain..."; const QString GoToLocation = "Go To Location..."; + const QString GoToUser = "Go To User..."; const QString ImportVoxels = "Import Voxels"; const QString ImportVoxelsClipboard = "Import Voxels to Clipboard"; const QString IncreaseAvatarSize = "Increase Avatar Size"; From 3231776e7683ef89d5fedc66221fd9a4df3f26f5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 16:45:02 -0700 Subject: [PATCH 05/11] add API for Profile userString and multiple value requests --- interface/src/DataServerClient.cpp | 61 +++++++++++++++--------------- interface/src/DataServerClient.h | 4 +- interface/src/avatar/Profile.cpp | 10 +++++ interface/src/avatar/Profile.h | 2 + 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index ff8afeb942..3ffca22fad 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -26,11 +26,7 @@ const unsigned short DATA_SERVER_PORT = 3282; const sockaddr_in DATA_SERVER_SOCKET = socketForHostnameAndHostOrderPort(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); void DataServerClient::putValueForKey(const char* key, const char* value) { - Profile* userProfile = Application::getInstance()->getProfile(); - QString clientString = userProfile->getUUID().isNull() - ? userProfile->getUsername() - : uuidStringWithoutCurlyBraces(userProfile->getUUID().toString()); - + QString clientString = Application::getInstance()->getProfile()->getUserString(); if (!clientString.isEmpty()) { unsigned char* putPacket = new unsigned char[MAX_PACKET_SIZE]; @@ -62,40 +58,45 @@ void DataServerClient::putValueForKey(const char* key, const char* value) { } void DataServerClient::getValueForKeyAndUUID(const char* key, const QUuid &uuid) { + getValuesForKeysAndUUID(QStringList(QString(key)), uuid); +} + +void DataServerClient::getValuesForKeysAndUUID(const QStringList& keys, const QUuid& uuid) { if (!uuid.isNull()) { - getValueForKeyAndUserString(key, uuidStringWithoutCurlyBraces(uuid)); + getValuesForKeysAndUserString(keys, uuidStringWithoutCurlyBraces(uuid)); } } -void DataServerClient::getValueForKeyAndUserString(const char* key, const QString& userString) { - unsigned char* getPacket = new unsigned char[MAX_PACKET_SIZE]; - - // setup the header for this packet - int numPacketBytes = populateTypeAndVersion(getPacket, PACKET_TYPE_DATA_SERVER_GET); - - // pack the user string (could be username or UUID string), null-terminate - memcpy(getPacket + numPacketBytes, userString.toLocal8Bit().constData(), userString.toLocal8Bit().size()); - numPacketBytes += userString.toLocal8Bit().size(); - getPacket[numPacketBytes++] = '\0'; - - // pack the key, null terminated - strcpy((char*) getPacket + numPacketBytes, key); - int numKeyBytes = strlen(key); - - if (numKeyBytes > 0) { - numPacketBytes += numKeyBytes; +void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, const QString& userString) { + if (!userString.isEmpty()) { + unsigned char* getPacket = new unsigned char[MAX_PACKET_SIZE]; + + // setup the header for this packet + int numPacketBytes = populateTypeAndVersion(getPacket, PACKET_TYPE_DATA_SERVER_GET); + + // pack the user string (could be username or UUID string), null-terminate + memcpy(getPacket + numPacketBytes, userString.toLocal8Bit().constData(), userString.toLocal8Bit().size()); + numPacketBytes += userString.toLocal8Bit().size(); getPacket[numPacketBytes++] = '\0'; + + for (int i = 0; i < keys.size(); ++i) { + // pack the keys, null terminated + strcpy((char*) getPacket + numPacketBytes, keys[i].toLocal8Bit().constData()); + + numPacketBytes += keys[i].size(); + getPacket[numPacketBytes++] = '\0'; + } + + // add the getPacket to our vector of uncofirmed packets, will be deleted once we get a response from the nameserver + _unmatchedPackets.insert(std::pair(getPacket, numPacketBytes)); + + // send the get to the data server + NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, getPacket, numPacketBytes); } - - // add the getPacket to our vector of uncofirmed packets, will be deleted once we get a response from the nameserver - _unmatchedPackets.insert(std::pair(getPacket, numPacketBytes)); - - // send the get to the data server - NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, getPacket, numPacketBytes); } void DataServerClient::getClientValueForKey(const char* key) { - getValueForKeyAndUserString(key, Application::getInstance()->getProfile()->getUsername()); + getValuesForKeysAndUserString(QStringList(QString(key)), Application::getInstance()->getProfile()->getUserString()); } void DataServerClient::processConfirmFromDataServer(unsigned char* packetData, int numPacketBytes) { diff --git a/interface/src/DataServerClient.h b/interface/src/DataServerClient.h index 1b8df7c00c..8adf01db5d 100644 --- a/interface/src/DataServerClient.h +++ b/interface/src/DataServerClient.h @@ -19,7 +19,7 @@ class DataServerClient { public: static void putValueForKey(const char* key, const char* value); static void getValueForKeyAndUUID(const char* key, const QUuid& uuid); - static void getValueForKeyAndUserString(const char* key, const QString& userString); + static void getValuesForKeysAndUUID(const QStringList& keys, const QUuid& uuid); static void getClientValueForKey(const char* key); static void processConfirmFromDataServer(unsigned char* packetData, int numPacketBytes); static void processSendFromDataServer(unsigned char* packetData, int numPacketBytes); @@ -27,6 +27,8 @@ public: static void removeMatchedPacketFromMap(unsigned char* packetData, int numPacketBytes); static void resendUnmatchedPackets(); private: + static void getValuesForKeysAndUserString(const QStringList& keys, const QString& userString); + static std::map _unmatchedPackets; }; diff --git a/interface/src/avatar/Profile.cpp b/interface/src/avatar/Profile.cpp index 7326edd9e6..4b89849620 100644 --- a/interface/src/avatar/Profile.cpp +++ b/interface/src/avatar/Profile.cpp @@ -8,6 +8,8 @@ #include +#include + #include "Profile.h" #include "DataServerClient.h" @@ -24,6 +26,14 @@ Profile::Profile(const QString &username) : } } +QString Profile::getUserString() const { + if (_uuid.isNull()) { + return _username; + } else { + return uuidStringWithoutCurlyBraces(_uuid); + } +} + void Profile::setUUID(const QUuid& uuid) { _uuid = uuid; diff --git a/interface/src/avatar/Profile.h b/interface/src/avatar/Profile.h index 398d0204fb..46086d1476 100644 --- a/interface/src/avatar/Profile.h +++ b/interface/src/avatar/Profile.h @@ -19,6 +19,8 @@ class Profile { public: Profile(const QString& username); + QString getUserString() const; + const QString& getUsername() const { return _username; } void setUUID(const QUuid& uuid); From cd504e229398fa567c228631bd1dede9393e68e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 16:50:54 -0700 Subject: [PATCH 06/11] use QString for DataServerClient keys --- interface/src/DataServerClient.cpp | 20 ++++++++++---------- interface/src/DataServerClient.h | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 3ffca22fad..50184f9074 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -25,7 +25,7 @@ const char DATA_SERVER_HOSTNAME[] = "data.highfidelity.io"; const unsigned short DATA_SERVER_PORT = 3282; const sockaddr_in DATA_SERVER_SOCKET = socketForHostnameAndHostOrderPort(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); -void DataServerClient::putValueForKey(const char* key, const char* value) { +void DataServerClient::putValueForKey(const QString& key, const char* value) { QString clientString = Application::getInstance()->getProfile()->getUserString(); if (!clientString.isEmpty()) { @@ -40,8 +40,8 @@ void DataServerClient::putValueForKey(const char* key, const char* value) { putPacket[numPacketBytes++] = '\0'; // pack the key, null terminated - strcpy((char*) putPacket + numPacketBytes, key); - numPacketBytes += strlen(key); + strcpy((char*) putPacket + numPacketBytes, key.toLocal8Bit().constData()); + numPacketBytes += key.size(); putPacket[numPacketBytes++] = '\0'; // pack the value, null terminated @@ -57,8 +57,8 @@ void DataServerClient::putValueForKey(const char* key, const char* value) { } } -void DataServerClient::getValueForKeyAndUUID(const char* key, const QUuid &uuid) { - getValuesForKeysAndUUID(QStringList(QString(key)), uuid); +void DataServerClient::getValueForKeyAndUUID(const QString& key, const QUuid &uuid) { + getValuesForKeysAndUUID(QStringList(key), uuid); } void DataServerClient::getValuesForKeysAndUUID(const QStringList& keys, const QUuid& uuid) { @@ -95,8 +95,8 @@ void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, co } } -void DataServerClient::getClientValueForKey(const char* key) { - getValuesForKeysAndUserString(QStringList(QString(key)), Application::getInstance()->getProfile()->getUserString()); +void DataServerClient::getClientValueForKey(const QString& key) { + getValuesForKeysAndUserString(QStringList(key), Application::getInstance()->getProfile()->getUserString()); } void DataServerClient::processConfirmFromDataServer(unsigned char* packetData, int numPacketBytes) { @@ -123,18 +123,18 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int // the user string was a username // for now assume this means that it is for our avatar - if (strcmp(dataKeyPosition, DataServerKey::FaceMeshURL) == 0) { + if (strcmp(dataKeyPosition, DataServerKey::FaceMeshURL.toLocal8Bit().constData()) == 0) { // pull the user's face mesh and set it on the Avatar instance qDebug("Changing user's face model URL to %s\n", dataValueString.toLocal8Bit().constData()); Application::getInstance()->getProfile()->setFaceModelURL(QUrl(dataValueString)); - } else if (strcmp(dataKeyPosition, DataServerKey::UUID) == 0) { + } else if (strcmp(dataKeyPosition, DataServerKey::UUID.toLocal8Bit().constData()) == 0) { // this is the user's UUID - set it on the profile Application::getInstance()->getProfile()->setUUID(dataValueString); } } else { // user string was UUID, find matching avatar and associate data - if (strcmp(dataKeyPosition, DataServerKey::FaceMeshURL) == 0) { + if (strcmp(dataKeyPosition, DataServerKey::FaceMeshURL.toLocal8Bit().constData()) == 0) { NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { diff --git a/interface/src/DataServerClient.h b/interface/src/DataServerClient.h index 8adf01db5d..e6b6cbcaad 100644 --- a/interface/src/DataServerClient.h +++ b/interface/src/DataServerClient.h @@ -17,10 +17,10 @@ class DataServerClient { public: - static void putValueForKey(const char* key, const char* value); - static void getValueForKeyAndUUID(const char* key, const QUuid& uuid); + static void putValueForKey(const QString& key, const char* value); + static void getValueForKeyAndUUID(const QString& key, const QUuid& uuid); static void getValuesForKeysAndUUID(const QStringList& keys, const QUuid& uuid); - static void getClientValueForKey(const char* key); + static void getClientValueForKey(const QString& key); static void processConfirmFromDataServer(unsigned char* packetData, int numPacketBytes); static void processSendFromDataServer(unsigned char* packetData, int numPacketBytes); static void processMessageFromDataServer(unsigned char* packetData, int numPacketBytes); @@ -33,10 +33,10 @@ private: }; namespace DataServerKey { - const char Domain[] = "domain"; - const char FaceMeshURL[] = "mesh"; - const char Position[] = "position"; - const char UUID[] = "uuid"; + const QString Domain = "domain"; + const QString FaceMeshURL = "mesh"; + const QString Position = "position"; + const QString UUID = "uuid"; } #endif /* defined(__hifi__DataServerClient__) */ From 4c148c6f3ab684ea558d55f5e0662a9c150e3369 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 16:58:27 -0700 Subject: [PATCH 07/11] ask data-server for domain + position of user from goToUser --- interface/src/DataServerClient.h | 7 +++++-- interface/src/Menu.cpp | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/src/DataServerClient.h b/interface/src/DataServerClient.h index e6b6cbcaad..dabb1c822c 100644 --- a/interface/src/DataServerClient.h +++ b/interface/src/DataServerClient.h @@ -18,16 +18,19 @@ class DataServerClient { public: static void putValueForKey(const QString& key, const char* value); + static void getClientValueForKey(const QString& key); + static void getValueForKeyAndUUID(const QString& key, const QUuid& uuid); static void getValuesForKeysAndUUID(const QStringList& keys, const QUuid& uuid); - static void getClientValueForKey(const QString& key); + static void getValuesForKeysAndUserString(const QStringList& keys, const QString& userString); + static void processConfirmFromDataServer(unsigned char* packetData, int numPacketBytes); static void processSendFromDataServer(unsigned char* packetData, int numPacketBytes); static void processMessageFromDataServer(unsigned char* packetData, int numPacketBytes); static void removeMatchedPacketFromMap(unsigned char* packetData, int numPacketBytes); static void resendUnmatchedPackets(); private: - static void getValuesForKeysAndUserString(const QStringList& keys, const QString& userString); + static std::map _unmatchedPackets; }; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 76478cb148..441236ed44 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -995,6 +995,12 @@ void Menu::goToUser() { if (ret != QDialog::Accepted) { return; } + + if (!usernameLineEdit->text().isEmpty()) { + // there's a username entered by the user, make a request to the data-server + DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position), + usernameLineEdit->text()); + } } void Menu::bandwidthDetails() { From fb39ad0a55898125053de8ae67eda7553adb6fc4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 9 Oct 2013 17:03:02 -0700 Subject: [PATCH 08/11] comment out data-server packet queueing until sequencing is implemented --- interface/src/DataServerClient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 50184f9074..6152914db5 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -50,7 +50,7 @@ void DataServerClient::putValueForKey(const QString& key, const char* value) { putPacket[numPacketBytes++] = '\0'; // add the putPacket to our vector of unconfirmed packets, will be deleted once put is confirmed - _unmatchedPackets.insert(std::pair(putPacket, numPacketBytes)); + // _unmatchedPackets.insert(std::pair(putPacket, numPacketBytes)); // send this put request to the data server NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, putPacket, numPacketBytes); @@ -88,7 +88,7 @@ void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, co } // add the getPacket to our vector of uncofirmed packets, will be deleted once we get a response from the nameserver - _unmatchedPackets.insert(std::pair(getPacket, numPacketBytes)); + // _unmatchedPackets.insert(std::pair(getPacket, numPacketBytes)); // send the get to the data server NodeList::getInstance()->getNodeSocket()->send((sockaddr*) &DATA_SERVER_SOCKET, getPacket, numPacketBytes); @@ -151,7 +151,7 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int } // remove the matched packet from our map so it isn't re-sent to the data-server - removeMatchedPacketFromMap(packetData, numPacketBytes); + // removeMatchedPacketFromMap(packetData, numPacketBytes); } void DataServerClient::processMessageFromDataServer(unsigned char* packetData, int numPacketBytes) { From d37ae7da1b0478423cb6150de45b607bc77a154c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Oct 2013 11:49:14 -0700 Subject: [PATCH 09/11] include the number of keys with data-server get --- interface/src/DataServerClient.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 6152914db5..7e64717236 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -68,7 +68,7 @@ void DataServerClient::getValuesForKeysAndUUID(const QStringList& keys, const QU } void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, const QString& userString) { - if (!userString.isEmpty()) { + if (!userString.isEmpty() && keys.size() <= UCHAR_MAX) { unsigned char* getPacket = new unsigned char[MAX_PACKET_SIZE]; // setup the header for this packet @@ -79,6 +79,9 @@ void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, co numPacketBytes += userString.toLocal8Bit().size(); getPacket[numPacketBytes++] = '\0'; + // pack one byte to designate the number of keys + getPacket[numPacketBytes++] = keys.size(); + for (int i = 0; i < keys.size(); ++i) { // pack the keys, null terminated strcpy((char*) getPacket + numPacketBytes, keys[i].toLocal8Bit().constData()); From 7851251e5d9632a37adf55a9f83139cc098300fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Oct 2013 11:51:18 -0700 Subject: [PATCH 10/11] indicate number of values being put to data-server --- interface/src/DataServerClient.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 7e64717236..9d257244aa 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -39,6 +39,9 @@ void DataServerClient::putValueForKey(const QString& key, const char* value) { numPacketBytes += clientString.toLocal8Bit().size(); putPacket[numPacketBytes++] = '\0'; + // pack a 1 to designate that we are putting a single value + putPacket[numPacketBytes++] = 1; + // pack the key, null terminated strcpy((char*) putPacket + numPacketBytes, key.toLocal8Bit().constData()); numPacketBytes += key.size(); From 33e6e1925ec214285147b518fe02836fa93db671 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 10 Oct 2013 13:50:03 -0700 Subject: [PATCH 11/11] handle get of multiple values in single packet --- interface/src/DataServerClient.cpp | 91 ++++++++++++++++++------------ 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/interface/src/DataServerClient.cpp b/interface/src/DataServerClient.cpp index 9d257244aa..b8f2c49681 100644 --- a/interface/src/DataServerClient.cpp +++ b/interface/src/DataServerClient.cpp @@ -18,9 +18,10 @@ #include "DataServerClient.h" - std::map DataServerClient::_unmatchedPackets; +const char MULTI_KEY_VALUE_SEPARATOR = '|'; + const char DATA_SERVER_HOSTNAME[] = "data.highfidelity.io"; const unsigned short DATA_SERVER_PORT = 3282; const sockaddr_in DATA_SERVER_SOCKET = socketForHostnameAndHostOrderPort(DATA_SERVER_HOSTNAME, DATA_SERVER_PORT); @@ -85,13 +86,11 @@ void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, co // pack one byte to designate the number of keys getPacket[numPacketBytes++] = keys.size(); - for (int i = 0; i < keys.size(); ++i) { - // pack the keys, null terminated - strcpy((char*) getPacket + numPacketBytes, keys[i].toLocal8Bit().constData()); - - numPacketBytes += keys[i].size(); - getPacket[numPacketBytes++] = '\0'; - } + QString keyString = keys.join(MULTI_KEY_VALUE_SEPARATOR); + + // pack the key string, null terminated + strcpy((char*) getPacket + numPacketBytes, keyString.toLocal8Bit().constData()); + numPacketBytes += keyString.size() + sizeof('\0'); // add the getPacket to our vector of uncofirmed packets, will be deleted once we get a response from the nameserver // _unmatchedPackets.insert(std::pair(getPacket, numPacketBytes)); @@ -119,39 +118,57 @@ void DataServerClient::processSendFromDataServer(unsigned char* packetData, int QUuid userUUID(userString); - char* dataKeyPosition = (char*) packetData + numHeaderBytes + strlen(userStringPosition) + sizeof('\0'); - char* dataValuePosition = dataKeyPosition + strlen(dataKeyPosition) + sizeof(char); + char* keysPosition = (char*) packetData + numHeaderBytes + strlen(userStringPosition) + + sizeof('\0') + sizeof(unsigned char); + char* valuesPosition = keysPosition + strlen(keysPosition) + sizeof('\0'); - QString dataValueString(QByteArray(dataValuePosition, - numPacketBytes - ((unsigned char*) dataValuePosition - packetData))); + QStringList keyList = QString(keysPosition).split(MULTI_KEY_VALUE_SEPARATOR); + QStringList valueList = QString(valuesPosition).split(MULTI_KEY_VALUE_SEPARATOR); - if (userUUID.isNull()) { - // the user string was a username - // for now assume this means that it is for our avatar - - if (strcmp(dataKeyPosition, DataServerKey::FaceMeshURL.toLocal8Bit().constData()) == 0) { - // pull the user's face mesh and set it on the Avatar instance - - qDebug("Changing user's face model URL to %s\n", dataValueString.toLocal8Bit().constData()); - Application::getInstance()->getProfile()->setFaceModelURL(QUrl(dataValueString)); - } else if (strcmp(dataKeyPosition, DataServerKey::UUID.toLocal8Bit().constData()) == 0) { - // this is the user's UUID - set it on the profile - Application::getInstance()->getProfile()->setUUID(dataValueString); - } - } else { - // user string was UUID, find matching avatar and associate data - if (strcmp(dataKeyPosition, DataServerKey::FaceMeshURL.toLocal8Bit().constData()) == 0) { - NodeList* nodeList = NodeList::getInstance(); - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { - Avatar* avatar = (Avatar *) node->getLinkedData(); - - if (avatar->getUUID() == userUUID) { - QMetaObject::invokeMethod(&avatar->getHead().getBlendFace(), - "setModelURL", - Q_ARG(QUrl, QUrl(dataValueString))); + // user string was UUID, find matching avatar and associate data + for (int i = 0; i < keyList.size(); i++) { + if (valueList[i] != " ") { + if (keyList[i] == DataServerKey::FaceMeshURL) { + + if (userUUID.isNull() || userUUID == Application::getInstance()->getProfile()->getUUID()) { + qDebug("Changing user's face model URL to %s\n", valueList[0].toLocal8Bit().constData()); + Application::getInstance()->getProfile()->setFaceModelURL(QUrl(valueList[0])); + } else { + // mesh URL for a UUID, find avatar in our list + NodeList* nodeList = NodeList::getInstance(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { + Avatar* avatar = (Avatar *) node->getLinkedData(); + + if (avatar->getUUID() == userUUID) { + QMetaObject::invokeMethod(&avatar->getHead().getBlendFace(), + "setModelURL", + Q_ARG(QUrl, QUrl(valueList[0]))); + } + } } } + } else if (keyList[i] == DataServerKey::Domain) { + qDebug() << "Changing domain hostname to" << valueList[i].toLocal8Bit().constData() << + "to go to" << userString << "\n"; + NodeList::getInstance()->setDomainHostname(valueList[i]); + } else if (keyList[i] == DataServerKey::Position) { + QStringList coordinateItems = valueList[i].split(','); + + if (coordinateItems.size() == 3) { + qDebug() << "Changing position to" << valueList[i].toLocal8Bit().constData() << + "to go to" << userString << "\n"; + + glm::vec3 newPosition(coordinateItems[0].toFloat(), + coordinateItems[1].toFloat(), + coordinateItems[2].toFloat()); + Application::getInstance()->getAvatar()->setPosition(newPosition); + } + + + } else if (keyList[i] == DataServerKey::UUID) { + // this is the user's UUID - set it on the profile + Application::getInstance()->getProfile()->setUUID(valueList[0]); } } }