diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 18ba881573..9a97e9a42f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3146,6 +3146,9 @@ void Application::loadServerlessDomain(QUrl domainURL) { tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0); } + std::map namedPaths = tmpTree->getNamedPaths(); + nodeList->getDomainHandler().setIsConnected(true, namedPaths); + _fullSceneReceivedCounter++; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 2cf66911a4..d5c7b9c2d6 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2303,6 +2303,18 @@ bool EntityTree::readFromMap(QVariantMap& map) { _persistDataVersion = map["DataVersion"].toInt(); } + _namedPaths.clear(); + if (map.contains("Paths")) { + QVariantMap namedPathsMap = map["Paths"].toMap(); + for(QVariantMap::const_iterator iter = namedPathsMap.begin(); iter != namedPathsMap.end(); ++iter) { + QString namedPathName = iter.key(); + QString namedPathViewPoint = iter.value().toString(); + _namedPaths[namedPathName] = namedPathViewPoint; + } + } else { + _namedPaths["/"] = "/"; + } + // map will have a top-level list keyed as "Entities". This will be extracted // and iterated over. Each member of this list is converted to a QVariantMap, then // to a QScriptValue, and then to EntityItemProperties. These properties are used diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 5f69714432..791c030fc8 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -301,6 +301,8 @@ public: static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName); static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName); + std::map getNamedPaths() const { return _namedPaths; } + signals: void deletingEntity(const EntityItemID& entityID); void deletingEntityPointer(EntityItem* entityID); @@ -417,6 +419,8 @@ private: static std::function _removeMaterialFromOverlayOperator; bool _serverlessDomain { false }; + + std::map _namedPaths; }; #endif // hifi_EntityTree_h diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 3c24cc796c..56b148a43c 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -29,7 +29,7 @@ #include "UserActivityLogger.h" #include "udt/PacketHeaders.h" -const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json"; +const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json?location=/"; const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; const QString SETTINGS_CURRENT_ADDRESS_KEY = "address"; @@ -312,7 +312,15 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) { _shareablePlaceName.clear(); setDomainInfo(lookupUrl, trigger); emit lookupResultsFinished(); - handlePath(DOMAIN_SPAWNING_POINT, LookupTrigger::Internal, false); + + QString path = DOMAIN_SPAWNING_POINT; + QUrlQuery queryArgs(lookupUrl); + const QString LOCATION_QUERY_KEY = "location"; + if (queryArgs.hasQueryItem(LOCATION_QUERY_KEY)) { + path = queryArgs.queryItemValue(LOCATION_QUERY_KEY); + } + + handlePath(path, LookupTrigger::Internal, false); return true; } diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index c20d6d73be..fe3b0abcb7 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -173,9 +173,7 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) { QString previousHost = _domainURL.host(); _domainURL = domainURL; - if (domainURL.scheme() != URL_SCHEME_HIFI) { - setIsConnected(true); - } else if (previousHost != domainURL.host()) { + if (previousHost != domainURL.host()) { qCDebug(networking) << "Updated domain hostname to" << domainURL.host(); if (!domainURL.host().isEmpty()) { @@ -250,6 +248,14 @@ void DomainHandler::activateICEPublicSocket() { emit completedSocketDiscovery(); } +QString DomainHandler::getViewPointFromNamedPath(QString namedPath) { + auto lookup = _namedPaths.find(namedPath); + if (lookup != _namedPaths.end()) { + return lookup->second; + } + return DOMAIN_SPAWNING_POINT; +} + void DomainHandler::completedHostnameLookup(const QHostInfo& hostInfo) { for (int i = 0; i < hostInfo.addresses().size(); i++) { if (hostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { @@ -279,7 +285,8 @@ void DomainHandler::completedIceServerHostnameLookup() { emit iceSocketAndIDReceived(); } -void DomainHandler::setIsConnected(bool isConnected) { +void DomainHandler::setIsConnected(bool isConnected, std::map namedPaths) { + _namedPaths = namedPaths; if (_isConnected != isConnected) { _isConnected = isConnected; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index fbc60e2492..760b2f8235 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -73,9 +73,11 @@ public: void activateICEPublicSocket(); bool isConnected() const { return _isConnected; } - void setIsConnected(bool isConnected); + void setIsConnected(bool isConnected, std::map namedPaths = std::map()); bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_HIFI; } + QString getViewPointFromNamedPath(QString namedPath); + bool hasSettings() const { return !_settingsObject.isEmpty(); } void requestDomainSettings(); const QJsonObject& getSettingsObject() const { return _settingsObject; } @@ -200,6 +202,8 @@ private: int _checkInPacketsSinceLastReply { 0 }; QTimer _apiRefreshTimer; + + std::map _namedPaths; }; const QString DOMAIN_SPAWNING_POINT { "/0, -10, 0" }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index cb0d2e4cd5..3c2b4cd336 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -413,7 +413,14 @@ void NodeList::sendDomainServerCheckIn() { } void NodeList::handleDSPathQuery(const QString& newPath) { - if (_domainHandler.isSocketKnown()) { + if (_domainHandler.isServerless()) { + if (_domainHandler.isConnected()) { + auto viewpoint = _domainHandler.getViewPointFromNamedPath(newPath); + DependencyManager::get()->goToViewpointForPath(viewpoint, newPath); + } else { + _domainHandler.setPendingPath(newPath); + } + } else if (_domainHandler.isSocketKnown()) { // if we have a DS socket we assume it will get this packet and send if off right away sendDSPathQuery(newPath); } else { @@ -427,10 +434,15 @@ void NodeList::sendPendingDSPathQuery() { QString pendingPath = _domainHandler.getPendingPath(); if (!pendingPath.isEmpty()) { - qCDebug(networking) << "Attempting to send pending query to DS for path" << pendingPath; - // this is a slot triggered if we just established a network link with a DS and want to send a path query - sendDSPathQuery(_domainHandler.getPendingPath()); + if (_domainHandler.isServerless()) { + auto viewpoint = _domainHandler.getViewPointFromNamedPath(pendingPath); + DependencyManager::get()->goToViewpointForPath(viewpoint, pendingPath); + } else { + qCDebug(networking) << "Attempting to send pending query to DS for path" << pendingPath; + // this is a slot triggered if we just established a network link with a DS and want to send a path query + sendDSPathQuery(_domainHandler.getPendingPath()); + } // clear whatever the pending path was _domainHandler.clearPendingPath();