From 7b1ac247094b67a66353be475630f3ead17f35f1 Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Thu, 4 Jan 2018 17:32:14 -0800 Subject: [PATCH 1/2] Update (#1) * Tablet paginator initial * Refactor to SwipeView * Use MouseArea for interacting instead of default one to be able interact in HMD mode * Make page indicators non clickable. Attempt to enable swipe even over buttons * Tune press delay to be able to swipe tablet pages easier * VR stylus and laser need longer timeout than mouse * Swipe area expanded to whole tablet. Icons doesnt stick together anymore * Fix warnings after apps closed * Using Flickable signals to remove hover state instead of timer. No more delays * Created poly scripting interface template * Created poly scripting interface template * can fetch poly asset list synchronously * removed key * Something intermediate * Retreive buttons list from tablet proxy * Added buttons list mutex protection. Reworked keyboard tablet navigation. no more double selections * Code style * Created poly scripting interface template * can fetch poly asset list synchronously * removed key * added getAssetList() and getFBX() * Added smart pointer for qml buttons. removed extra modifiers. page changed using left and right buttons * Create pages and store in global array, makes sure it will not be cleared by garbage collector whe out of scope * enabled fbx, obj, and blocks model url retrieval * added gltf import feature, getAssetList() not working * fixed getAssetList() * cleaned up code * added const to valid inputs * changed qtglobal include * added newline to header * Store button list in the resources section of fake item instead of C++ space * Preliminary proxy model * fix issue * delete dot file * fix spacing * fix grabbing * delete code * fix model overlays visibility change * typo * Refactored using new GridView approach * Selection consistency #1 * Selection consistency #2 * handles empty json object return * keyword filters case insensitive now * fixed constant names, added another URL check * added const to several parameters * changed api key variable name * Use buttons index * Cleanup. Errors checks * Remove legacy jurisdiction code * Update Octree server stats to handle single server * CR * Fix marketplacesInject.js for local Metaverse * Make things slightly better? * Remove erroneous "filed" Overlay property * Add a link to My Purchases from Wallet Home * add .jsc, remove duplicate qmlc, and remote Utils.jsc * Fix Security Pic Change dialog after QML security changes * Add Unused packet type back for ICE servers * Make sure the protocol signature still changes * fix bug preventing sim owenrship on local domain * remove unnecessary 'virtual' keyword --- .gitignore | 4 +- assignment-client/src/Agent.cpp | 15 - assignment-client/src/Agent.h | 1 - .../src/octree/OctreeHeadlessViewer.cpp | 176 +--------- .../src/octree/OctreeHeadlessViewer.h | 4 - .../src/octree/OctreeSendThread.cpp | 5 +- assignment-client/src/octree/OctreeServer.cpp | 44 --- assignment-client/src/octree/OctreeServer.h | 4 - .../src/octree/OctreeServerConsts.h | 1 - .../src/scripts/EntityScriptServer.cpp | 15 - .../src/scripts/EntityScriptServer.h | 1 - .../commerce/wallet/SecurityImageChange.qml | 4 +- .../qml/hifi/commerce/wallet/WalletHome.qml | 26 +- .../qml/hifi/tablet/TabletButton.qml | 22 +- .../resources/qml/hifi/tablet/TabletHome.qml | 219 +++++++++--- interface/resources/qml/js/Utils.jsc | Bin 6596 -> 0 bytes interface/src/Application.cpp | 204 +---------- interface/src/Application.h | 5 +- .../GooglePolyScriptingInterface.cpp | 181 ++++++++++ .../scripting/GooglePolyScriptingInterface.h | 47 +++ interface/src/ui/OctreeStatsDialog.cpp | 178 +++------- interface/src/ui/OctreeStatsDialog.h | 35 +- interface/src/ui/OctreeStatsProvider.cpp | 229 ++++++------ interface/src/ui/OctreeStatsProvider.h | 9 +- interface/src/ui/overlays/Base3DOverlay.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 31 +- libraries/entities/src/EntityItem.h | 2 +- libraries/networking/src/LimitedNodeList.cpp | 5 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 7 +- libraries/octree/src/JurisdictionListener.cpp | 85 ----- libraries/octree/src/JurisdictionListener.h | 60 ---- libraries/octree/src/JurisdictionMap.cpp | 325 ------------------ libraries/octree/src/JurisdictionMap.h | 88 ----- libraries/octree/src/JurisdictionSender.cpp | 68 ---- libraries/octree/src/JurisdictionSender.h | 58 ---- libraries/octree/src/Octree.cpp | 25 +- libraries/octree/src/Octree.h | 8 - .../octree/src/OctreeEditPacketSender.cpp | 216 ++++-------- libraries/octree/src/OctreeEditPacketSender.h | 11 - libraries/octree/src/OctreeSceneStats.cpp | 95 +---- libraries/octree/src/OctreeSceneStats.h | 12 +- .../octree/src/OctreeScriptingInterface.cpp | 26 +- .../octree/src/OctreeScriptingInterface.h | 7 +- libraries/render-utils/src/Model.cpp | 55 ++- libraries/render-utils/src/Model.h | 6 +- .../ui/src/ui/TabletScriptingInterface.cpp | 41 +++ .../ui/src/ui/TabletScriptingInterface.h | 31 ++ scripts/system/commerce/wallet.js | 1 + scripts/system/html/js/marketplacesInject.js | 17 +- 50 files changed, 889 insertions(+), 1826 deletions(-) delete mode 100644 interface/resources/qml/js/Utils.jsc create mode 100644 interface/src/scripting/GooglePolyScriptingInterface.cpp create mode 100644 interface/src/scripting/GooglePolyScriptingInterface.h delete mode 100644 libraries/octree/src/JurisdictionListener.cpp delete mode 100644 libraries/octree/src/JurisdictionListener.h delete mode 100644 libraries/octree/src/JurisdictionMap.cpp delete mode 100644 libraries/octree/src/JurisdictionMap.h delete mode 100644 libraries/octree/src/JurisdictionSender.cpp delete mode 100644 libraries/octree/src/JurisdictionSender.h diff --git a/.gitignore b/.gitignore index 665238e7da..76ae194c82 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,7 @@ android/.gradle android/app/src/main/jniLibs # VSCode -# List taken from Github Global Ignores master@435c4d92 +# List taken from Github Global Ignores master@435c4d92 # https://github.com/github/gitignore/commits/master/Global/VisualStudioCode.gitignore .vscode/* !.vscode/settings.json @@ -66,7 +66,7 @@ gvr-interface/libs/* # ignore files for various dev environments TAGS *.sw[po] -*.qmlc +*.jsc # ignore QML compilation output *.qmlc diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index f166a780ff..2fc905c6fd 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -94,7 +94,6 @@ Agent::Agent(ReceivedMessage& message) : packetReceiver.registerListenerForTypes( { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); @@ -149,17 +148,6 @@ void Agent::handleOctreePacket(QSharedPointer message, SharedNo } } -void Agent::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { - NodeType_t nodeType; - message->peekPrimitive(&nodeType); - - // PacketType_JURISDICTION, first byte is the node type... - if (nodeType == NodeType::EntityServer) { - DependencyManager::get()->getJurisdictionListener()-> - queueReceivedPacket(message, senderNode); - } -} - void Agent::handleAudioPacket(QSharedPointer message) { _receivedAudioStream.parseData(*message); _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); @@ -483,10 +471,7 @@ void Agent::executeScript() { auto recordingInterface = DependencyManager::get(); _scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); - // we need to make sure that init has been called for our EntityScriptingInterface - // so that it actually has a jurisdiction listener when we ask it for it next entityScriptingInterface->init(); - _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); _entityViewer.init(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 168da185b6..1229f06276 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -73,7 +73,6 @@ private slots: void handleAudioPacket(QSharedPointer message); void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); - void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); void nodeActivated(SharedNodePointer activatedNode); diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.cpp b/assignment-client/src/octree/OctreeHeadlessViewer.cpp index 4e885da7a5..d3b20fb623 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.cpp +++ b/assignment-client/src/octree/OctreeHeadlessViewer.cpp @@ -23,23 +23,6 @@ void OctreeHeadlessViewer::queryOctree() { char serverType = getMyNodeType(); PacketType packetType = getMyQueryMessageType(); - NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions(); - - bool wantExtraDebugging = false; - - if (wantExtraDebugging) { - qCDebug(octree) << "OctreeHeadlessViewer::queryOctree() _jurisdictionListener=" << _jurisdictionListener; - qCDebug(octree) << "---------------"; - qCDebug(octree) << "_jurisdictionListener=" << _jurisdictionListener; - qCDebug(octree) << "Jurisdictions..."; - jurisdictions.withReadLock([&] { - for (NodeToJurisdictionMapIterator i = jurisdictions.begin(); i != jurisdictions.end(); ++i) { - qCDebug(octree) << i.key() << ": " << &i.value(); - } - }); - qCDebug(octree) << "---------------"; - } - _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); @@ -51,159 +34,22 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setOctreeSizeScale(_voxelSizeScale); _octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust); - // Iterate all of the nodes, and get a count of how many voxel servers we have... - int totalServers = 0; - int inViewServers = 0; - int unknownJurisdictionServers = 0; - - DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - totalServers++; - - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); - - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - VoxelPositionSize rootDetails; - bool foundRootDetails = false; - jurisdictions.withReadLock([&] { - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownJurisdictionServers++; - return; - } - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - - auto rootCode = map.getRootOctalCode(); - if (!rootCode) { - return; - } - - voxelDetailsForCode(rootCode.get(), rootDetails); - foundRootDetails = true; - }); - - if (foundRootDetails) { - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - if ((bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds))) { - inViewServers++; - } - } - } - }); - - if (wantExtraDebugging) { - qCDebug(octree, "Servers: total %d, in view %d, unknown jurisdiction %d", - totalServers, inViewServers, unknownJurisdictionServers); - } - - int perServerPPS = 0; - const int SMALL_BUDGET = 10; - int perUnknownServer = SMALL_BUDGET; - int totalPPS = getMaxPacketsPerSecond(); - - // determine PPS based on number of servers - if (inViewServers >= 1) { - // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS - // for each unknown jurisdiction server - perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); - } else { - if (unknownJurisdictionServers > 0) { - perUnknownServer = (totalPPS / unknownJurisdictionServers); - } - } - - if (wantExtraDebugging) { - qCDebug(octree, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); - } - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); + auto node = nodeList->soloNodeOfType(serverType); + if (node && node->getActiveSocket()) { + _octreeQuery.setMaxQueryPacketsPerSecond(getMaxPacketsPerSecond()); - bool inView = false; - bool unknownView = false; + auto queryPacket = NLPacket::create(packetType); - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - VoxelPositionSize rootDetails; - bool foundRootDetails = false; - jurisdictions.withReadLock([&] { - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownView = true; // assume it's in view - if (wantExtraDebugging) { - qCDebug(octree) << "no known jurisdiction for node " << *node << ", assume it's visible."; - } - return; - } + // encode the query data + auto packetData = reinterpret_cast(queryPacket->getPayload()); + int packetSize = _octreeQuery.getBroadcastData(packetData); + queryPacket->setPayloadSize(packetSize); - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - auto rootCode = map.getRootOctalCode(); - - if (!rootCode) { - if (wantExtraDebugging) { - qCDebug(octree) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; - } - return; - } - voxelDetailsForCode(rootCode.get(), rootDetails); - foundRootDetails = true; - }); - - if (foundRootDetails) { - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - inView = (bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds)); - } - - if (inView) { - _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS); - if (wantExtraDebugging) { - qCDebug(octree) << "inView for node " << *node << ", give it budget of " << perServerPPS; - } - } else if (unknownView) { - if (wantExtraDebugging) { - qCDebug(octree) << "no known jurisdiction for node " << *node << ", give it budget of " - << perUnknownServer << " to send us jurisdiction."; - } - - // set the query's position/orientation to be degenerate in a manner that will get the scene quickly - // If there's only one server, then don't do this, and just let the normal voxel query pass through - // as expected... this way, we will actually get a valid scene if there is one to be seen - if (totalServers > 1) { - _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); - const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); - _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); - _octreeQuery.setCameraNearClip(0.1f); - _octreeQuery.setCameraFarClip(0.1f); - if (wantExtraDebugging) { - qCDebug(octree) << "Using 'minimal' camera position for node" << *node; - } - } else { - if (wantExtraDebugging) { - qCDebug(octree) << "Using regular camera position for node" << *node; - } - } - _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer); - } else { - _octreeQuery.setMaxQueryPacketsPerSecond(0); - } - - // setup the query packet - auto queryPacket = NLPacket::create(packetType); - - // read the data to our packet and set the payload size to fit the query - int querySize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); - queryPacket->setPayloadSize(querySize); - - // ask the NodeList to send it - nodeList->sendPacket(std::move(queryPacket), *node); - } - }); + // make sure we still have an active socket + nodeList->sendUnreliablePacket(*queryPacket, *node); + } } diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.h b/assignment-client/src/octree/OctreeHeadlessViewer.h index 5a7544498d..feb8211c39 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.h +++ b/assignment-client/src/octree/OctreeHeadlessViewer.h @@ -13,7 +13,6 @@ #define hifi_OctreeHeadlessViewer_h #include -#include #include @@ -23,8 +22,6 @@ class OctreeHeadlessViewer : public OctreeProcessor { public: OctreeHeadlessViewer(); virtual ~OctreeHeadlessViewer() {}; - - void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } OctreeQuery& getOctreeQuery() { return _octreeQuery; } @@ -57,7 +54,6 @@ public slots: unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); } private: - JurisdictionListener* _jurisdictionListener = nullptr; OctreeQuery _octreeQuery; ViewFrustum _viewFrustum; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 3ae653307f..d5b9da7353 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -391,8 +391,7 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData->sceneStart(usecTimestampNow() - CHANGE_FUDGE); // start tracking our stats - nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, - _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot()); preStartNewScene(nodeData, isFullScene); } @@ -507,7 +506,7 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre float octreeSizeScale = nodeData->getOctreeSizeScale(); EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP, viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale, - isFullScene, _myServer->getJurisdiction(), nodeData); + isFullScene, nodeData); // Our trackSend() function is implemented by the server subclass, and will be called back as new entities/data elements are sent params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { _myServer->trackSend(dataID, dataEdited, _nodeUuid); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c535c48dda..42494ea7ee 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -237,8 +237,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) : _debugSending(false), _debugReceiving(false), _verboseDebug(false), - _jurisdiction(NULL), - _jurisdictionSender(NULL), _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), @@ -257,12 +255,6 @@ OctreeServer::~OctreeServer() { delete[] _parsedArgV; } - if (_jurisdictionSender) { - _jurisdictionSender->terminating(); - _jurisdictionSender->terminate(); - _jurisdictionSender->deleteLater(); - } - if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); _octreeInboundPacketProcessor->terminate(); @@ -275,9 +267,6 @@ OctreeServer::~OctreeServer() { _persistThread->deleteLater(); } - delete _jurisdiction; - _jurisdiction = NULL; - // cleanup our tree here... qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; _tree.reset(); @@ -933,10 +922,6 @@ void OctreeServer::handleOctreeDataNackPacket(QSharedPointer me } } -void OctreeServer::handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { - _jurisdictionSender->queueReceivedPacket(message, senderNode); -} - void OctreeServer::handleOctreeFileReplacement(QSharedPointer message) { if (!_isFinished && !_isShuttingDown) { // these messages are only allowed to come from the domain server, so make sure that is the case @@ -1111,23 +1096,6 @@ void OctreeServer::readConfiguration() { qDebug() << "statusPort= DISABLED"; } - QString jurisdictionFile; - if (readOptionString(QString("jurisdictionFile"), settingsSectionObject, jurisdictionFile)) { - qDebug("jurisdictionFile=%s", qPrintable(jurisdictionFile)); - qDebug("about to readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile)); - _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionFile)); - qDebug("after readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile)); - } else { - QString jurisdictionRoot; - bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot); - QString jurisdictionEndNodes; - bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes); - - if (hasRoot || hasEndNodes) { - _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes)); - } - } - readOptionBool(QString("verboseDebug"), settingsSectionObject, _verboseDebug); qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug)); @@ -1241,7 +1209,6 @@ void OctreeServer::domainSettingsRequestComplete() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(getMyQueryMessageType(), this, "handleOctreeQueryPacket"); packetReceiver.registerListener(PacketType::OctreeDataNack, this, "handleOctreeDataNackPacket"); - packetReceiver.registerListener(PacketType::JurisdictionRequest, this, "handleJurisdictionRequestPacket"); packetReceiver.registerListener(PacketType::OctreeFileReplacement, this, "handleOctreeFileReplacement"); packetReceiver.registerListener(PacketType::OctreeFileReplacementFromUrl, this, "handleOctreeFileReplacementFromURL"); @@ -1365,13 +1332,6 @@ void OctreeServer::domainSettingsRequestComplete() { _persistThread->initialize(true); } - // set up our jurisdiction broadcaster... - if (_jurisdiction) { - _jurisdiction->setNodeType(getMyNodeType()); - } - _jurisdictionSender = new JurisdictionSender(_jurisdiction, getMyNodeType()); - _jurisdictionSender->initialize(true); - // set up our OctreeServerPacketProcessor _octreeInboundPacketProcessor = new OctreeInboundPacketProcessor(this); _octreeInboundPacketProcessor->initialize(true); @@ -1441,10 +1401,6 @@ void OctreeServer::aboutToFinish() { _octreeInboundPacketProcessor->terminating(); } - if (_jurisdictionSender) { - _jurisdictionSender->terminating(); - } - // Shut down all the send threads for (auto& it : _sendThreads) { auto& sendThread = *it.second; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index f930f299f3..0eba914064 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -44,7 +44,6 @@ public: bool wantsVerboseDebug() const { return _verboseDebug; } OctreePointer getOctree() { return _tree; } - JurisdictionMap* getJurisdiction() { return _jurisdiction; } int getPacketsPerClientPerInterval() const { return std::min(_packetsPerClientPerInterval, std::max(1, getPacketsTotalPerInterval() / std::max(1, getCurrentClientCount()))); } @@ -138,7 +137,6 @@ private slots: void domainSettingsRequestComplete(); void handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode); - void handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeFileReplacement(QSharedPointer message); void handleOctreeFileReplacementFromURL(QSharedPointer message); void removeSendThread(); @@ -190,8 +188,6 @@ protected: bool _debugReceiving; bool _debugTimestampNow; bool _verboseDebug; - JurisdictionMap* _jurisdiction; - JurisdictionSender* _jurisdictionSender; OctreeInboundPacketProcessor* _octreeInboundPacketProcessor; OctreePersistThread* _persistThread; diff --git a/assignment-client/src/octree/OctreeServerConsts.h b/assignment-client/src/octree/OctreeServerConsts.h index 30b55b8786..2706b3ef73 100644 --- a/assignment-client/src/octree/OctreeServerConsts.h +++ b/assignment-client/src/octree/OctreeServerConsts.h @@ -14,7 +14,6 @@ #include #include // for MAX_PACKET_SIZE -#include const int MAX_FILENAME_LENGTH = 1024; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index c8067ce81f..b4a6b3af93 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -79,7 +79,6 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); auto avatarHashMap = DependencyManager::set(); @@ -283,11 +282,8 @@ void EntityScriptServer::run() { // Setup Script Engine resetEntitiesScriptEngine(); - // we need to make sure that init has been called for our EntityScriptingInterface - // so that it actually has a jurisdiction listener when we ask it for it next auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); - _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); _entityViewer.init(); @@ -566,17 +562,6 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer mess } } -void EntityScriptServer::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { - NodeType_t nodeType; - message->peekPrimitive(&nodeType); - - // PacketType_JURISDICTION, first byte is the node type... - if (nodeType == NodeType::EntityServer) { - DependencyManager::get()->getJurisdictionListener()-> - queueReceivedPacket(message, senderNode); - } -} - void EntityScriptServer::aboutToFinish() { shutdownScriptEngine(); diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index f9c5e921f0..9c6c4c752e 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -41,7 +41,6 @@ public slots: private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); - void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); void handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode); diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index b261743434..2ad2b75553 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -66,7 +66,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } } Item { @@ -194,7 +194,7 @@ Item { securityImageSubmitButton.text = "Submitting..."; securityImageSubmitButton.enabled = false; var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - commerce.chooseSecurityImage(securityImagePath); + Commerce.chooseSecurityImage(securityImagePath); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 5a5eeeb91f..42ee44d584 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -197,14 +197,36 @@ Item { anchors.topMargin: 26; anchors.left: parent.left; anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 30; + width: paintedWidth; height: 30; // Text size size: 22; // Style color: hifi.colors.baseGrayHighlight; } + + RalewaySemiBold { + id: myPurchasesLink; + text: 'My Purchases'; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 26; + anchors.right: parent.right; + anchors.rightMargin: 20; + width: paintedWidth; + height: 30; + y: 4; + // Text size + size: 18; + // Style + color: hifi.colors.baseGrayHighlight; + horizontalAlignment: Text.AlignRight; + + onLinkActivated: { + sendSignalToWallet({method: 'goToPurchases_fromWalletHome'}); + } + } + ListModel { id: tempTransactionHistoryModel; } diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 1508367318..4d443fb97c 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -23,11 +23,26 @@ Item { property double sortOrder: 100 property int stableOrder: 0 property var tabletRoot; + property var flickable: null + property var gridView: null + + property int buttonIndex: -1 + width: 129 height: 129 signal clicked() + Connections { + target: flickable + onMovingChanged: { + //when flick/move started, and hover is on, clean hove state + if (flickable.moving && tabletButton.state.indexOf("hover") !== -1) { + tabletButton.state = (tabletButton.isActive) ? "active state" : "base state"; + } + } + } + function changeProperty(key, value) { tabletButton[key] = value; } @@ -121,8 +136,10 @@ Item { anchors.fill: parent hoverEnabled: true enabled: true - preventStealing: true + preventStealing: false onClicked: { + gridView.currentIndex = buttonIndex + if (tabletButton.inDebugMode) { if (tabletButton.isActive) { tabletButton.isActive = false; @@ -130,12 +147,15 @@ Item { tabletButton.isActive = true; } } + tabletButton.clicked(); if (tabletRoot) { Tablet.playSound(TabletEnums.ButtonClick); } } + onEntered: { + gridView.currentIndex = buttonIndex tabletButton.isEntered = true; Tablet.playSound(TabletEnums.ButtonHover); diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 3f9451436c..e934f18ab6 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -1,7 +1,10 @@ -import QtQuick 2.5 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 +import TabletScriptingInterface 1.0 + import "." import "../../styles-uit" import "../audio" as HifiAudio @@ -10,7 +13,11 @@ Item { id: tablet objectName: "tablet" property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system"); - + + property var currentGridItems: null + + focus: true + Rectangle { id: bgTopBar height: 90 @@ -85,7 +92,6 @@ Item { Rectangle { id: bgMain - clip: true gradient: Gradient { GradientStop { position: 0 @@ -102,55 +108,186 @@ Item { anchors.left: parent.left anchors.top: bgTopBar.bottom - GridView { - id: flickable - anchors.top: parent.top - anchors.topMargin: 15 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - width: cellWidth * 3 - cellHeight: 145 - cellWidth: 145 - model: tabletProxy.buttons - delegate: Item { - width: flickable.cellWidth - height: flickable.cellHeight - property var proxy: modelData - - TabletButton { - id: tabletButton - anchors.centerIn: parent - onClicked: modelData.clicked() - state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + SwipeView { + id: swipeView + clip: false + currentIndex: -1 + property int previousIndex: -1 + Repeater { + id: pageRepeater + model: Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage) + onItemAdded: { + item.proxyModel.sourceModel = tabletProxy.buttons; + item.proxyModel.pageIndex = index; } - Connections { - target: modelData; - onPropertiesChanged: { - updateProperties(); + delegate: Item { + id: page + property TabletButtonsProxyModel proxyModel: TabletButtonsProxyModel {} + + GridView { + id: gridView + keyNavigationEnabled: false + highlightFollowsCurrentItem: false + property int previousGridIndex: -1 + anchors { + fill: parent + topMargin: 20 + leftMargin: 30 + rightMargin: 30 + bottomMargin: 0 + } + + function setButtonState(buttonIndex, buttonstate) { + if (buttonIndex < 0 || gridView.contentItem === undefined + || gridView.contentItem.children.length - 1 < buttonIndex) { + return; + } + var itemat = gridView.contentItem.children[buttonIndex].children[0]; + if (itemat.isActive) { + itemat.state = "active state"; + } else { + itemat.state = buttonstate; + } + } + + onCurrentIndexChanged: { + setButtonState(previousGridIndex, "base state"); + setButtonState(currentIndex, "hover state"); + previousGridIndex = currentIndex + } + + cellWidth: width/3 + cellHeight: cellWidth + flow: GridView.LeftToRight + model: page.proxyModel + + delegate: Item { + id: wrapper + width: gridView.cellWidth + height: gridView.cellHeight + + property var proxy: modelData + + TabletButton { + id: tabletButton + anchors.centerIn: parent + gridView: wrapper.GridView.view + buttonIndex: page.proxyModel.buttonIndex(uuid); + flickable: swipeView.contentItem; + onClicked: modelData.clicked() + } + + Connections { + target: modelData; + onPropertiesChanged: { + updateProperties(); + } + } + + Component.onCompleted: updateProperties() + + function updateProperties() { + var keys = Object.keys(modelData.properties).forEach(function (key) { + if (tabletButton[key] !== modelData.properties[key]) { + tabletButton[key] = modelData.properties[key]; + } + }); + } + } } } + } - Component.onCompleted: updateProperties() - - function updateProperties() { - var keys = Object.keys(modelData.properties).forEach(function (key) { - if (tabletButton[key] !== modelData.properties[key]) { - tabletButton[key] = modelData.properties[key]; - } - }); + onCurrentIndexChanged: { + if (swipeView.currentIndex < 0 + || swipeView.itemAt(swipeView.currentIndex) === null + || swipeView.itemAt(swipeView.currentIndex).children[0] === null) { + return; } + + currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0]; + + currentGridItems.currentIndex = (previousIndex > swipeView.currentIndex ? currentGridItems.count - 1 : 0); + previousIndex = currentIndex; + } + + hoverEnabled: true + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: pageIndicator.top + } + } + + PageIndicator { + id: pageIndicator + currentIndex: swipeView.currentIndex + + delegate: Item { + width: 15 + height: 15 + + Rectangle { + anchors.centerIn: parent + opacity: index === pageIndicator.currentIndex ? 0.95 : 0.45 + implicitWidth: index === pageIndicator.currentIndex ? 15 : 10 + implicitHeight: implicitWidth + radius: width/2 + color: "white" + Behavior on opacity { + OpacityAnimator { + duration: 100 + } + } + } + } + + interactive: false + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + count: swipeView.count + } + } + + Component.onCompleted: { + focus = true; + forceActiveFocus(); + } + + Keys.onRightPressed: { + if (!currentGridItems) { + return; + } + + var index = currentGridItems.currentIndex; + currentGridItems.moveCurrentIndexRight(); + if (index === currentGridItems.count - 1 && index === currentGridItems.currentIndex) { + if (swipeView.currentIndex < swipeView.count - 1) { + swipeView.incrementCurrentIndex(); } } } - Keys.onRightPressed: flickable.moveCurrentIndexRight(); - Keys.onLeftPressed: flickable.moveCurrentIndexLeft(); - Keys.onDownPressed: flickable.moveCurrentIndexDown(); - Keys.onUpPressed: flickable.moveCurrentIndexUp(); + Keys.onLeftPressed: { + if (!currentGridItems) { + return; + } + + var index = currentGridItems.currentIndex; + currentGridItems.moveCurrentIndexLeft(); + if (index === 0 && index === currentGridItems.currentIndex) { + if (swipeView.currentIndex > 0) { + swipeView.decrementCurrentIndex(); + } + } + } + Keys.onDownPressed: currentGridItems.moveCurrentIndexDown(); + Keys.onUpPressed: currentGridItems.moveCurrentIndexUp(); Keys.onReturnPressed: { - if (flickable.currentItem) { - flickable.currentItem.proxy.clicked(); + if (currentGridItems.currentItem) { + currentGridItems.currentItem.proxy.clicked(); if (tabletRoot) { tabletRoot.playButtonClickSound(); } diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc deleted file mode 100644 index ab20e996b9469915ac6a89901da175143e6b5024..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6596 zcmcIoZD?EP6@Kh1ckah_<+cmm)~+s7*+{cEDOm|)Y*uPBiCux$Iwl#JYtNP&7t3}W zIXI&o4oU8EkM2n zXjl7O2dDtRuNCd{@)jY-)d!#zenqKY4sn&W{weu)twmlb!$4JTzv65rm+K1vDC#!F zU$|ZVIZ9zlW+S<`HL;hgR&M8~1sQiLyXg~6*Kx4qHtya=?){4Iz`gR%B^6)FqD(EX zPx0NgjXdr9YAbNP75KOnxYqy<89DFo`<=jA05hh+!CUJc)7q5K-I-U<4BwMhw#!Kold03qHB1qPh=(m57jV zQZO*TlsKpO<^4D&)ji|-UBpF<$-`KmCFTK~acFxKqv8qb`vJ}(jwnv6ynF{ogq(=F zep_Ap)wNGud)4)O>UtbUguEF{VOB&&#)x21=BI^yoeI;=cpet< z8yEavN0<0LF8)1^DU2eDE}X7EzTC=9#(VVvU%?VLXPX@E8u^tC$cdhzrY~ z5|TzSE|9{#2}}z<=It55SzSj%iNA*yHv6nZbjwP_N>*aF82-K7|F|4Z{3((gYY*l1 z1HmPNES&HK!VAmo!G#Z7%nSc2m&=jFSbJz;vopy0hR~Acw-O%(%P$^o0YVGQoxRBc zfA58N%nJ{-l0bHGCbwg^#q(qrrDi+!w<_$cdfT#JQtVa6B|0HZKTvD>SPT8{3FK*i zWU(iZU!oSteUbW{j!MrrowDh%hwMA*Wz%5~+1G_Km+UHco!!3?d2`uawWQAO`Fhz^ zFY9DKQ7^k1!8+Li%B~H>BZmbX7dAVWSkh#gI3&0r zaF0rAW;@0YRTR^~w|fH1=rq7T1!gIn>dAFt!Sy*C45#|hZ zyKMQfPE=zR8BZ12Iu&e;jZ`qZ;(XBNe0X7VdI#CX&hyK$=>L{qIw{h|R_2l4RI7AY z^-G-Fg*Pl@c)U6&I`)6~vWKqD3?b!JxCu1uN`cA?Q-i-75ra?*w4> z7DLeZEXfck*xy13exhOT)~XM$^JKYWuGBjYFUK{J-kQV9*AmCcI=9Ipz3t&zt&~o& zbp5o=j@d0M5iMDXSkX$%t~YJ^dxYvnP2X7@RT0fd+JSJgHI(cgqRD9&=_E-h7ipTL zi!Ra}N%Kz9JRJ@v&Ijf=afs?ImCUopaAUf5Bc(P@)^4QL#!&4B4=hC;lN+q^_W+Q1 zP^n|i{5|@(6kNweRp@!g!IB0$&XzP(9WOq8UKl6|MM0Czbbp-MJtdAmS4|C?43SDf)z9}dNlLtGo5xl*UM-i)V9TyEvOFWw5I(m_-&8|fx011{`>NNH;(6Df(rr#QsN>-}$CJna|wOpzoRcq-Fq`bAH8fghvwNyJ`N_RlpJYiGQZuHu}HZ5Pa zdE8c|q5`8P==g;$uId?L_>-ZdTT7Ja(9^jWIyw}4%`oqUj`vkn%QKo+>hkt%Am^R8 zT%)}GyrqJUtqMAFDsNlV@ #include #include +#include #include #include @@ -698,6 +699,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(nullptr, qApp->getOcteeSceneStats()); DependencyManager::set(); DependencyManager::set(); @@ -1189,8 +1191,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo userActivityLogger.logAction("launch", properties); } - // Tell our entity edit sender about our known jurisdictions - _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); _entityEditSender.setMyAvatar(myAvatar.get()); // The entity octree will have to know about MyAvatar for the parentJointName import @@ -4557,7 +4557,7 @@ void Application::reloadResourceCaches() { _lastQueriedTime = 0; _octreeQuery.incrementConnectionID(); - queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); + queryOctree(NodeType::EntityServer, PacketType::EntityQuery); DependencyManager::get()->clearCache(); @@ -5050,7 +5050,7 @@ void Application::update(float deltaTime) { if (queryIsDue || viewIsDifferentEnough) { _lastQueriedTime = now; if (DependencyManager::get()->shouldRenderEntities()) { - queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); + queryOctree(NodeType::EntityServer, PacketType::EntityQuery); } sendAvatarViewFrustum(); _lastQueriedViewFrustum = _viewFrustum; @@ -5271,15 +5271,12 @@ int Application::sendNackPackets() { return packetsSent; } -void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { +void Application::queryOctree(NodeType_t serverType, PacketType packetType) { if (!_settingsLoaded) { return; // bail early if settings are not loaded } - //qCDebug(interfaceapp) << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView(); - bool wantExtraDebugging = getLogger()->extraDebugging(); - ViewFrustum viewFrustum; copyViewFrustum(viewFrustum); _octreeQuery.setCameraPosition(viewFrustum.getPosition()); @@ -5294,147 +5291,22 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); - // Iterate all of the nodes, and get a count of how many octree servers we have... - int totalServers = 0; - int inViewServers = 0; - int unknownJurisdictionServers = 0; - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node) { - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - totalServers++; + auto node = nodeList->soloNodeOfType(serverType); + if (node && node->getActiveSocket()) { + _octreeQuery.setMaxQueryPacketsPerSecond(getMaxOctreePacketsPerSecond()); - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); + auto queryPacket = NLPacket::create(packetType); - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownJurisdictionServers++; - } else { - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; + // encode the query data + auto packetData = reinterpret_cast(queryPacket->getPayload()); + int packetSize = _octreeQuery.getBroadcastData(packetData); + queryPacket->setPayloadSize(packetSize); - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, - rootDetails.y * TREE_SCALE, - rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE), - rootDetails.s * TREE_SCALE); - if (viewFrustum.cubeIntersectsKeyhole(serverBounds)) { - inViewServers++; - } - } - } - } - }); - - if (wantExtraDebugging) { - qCDebug(interfaceapp, "Servers: total %d, in view %d, unknown jurisdiction %d", - totalServers, inViewServers, unknownJurisdictionServers); + // make sure we still have an active socket + nodeList->sendUnreliablePacket(*queryPacket, *node); } - - int perServerPPS = 0; - const int SMALL_BUDGET = 10; - int perUnknownServer = SMALL_BUDGET; - int totalPPS = getMaxOctreePacketsPerSecond(); - - // determine PPS based on number of servers - if (inViewServers >= 1) { - // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS - // for each unknown jurisdiction server - perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); - } else { - if (unknownJurisdictionServers > 0) { - perUnknownServer = (totalPPS / unknownJurisdictionServers); - } - } - - if (wantExtraDebugging) { - qCDebug(interfaceapp, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); - } - - auto queryPacket = NLPacket::create(packetType); - - nodeList->eachNode([&](const SharedNodePointer& node) { - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); - - bool inView = false; - bool unknownView = false; - - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownView = true; // assume it's in view - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", assume it's visible."; - } - } else { - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, - rootDetails.y * TREE_SCALE, - rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE), - rootDetails.s * TREE_SCALE); - - - inView = viewFrustum.cubeIntersectsKeyhole(serverBounds); - } else if (wantExtraDebugging) { - qCDebug(interfaceapp) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; - } - } - - if (inView) { - _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS); - } else if (unknownView) { - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", give it budget of " - << perUnknownServer << " to send us jurisdiction."; - } - - // set the query's position/orientation to be degenerate in a manner that will get the scene quickly - // If there's only one server, then don't do this, and just let the normal voxel query pass through - // as expected... this way, we will actually get a valid scene if there is one to be seen - if (totalServers > 1) { - _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); - const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); - _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); - _octreeQuery.setCameraNearClip(0.1f); - _octreeQuery.setCameraFarClip(0.1f); - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "Using 'minimal' camera position for node" << *node; - } - } else { - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "Using regular camera position for node" << *node; - } - } - _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer); - } else { - _octreeQuery.setMaxQueryPacketsPerSecond(0); - } - - // encode the query data - int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); - queryPacket->setPayloadSize(packetSize); - - // make sure we still have an active socket - nodeList->sendUnreliablePacket(*queryPacket, *node); - } - }); } @@ -5549,11 +5421,6 @@ void Application::clearDomainOctreeDetails() { resetPhysicsReadyInformation(); - // reset our node to stats and node to jurisdiction maps... since these must be changing... - _entityServerJurisdictions.withWriteLock([&] { - _entityServerJurisdictions.clear(); - }); - _octreeServerSceneStats.withWriteLock([&] { _octreeServerSceneStats.clear(); }); @@ -5755,8 +5622,6 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { } int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { - // But, also identify the sender, and keep track of the contained jurisdiction root for this server - // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to int statsMessageLength = 0; @@ -5771,42 +5636,6 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer if (octreeStats.isFullScene()) { _fullSceneReceivedCounter++; } - - // see if this is the first we've heard of this node... - NodeToJurisdictionMap* jurisdiction = nullptr; - QString serverType; - if (sendingNode->getType() == NodeType::EntityServer) { - jurisdiction = &_entityServerJurisdictions; - serverType = "Entity"; - } - - bool found = false; - - jurisdiction->withReadLock([&] { - if (jurisdiction->find(nodeUUID) != jurisdiction->end()) { - found = true; - return; - } - - VoxelPositionSize rootDetails; - voxelDetailsForCode(octreeStats.getJurisdictionRoot().get(), rootDetails); - - qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", - qPrintable(serverType), - (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); - }); - - if (!found) { - // store jurisdiction details for later use - // This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it - // but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the - // details from the OctreeSceneStats to construct the JurisdictionMap - JurisdictionMap jurisdictionMap; - jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes()); - jurisdiction->withWriteLock([&] { - (*jurisdiction)[nodeUUID] = jurisdictionMap; - }); - } }); return statsMessageLength; @@ -5827,7 +5656,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe return !entityServerNode || isPhysicsEnabled(); }); - // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so + // setup the packet sender of the script engine's scripting interfaces so // we can use the same ones from the application. auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->setPacketSender(&_entityEditSender); @@ -5941,6 +5770,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get())); diff --git a/interface/src/Application.h b/interface/src/Application.h index ee16740f20..5267d50cf6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -228,8 +228,6 @@ public: FileLogger* getLogger() const { return _logger; } - NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } - float getRenderResolutionScale() const; qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); } @@ -450,7 +448,7 @@ private: void updateThreads(float deltaTime); void updateDialogs(float deltaTime) const; - void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); + void queryOctree(NodeType_t serverType, PacketType packetType); int sendNackPackets(); void sendAvatarViewFrustum(); @@ -571,7 +569,6 @@ private: StDev _idleLoopStdev; float _idleLoopMeasuredJitter; - NodeToJurisdictionMap _entityServerJurisdictions; NodeToOctreeSceneStats _octreeServerSceneStats; ControllerScriptingInterface* _controllerScriptingInterface{ nullptr }; QPointer _logDialog; diff --git a/interface/src/scripting/GooglePolyScriptingInterface.cpp b/interface/src/scripting/GooglePolyScriptingInterface.cpp new file mode 100644 index 0000000000..8ed5d59d07 --- /dev/null +++ b/interface/src/scripting/GooglePolyScriptingInterface.cpp @@ -0,0 +1,181 @@ +// +// GooglePolyScriptingInterface.cpp +// interface/src/scripting +// +// Created by Elisa Lupin-Jimenez on 12/3/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GooglePolyScriptingInterface.h" +#include "ScriptEngineLogging.h" + +const QString LIST_POLY_URL = "https://poly.googleapis.com/v1/assets?"; +const QString GET_POLY_URL = "https://poly.googleapis.com/v1/assets/model?"; + +const QStringList VALID_FORMATS = QStringList() << "BLOCKS" << "FBX" << "GLTF" << "GLTF2" << "OBJ" << "TILT" << ""; +const QStringList VALID_CATEGORIES = QStringList() << "animals" << "architecture" << "art" << "food" << + "nature" << "objects" << "people" << "scenes" << "technology" << "transport" << ""; + +GooglePolyScriptingInterface::GooglePolyScriptingInterface() { + // nothing to be implemented +} + +void GooglePolyScriptingInterface::setAPIKey(const QString& key) { + _authCode = key; +} + +QString GooglePolyScriptingInterface::getAssetList(const QString& keyword, const QString& category, const QString& format) { + QUrl url = formatURLQuery(keyword, category, format); + if (!url.isEmpty()) { + QByteArray json = parseJSON(url, 0).toJsonDocument().toJson(); + return (QString) json; + } else { + qCDebug(scriptengine) << "Invalid filters were specified."; + return ""; + } +} + +QString GooglePolyScriptingInterface::getFBX(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "FBX"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getOBJ(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "OBJ"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getBlocks(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "BLOCKS"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getGLTF(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "GLTF"); + return getModelURL(url); +} + +QString GooglePolyScriptingInterface::getGLTF2(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "GLTF2"); + return getModelURL(url); +} + +// This method will not be useful until we support Tilt models +QString GooglePolyScriptingInterface::getTilt(const QString& keyword, const QString& category) { + QUrl url = formatURLQuery(keyword, category, "TILT"); + return getModelURL(url); +} + +// Can provide asset name or full URL to model +QString GooglePolyScriptingInterface::getModelInfo(const QString& input) { + QString name(input); + if (input.contains("poly.googleapis") || input.contains("poly.google.com")) { + QStringList list = input.split("/"); + if (input.contains("poly.googleapis")) { + name = list[4]; + } else { + name = list.last(); + } + } + QString urlString(GET_POLY_URL); + urlString = urlString.replace("model", name) + "key=" + _authCode; + qCDebug(scriptengine) << "Google URL request: " << urlString; + QUrl url(urlString); + QString json = parseJSON(url, 2).toString(); + return json; +} + +int GooglePolyScriptingInterface::getRandIntInRange(int length) { + QTime time = QTime::currentTime(); + qsrand((uint)time.msec()); + return qrand() % length; +} + +QUrl GooglePolyScriptingInterface::formatURLQuery(const QString& keyword, const QString& category, const QString& format) { + QString queries; + if (!VALID_FORMATS.contains(format, Qt::CaseInsensitive) || !VALID_CATEGORIES.contains(category, Qt::CaseInsensitive)) { + return QUrl(""); + } else { + if (!keyword.isEmpty()) { + QString keywords(keyword); + keywords.replace(" ", "+"); + queries.append("&keywords=" + keywords); + } + if (!category.isEmpty()) { + queries.append("&category=" + category); + } + if (!format.isEmpty()) { + queries.append("&format=" + format); + } + QString urlString(LIST_POLY_URL + "key=" + _authCode + queries); + return QUrl(urlString); + } +} + +QString GooglePolyScriptingInterface::getModelURL(const QUrl& url) { + qCDebug(scriptengine) << "Google URL request: " << url; + if (!url.isEmpty()) { + return parseJSON(url, 1).toString(); + } else { + qCDebug(scriptengine) << "Invalid filters were specified."; + return ""; + } +} + +// FIXME: synchronous +QByteArray GooglePolyScriptingInterface::getHTTPRequest(const QUrl& url) { + QNetworkAccessManager manager; + QNetworkReply *response = manager.get(QNetworkRequest(url)); + QEventLoop event; + connect(response, SIGNAL(finished()), &event, SLOT(quit())); + event.exec(); + + return response->readAll(); +} + +// 0 = asset list, 1 = model from asset list, 2 = specific model +QVariant GooglePolyScriptingInterface::parseJSON(const QUrl& url, int fileType) { + QByteArray jsonString = getHTTPRequest(url); + QJsonDocument doc = QJsonDocument::fromJson(jsonString); + QJsonObject obj = doc.object(); + if (obj.isEmpty()) { + qCDebug(scriptengine) << "Assets with specified filters not found"; + return ""; + } + if (obj.keys().first() == "error") { + QString error = obj.value("error").toObject().value("message").toString(); + qCDebug(scriptengine) << error; + return ""; + } + if (fileType == 0 || fileType == 1) { + QJsonArray arr = obj.value("assets").toArray(); + // return model url + if (fileType == 1) { + int random = getRandIntInRange(arr.size()); + QJsonObject json = arr.at(random).toObject(); + // nested JSONs + return json.value("formats").toArray().at(0).toObject().value("root").toObject().value("url"); + } + // return whole asset list + return QJsonDocument(arr); + // return specific object + } else { + return jsonString; + } +} diff --git a/interface/src/scripting/GooglePolyScriptingInterface.h b/interface/src/scripting/GooglePolyScriptingInterface.h new file mode 100644 index 0000000000..fdd3597bec --- /dev/null +++ b/interface/src/scripting/GooglePolyScriptingInterface.h @@ -0,0 +1,47 @@ +// +// GooglePolyScriptingInterface.h +// interface/src/scripting +// +// Created by Elisa Lupin-Jimenez on 12/3/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GooglePolyScriptingInterface_h +#define hifi_GooglePolyScriptingInterface_h + +#include +#include + +class GooglePolyScriptingInterface : public QObject, public Dependency { + Q_OBJECT + +public: + GooglePolyScriptingInterface(); + +public slots: + void setAPIKey(const QString& key); + + QString getAssetList(const QString& keyword, const QString& category, const QString& format); + QString getFBX(const QString& keyword, const QString& category); + QString getOBJ(const QString& keyword, const QString& category); + QString getBlocks(const QString& keyword, const QString& categoryy); + QString getGLTF(const QString& keyword, const QString& category); + QString getGLTF2(const QString& keyword, const QString& category); + QString getTilt(const QString& keyword, const QString& category); + QString getModelInfo(const QString& input); + +private: + QString _authCode; + + QUrl formatURLQuery(const QString& keyword, const QString& category, const QString& format); + QString getModelURL(const QUrl& url); + QByteArray getHTTPRequest(const QUrl& url); + QVariant parseJSON(const QUrl& url, int fileType); + int getRandIntInRange(int length); + +}; + +#endif // hifi_GooglePolyScriptingInterface_h diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index fc0e6781d7..ec5d800042 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -26,27 +26,17 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), - _model(model), - _averageUpdatesPerSecond(SAMPLES_PER_SECOND) + _model(model) { - - _statCount = 0; - _octreeServerLabelsCount = 0; - - for (int i = 0; i < MAX_VOXEL_SERVERS; i++) { - _octreeServerLables[i] = 0; - _extraServerDetails[i] = LESS; - } - for (int i = 0; i < MAX_STATS; i++) { - _labels[i] = NULL; + _labels[i] = nullptr; } - this->setWindowTitle("Octree Server Statistics"); + setWindowTitle("Octree Server Statistics"); // Create layouter _form = new QFormLayout(); - this->QDialog::setLayout(_form); + setLayout(_form); // Setup stat items _serverElements = AddStatItem("Elements on Servers"); @@ -63,7 +53,14 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo _entityUpdateTime = AddStatItem("Entity Update Time"); _entityUpdates = AddStatItem("Entity Updates"); - + + + _octreeServerLabel = AddStatItem("Entity Server"); + _labels[_octreeServerLabel]->setTextFormat(Qt::RichText); + _labels[_octreeServerLabel]->setTextInteractionFlags(Qt::TextBrowserInteraction); + connect(_labels[_octreeServerLabel], SIGNAL(linkActivated(const QString&)), + this, SLOT(moreless(const QString&))); + layout()->setSizeConstraint(QLayout::SetFixedSize); } @@ -74,23 +71,16 @@ void OctreeStatsDialog::RemoveStatItem(int item) { _form->removeWidget(automaticLabel); automaticLabel->deleteLater(); myLabel->deleteLater(); - _labels[item] = NULL; + _labels[item] = nullptr; } void OctreeStatsDialog::moreless(const QString& link) { - QStringList linkDetails = link.split("-"); - const int COMMAND_ITEM = 0; - const int SERVER_NUMBER_ITEM = 1; - QString serverNumberString = linkDetails[SERVER_NUMBER_ITEM]; - QString command = linkDetails[COMMAND_ITEM]; - int serverNumber = serverNumberString.toInt(); - - if (command == "more") { - _extraServerDetails[serverNumber-1] = MORE; - } else if (command == "most") { - _extraServerDetails[serverNumber-1] = MOST; + if (link == "more") { + _extraServerDetails = MORE; + } else if (link == "most") { + _extraServerDetails = MOST; } else { - _extraServerDetails[serverNumber-1] = LESS; + _extraServerDetails = LESS; } } @@ -376,91 +366,34 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { QDialog::paintEvent(event); } void OctreeStatsDialog::showAllOctreeServers() { - int serverCount = 0; - - showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", - qApp->getEntityServerJurisdictions()); - - if (_octreeServerLabelsCount > serverCount) { - for (int i = serverCount; i < _octreeServerLabelsCount; i++) { - int serverLabel = _octreeServerLables[i]; - RemoveStatItem(serverLabel); - _octreeServerLables[i] = 0; - } - _octreeServerLabelsCount = serverCount; - } + showOctreeServersOfType(NodeType::EntityServer); } -void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName, - NodeToJurisdictionMap& serverJurisdictions) { - +void OctreeStatsDialog::showOctreeServersOfType(NodeType_t serverType) { QLocale locale(QLocale::English); - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node){ - - // only send to the NodeTypes that are NodeType_t_VOXEL_SERVER - if (node->getType() == serverType) { - serverCount++; - - if (serverCount > _octreeServerLabelsCount) { - QString label = QString("%1 Server %2").arg(serverTypeName).arg(serverCount); - int thisServerRow = _octreeServerLables[serverCount-1] = AddStatItem(label.toUtf8().constData()); - _labels[thisServerRow]->setTextFormat(Qt::RichText); - _labels[thisServerRow]->setTextInteractionFlags(Qt::TextBrowserInteraction); - connect(_labels[thisServerRow], SIGNAL(linkActivated(const QString&)), this, SLOT(moreless(const QString&))); - _octreeServerLabelsCount++; - } - - std::stringstream serverDetails(""); - std::stringstream extraDetails(""); - std::stringstream linkDetails(""); - - if (node->getActiveSocket()) { - serverDetails << "active "; - } else { - serverDetails << "inactive "; - } - - QUuid nodeUUID = node->getUUID(); - - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're - // missing at least one jurisdiction - serverJurisdictions.withReadLock([&] { - if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) { - serverDetails << " unknown jurisdiction "; - return; - } - const JurisdictionMap& map = serverJurisdictions[nodeUUID]; + auto node = DependencyManager::get()->soloNodeOfType(serverType); + if (node) { + std::stringstream serverDetails(""); + std::stringstream extraDetails(""); + std::stringstream linkDetails(""); - auto rootCode = map.getRootOctalCode(); + if (node->getActiveSocket()) { + serverDetails << "active "; + } else { + serverDetails << "inactive "; + } - if (rootCode) { - QString rootCodeHex = octalCodeToHexString(rootCode.get()); + QUuid nodeUUID = node->getUUID(); - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - serverDetails << " jurisdiction: " - << qPrintable(rootCodeHex) - << " [" - << rootDetails.x << ", " - << rootDetails.y << ", " - << rootDetails.z << ": " - << rootDetails.s << "] "; - } else { - serverDetails << " jurisdiction has no rootCode"; - } // root code - }); - - // now lookup stats details for this server... - if (_extraServerDetails[serverCount-1] != LESS) { - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); + // now lookup stats details for this server... + if (_extraServerDetails != LESS) { + NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); + sceneStats->withReadLock([&] { + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + OctreeSceneStats& stats = sceneStats->at(nodeUUID); - switch (_extraServerDetails[serverCount - 1]) { + switch (_extraServerDetails) { case MOST: { extraDetails << "
"; @@ -538,7 +471,7 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; serverDetails << "
" << - " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << + " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << " [" << qPrintable(formattedClockSkewString) << "]"; @@ -547,38 +480,37 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser " Wasted Bytes: " << qPrintable(incomingWastedBytesString); serverDetails << extraDetails.str(); - if (_extraServerDetails[serverCount - 1] == MORE) { - linkDetails << " " << " [most...]"; - linkDetails << " " << " [less...]"; + if (_extraServerDetails == MORE) { + linkDetails << " [most...]"; + linkDetails << " [less...]"; } else { - linkDetails << " " << " [less...]"; - linkDetails << " " << " [least...]"; + linkDetails << " [less...]"; + linkDetails << " [least...]"; } } break; case LESS: { // nothing } break; - } } - }); - } else { - linkDetails << " " << " [more...]"; - linkDetails << " " << " [most...]"; - } - serverDetails << linkDetails.str(); - _labels[_octreeServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); - } // is VOXEL_SERVER - }); + } + }); + } else { + linkDetails << " [more...]"; + linkDetails << " [most...]"; + } + serverDetails << linkDetails.str(); + _labels[_octreeServerLabel]->setText(serverDetails.str().c_str()); + } } void OctreeStatsDialog::reject() { // Just regularly close upon ESC - this->QDialog::close(); + QDialog::close(); } void OctreeStatsDialog::closeEvent(QCloseEvent* event) { - this->QDialog::closeEvent(event); + QDialog::closeEvent(event); emit closed(); } diff --git a/interface/src/ui/OctreeStatsDialog.h b/interface/src/ui/OctreeStatsDialog.h index 67f5c01f65..81bf5f251f 100644 --- a/interface/src/ui/OctreeStatsDialog.h +++ b/interface/src/ui/OctreeStatsDialog.h @@ -19,7 +19,6 @@ #include #define MAX_STATS 100 -#define MAX_VOXEL_SERVERS 50 #define DEFAULT_COLOR 0 class OctreeStatsDialog : public QDialog { @@ -47,18 +46,22 @@ protected: void RemoveStatItem(int item); void showAllOctreeServers(); - void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, - const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions); + void showOctreeServersOfType(NodeType_t serverType); private: + enum details { + LESS, + MORE, + MOST + }; - typedef enum { LESS, MORE, MOST } details; - - QFormLayout* _form; + QFormLayout* _form { nullptr }; QLabel* _labels[MAX_STATS]; - NodeToOctreeSceneStats* _model; - int _statCount; - + NodeToOctreeSceneStats* _model { nullptr }; + int _statCount { 0 }; + + int _octreeServerLabel; + int _sendingMode; int _serverElements; int _localElements; @@ -72,16 +75,14 @@ private: int _processedPacketsTiming; int _outboundEditPackets; - const int SAMPLES_PER_SECOND = 10; - SimpleMovingAverage _averageUpdatesPerSecond; - quint64 _lastWindowAt = usecTimestampNow(); - quint64 _lastKnownTrackedEdits = 0; + const int SAMPLES_PER_SECOND { 10 }; + SimpleMovingAverage _averageUpdatesPerSecond { SAMPLES_PER_SECOND }; + quint64 _lastWindowAt { usecTimestampNow() }; + quint64 _lastKnownTrackedEdits { 0 }; - quint64 _lastRefresh = 0; + quint64 _lastRefresh { 0 }; - int _octreeServerLables[MAX_VOXEL_SERVERS]; - int _octreeServerLabelsCount; - details _extraServerDetails[MAX_VOXEL_SERVERS]; + details _extraServerDetails { LESS }; }; #endif // hifi_OctreeStatsDialog_h diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index 5f40b9916d..a393660c17 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -16,9 +16,9 @@ OctreeStatsProvider::OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model) : QObject(parent), - _model(model) - , _statCount(0) - , _averageUpdatesPerSecond(SAMPLES_PER_SECOND) + _model(model), + _statCount(0), + _averageUpdatesPerSecond(SAMPLES_PER_SECOND) { //schedule updates connect(&_updateTimer, &QTimer::timeout, this, &OctreeStatsProvider::updateOctreeStatsData); @@ -237,140 +237,105 @@ void OctreeStatsProvider::updateOctreeStatsData() { } void OctreeStatsProvider::updateOctreeServers() { + showOctreeServersOfType(NodeType::EntityServer); +} + +void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) { + m_servers.clear(); int serverCount = 0; - showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", - qApp->getEntityServerJurisdictions()); - if (m_serversNum != serverCount) { + auto node = DependencyManager::get()->soloNodeOfType(serverType); + if (node) { + ++serverCount; + + QString lesserDetails; + QString moreDetails; + QString mostDetails; + + if (node->getActiveSocket()) { + lesserDetails += "active "; + } else { + lesserDetails += "inactive "; + } + + QUuid nodeUUID = node->getUUID(); + + // now lookup stats details for this server... + NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); + sceneStats->withReadLock([&] { + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + OctreeSceneStats& stats = sceneStats->at(nodeUUID); + + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; + float lastFullPackets = stats.getLastFullTotalPackets(); + float lastFullPPS = lastFullPackets; + if (lastFullSendInSeconds > 0) { + lastFullPPS = lastFullPackets / lastFullSendInSeconds; + } + + mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") + .arg(lastFullEncode) + .arg(lastFullSend) + .arg(lastFullPackets) + .arg(stats.getLastFullTotalBytes()) + .arg(lastFullPPS); + + for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { + OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); + OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + mostDetails += QString("
%1 %2") + .arg(itemInfo.caption).arg(stats.getItemValue(item)); + } + + moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; + + moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") + .arg(stats.getTotalElements()) + .arg(stats.getTotalInternal()) + .arg(stats.getTotalLeaves()); + + const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); + qint64 clockSkewInUsecs = node->getClockSkewUsec(); + qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; + + moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") + .arg(stats.getIncomingPackets()) + .arg(seqStats.getLost()) + .arg(seqStats.getRecovered()); + + moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") + .arg(seqStats.getOutOfOrder()) + .arg(seqStats.getEarly()) + .arg(seqStats.getLate()) + .arg(seqStats.getUnreasonable()); + + moreDetails += QString("
Average Flight Time: %1 msecs") + .arg(stats.getIncomingFlightTimeAverage()); + + moreDetails += QString("
Average Ping Time: %1 msecs") + .arg(node->getPingMs()); + + moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") + .arg(clockSkewInMS) + .arg(formatUsecTime(clockSkewInUsecs)); + + + moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") + .arg(stats.getIncomingBytes()) + .arg(stats.getIncomingWastedBytes()); + } + }); + m_servers.append(lesserDetails); + m_servers.append(moreDetails); + m_servers.append(mostDetails); + } + + if (serverCount != m_serversNum) { m_serversNum = serverCount; emit serversNumChanged(m_serversNum); } -} - -void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName, - NodeToJurisdictionMap& serverJurisdictions) { - - m_servers.clear(); - - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node) { - - // only send to the NodeTypes that are NodeType_t_VOXEL_SERVER - if (node->getType() == serverType) { - serverCount++; - - QString lesserDetails; - QString moreDetails; - QString mostDetails; - - if (node->getActiveSocket()) { - lesserDetails += "active "; - } else { - lesserDetails += "inactive "; - } - - QUuid nodeUUID = node->getUUID(); - - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're - // missing at least one jurisdiction - serverJurisdictions.withReadLock([&] { - if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) { - lesserDetails += " unknown jurisdiction "; - return; - } - const JurisdictionMap& map = serverJurisdictions[nodeUUID]; - - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - QString rootCodeHex = octalCodeToHexString(rootCode.get()); - - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - lesserDetails += QString(" jurisdiction: %1 [%2, %3, %4: %5]") - .arg(rootCodeHex) - .arg(rootDetails.x) - .arg(rootDetails.y) - .arg(rootDetails.z) - .arg(rootDetails.s); - } else { - lesserDetails += " jurisdiction has no rootCode"; - } // root code - }); - - // now lookup stats details for this server... - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); - - float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; - float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; - float lastFullPackets = stats.getLastFullTotalPackets(); - float lastFullPPS = lastFullPackets; - if (lastFullSendInSeconds > 0) { - lastFullPPS = lastFullPackets / lastFullSendInSeconds; - } - - mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") - .arg(lastFullEncode) - .arg(lastFullSend) - .arg(lastFullPackets) - .arg(stats.getLastFullTotalBytes()) - .arg(lastFullPPS); - - for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { - OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); - OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - mostDetails += QString("
%1 %2") - .arg(itemInfo.caption).arg(stats.getItemValue(item)); - } - - moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; - - moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") - .arg(stats.getTotalElements()) - .arg(stats.getTotalInternal()) - .arg(stats.getTotalLeaves()); - - const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); - qint64 clockSkewInUsecs = node->getClockSkewUsec(); - qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; - - moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") - .arg(stats.getIncomingPackets()) - .arg(seqStats.getLost()) - .arg(seqStats.getRecovered()); - - moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") - .arg(seqStats.getOutOfOrder()) - .arg(seqStats.getEarly()) - .arg(seqStats.getLate()) - .arg(seqStats.getUnreasonable()); - - moreDetails += QString("
Average Flight Time: %1 msecs") - .arg(stats.getIncomingFlightTimeAverage()); - - moreDetails += QString("
Average Ping Time: %1 msecs") - .arg(node->getPingMs()); - - moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") - .arg(clockSkewInMS) - .arg(formatUsecTime(clockSkewInUsecs)); - - - moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") - .arg(stats.getIncomingBytes()) - .arg(stats.getIncomingWastedBytes()); - } - }); - m_servers.append(lesserDetails); - m_servers.append(moreDetails); - m_servers.append(mostDetails); - } // is VOXEL_SERVER - }); emit serversChanged(m_servers); } diff --git a/interface/src/ui/OctreeStatsProvider.h b/interface/src/ui/OctreeStatsProvider.h index c919ca102f..5b3d4d735c 100644 --- a/interface/src/ui/OctreeStatsProvider.h +++ b/interface/src/ui/OctreeStatsProvider.h @@ -18,10 +18,6 @@ #include "DependencyManager.h" -#define MAX_STATS 100 -#define MAX_VOXEL_SERVERS 50 -#define DEFAULT_COLOR 0 - class OctreeStatsProvider : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -121,8 +117,7 @@ private slots: void updateOctreeStatsData(); protected: void updateOctreeServers(); - void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, - const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions); + void showOctreeServersOfType(NodeType_t serverType); private: NodeToOctreeSceneStats* _model; @@ -136,7 +131,7 @@ private: quint64 _lastRefresh = 0; QTimer _updateTimer; - int m_serversNum {0}; + int m_serversNum { 0 }; QString m_serverElements; QString m_localElements; QString m_localElementsMemory; diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 6922ca87b7..84a6fe1da4 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -212,8 +212,6 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { * parentID set, otherwise the same value as rotation. * @property {boolean} isSolid=false - Synonyms: solid, isFilled, * filled, and filed. Antonyms: isWire and wire. - * Deprecated: The erroneous property spelling "filed" is deprecated and support for it will - * be removed. * @property {boolean} isDashedLine=false - If true, a dashed line is drawn on the overlay's edges. Synonym: * dashed. * @property {boolean} ignoreRayIntersection=false - If true, @@ -241,7 +239,7 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "localRotation" || property == "localOrientation") { return quatToVariant(getLocalOrientation()); } - if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled" || property == "filed") { + if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled") { return _isSolid; } if (property == "isWire" || property == "wire") { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d0dca2d43e..91e26d0a3c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -686,18 +686,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); } } else if (_simulationOwner.pendingTake(now - maxPingRoundTrip)) { - // we sent a bid before this packet could have been sent from the server - // so we ignore it and pretend we own the object's simulation + // we sent a bid already but maybe before this packet was sent from the server weOwnSimulation = true; if (newSimOwner.getID().isNull()) { - // entity-server is trying to clear someone else's ownership - // but we want to own it, therefore we ignore this clear event + // the entity-server is trying to clear someone else's ownership if (!_simulationOwner.isNull()) { - // someone else really did own it markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; _simulationOwner.clearCurrentOwner(); } + } else if (newSimOwner.getID() == myNodeID) { + // the entity-server is awarding us ownership which is what we want + _simulationOwner.set(newSimOwner); } } else if (newSimOwner.matchesValidID(myNodeID) && !_hasBidOnSimulation) { // entity-server tells us that we have simulation ownership while we never requested this for this EntityItem, @@ -2082,17 +2082,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi } EntityDynamicPointer action = _objectActions[actionID]; - - action->setOwnerEntity(nullptr); - action->setIsMine(false); - - if (simulation) { - action->removeFromSimulation(simulation); - } - - bool success = true; - serializeActions(success, _allActionsDataCache); - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; auto removedActionType = action->getType(); if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) { _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; @@ -2109,7 +2098,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi // because they should have been set correctly when the action was added // and/or when children were linked } + action->setOwnerEntity(nullptr); + action->setIsMine(false); _objectActions.remove(actionID); + + if (simulation) { + action->removeFromSimulation(simulation); + } + + bool success = true; + serializeActions(success, _allActionsDataCache); + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; setDynamicDataNeedsTransmit(true); return success; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0136590ffa..d8fb3b3ab6 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -133,7 +133,7 @@ public: static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); - virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); + int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 94bc4eeff6..1b80c3b3af 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -42,7 +42,10 @@ static Setting::Handle LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.Loc const std::set SOLO_NODE_TYPES = { NodeType::AvatarMixer, NodeType::AudioMixer, - NodeType::AssetServer + NodeType::AssetServer, + NodeType::EntityServer, + NodeType::MessagesMixer, + NodeType::EntityScriptServer }; LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 0a75e8c31b..44f86baf40 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(EntityVersion::OwnershipChallengeFix); case PacketType::EntityQuery: - return static_cast(EntityQueryPacketVersion::ConnectionIdentifier); + return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); case PacketType::AvatarIdentity: case PacketType::AvatarData: case PacketType::BulkAvatarData: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 85f321a198..b2f22e2a1f 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -56,8 +56,8 @@ public: ICEServerPeerInformation, ICEServerQuery, OctreeStats, - Jurisdiction, - JurisdictionRequest, + UNUSED_PACKET_TYPE_1, + UNUSED_PACKET_TYPE_2, AssignmentClientStatus, NoisyMute, AvatarIdentity, @@ -212,7 +212,8 @@ enum class EntityScriptCallMethodVersion : PacketVersion { enum class EntityQueryPacketVersion: PacketVersion { JSONFilter = 18, JSONFilterWithFamilyTree = 19, - ConnectionIdentifier = 20 + ConnectionIdentifier = 20, + RemovedJurisdictions = 21 }; enum class AssetServerPacketVersion: PacketVersion { diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp deleted file mode 100644 index 76c5069006..0000000000 --- a/libraries/octree/src/JurisdictionListener.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// JurisdictionListener.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include -#include -#include -#include "JurisdictionListener.h" - -JurisdictionListener::JurisdictionListener(NodeType_t type) : - _nodeType(type), - _packetSender(JurisdictionListener::DEFAULT_PACKETS_PER_SECOND) -{ - setObjectName("Jurisdiction Listener"); - - connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled); - - // tell our NodeList we want to hear about nodes with our node type - DependencyManager::get()->addNodeTypeToInterestSet(type); -} - -void JurisdictionListener::nodeKilled(SharedNodePointer node) { - if (_jurisdictions.find(node->getUUID()) != _jurisdictions.end()) { - _jurisdictions.erase(_jurisdictions.find(node->getUUID())); - } -} - -bool JurisdictionListener::queueJurisdictionRequest() { - auto nodeList = DependencyManager::get(); - - int nodeCount = 0; - - nodeList->eachNode([&](const SharedNodePointer& node) { - if (node->getType() == getNodeType() && node->getActiveSocket()) { - auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0); - _packetSender.queuePacketForSending(node, std::move(packet)); - nodeCount++; - } - }); - - if (nodeCount > 0){ - _packetSender.setPacketsPerSecond(nodeCount); - } else { - _packetSender.setPacketsPerSecond(NO_SERVER_CHECK_RATE); - } - - // keep going if still running - return isStillRunning(); -} - -void JurisdictionListener::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { - if (message->getType() == PacketType::Jurisdiction) { - JurisdictionMap map; - map.unpackFromPacket(*message); - _jurisdictions[message->getSourceID()] = map; - } -} - -bool JurisdictionListener::process() { - bool continueProcessing = isStillRunning(); - - // If we're still running, and we don't have any requests waiting to be sent, then queue our jurisdiction requests - if (continueProcessing && !_packetSender.hasPacketsToSend()) { - queueJurisdictionRequest(); - } - - if (continueProcessing) { - continueProcessing = _packetSender.process(); - } - if (continueProcessing) { - // NOTE: This will sleep if there are no pending packets to process - continueProcessing = ReceivedPacketProcessor::process(); - } - - return continueProcessing; -} diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h deleted file mode 100644 index 7aee1659ff..0000000000 --- a/libraries/octree/src/JurisdictionListener.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// JurisdictionListener.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 High Fidelity, Inc. -// -// Voxel Packet Sender -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_JurisdictionListener_h -#define hifi_JurisdictionListener_h - -#include -#include -#include - -#include "JurisdictionMap.h" - -/// Sends out PacketType::_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes -/// the PacketType::_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions -/// within the domain. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets -/// and adding them to the processing queue by calling queueReceivedPacket() -class JurisdictionListener : public ReceivedPacketProcessor { - Q_OBJECT -public: - static const int DEFAULT_PACKETS_PER_SECOND = 1; - static const int NO_SERVER_CHECK_RATE = 60; // if no servers yet detected, keep checking at 60fps - - JurisdictionListener(NodeType_t type = NodeType::EntityServer); - - virtual bool process() override; - - NodeToJurisdictionMap* getJurisdictions() { return &_jurisdictions; } - - - NodeType_t getNodeType() const { return _nodeType; } - void setNodeType(NodeType_t type) { _nodeType = type; } - -public slots: - /// Called by NodeList to inform us that a node has been killed. - void nodeKilled(SharedNodePointer node); - -protected: - /// Callback for processing of received packets. Will process any queued PacketType::_JURISDICTION and update the - /// jurisdiction map member variable - virtual void processPacket(QSharedPointer messsage, SharedNodePointer sendingNode) override; - -private: - NodeToJurisdictionMap _jurisdictions; - NodeType_t _nodeType; - - bool queueJurisdictionRequest(); - - PacketSender _packetSender; -}; -#endif // hifi_JurisdictionListener_h diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp deleted file mode 100644 index fcbc085339..0000000000 --- a/libraries/octree/src/JurisdictionMap.cpp +++ /dev/null @@ -1,325 +0,0 @@ -// -// JurisdictionMap.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/1/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include -#include - -#include -#include -#include - -#include "OctreeLogging.h" -#include "JurisdictionMap.h" - -void myDebugOutputBits(unsigned char byte, bool withNewLine) { - if (isalnum(byte)) { - printf("[ %d (%c): ", byte, byte); - } else { - printf("[ %d (0x%x): ", byte, byte); - } - - for (int i = 0; i < 8; i++) { - printf("%d", byte >> (7 - i) & 1); - } - printf(" ] "); - - if (withNewLine) { - printf("\n"); - } -} - -void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) { - if (!octalCode) { - printf("nullptr"); - } else { - for (size_t i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { - myDebugOutputBits(octalCode[i], false); - } - } - if (withNewLine) { - printf("\n"); - } -} - -// standard assignment -// copy assignment -JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) { - copyContents(other); - return *this; -} - -// Copy constructor -JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(nullptr) { - copyContents(other); -} - -void JurisdictionMap::copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn) { - OctalCodePtr rootCode = rootCodeIn; - if (!rootCode) { - rootCode = createOctalCodePtr(1); - *rootCode = 0; - } - - OctalCodePtrList emptyEndNodes; - init(rootCode, endNodesIn); -} - -void JurisdictionMap::copyContents(const JurisdictionMap& other) { - _nodeType = other._nodeType; - - OctalCodePtr rootOctalCode; - OctalCodePtrList endNodes; - - std::tie(rootOctalCode, endNodes) = other.getRootAndEndNodeOctalCodes(); - - init(rootOctalCode, endNodes); -} - -JurisdictionMap::~JurisdictionMap() { -} - -JurisdictionMap::JurisdictionMap(NodeType_t type) : _rootOctalCode(nullptr) { - _nodeType = type; - OctalCodePtr rootCode = createOctalCodePtr(1); - *rootCode = 0; - - OctalCodePtrList emptyEndNodes; - init(rootCode, emptyEndNodes); -} - -JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(nullptr) { - readFromFile(filename); -} - -JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) { - - qCDebug(octree, "JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)", - rootHexCode, rootHexCode, endNodesHexCodes, endNodesHexCodes); - - _rootOctalCode = hexStringToOctalCode(QString(rootHexCode)); - - qCDebug(octree, "JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode.get()); - myDebugPrintOctalCode(_rootOctalCode.get(), true); - - QString endNodesHexStrings(endNodesHexCodes); - QString delimiterPattern(","); - QStringList endNodeList = endNodesHexStrings.split(delimiterPattern); - - for (int i = 0; i < endNodeList.size(); i++) { - QString endNodeHexString = endNodeList.at(i); - - auto endNodeOctcode = hexStringToOctalCode(endNodeHexString); - - qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeList(%d)=%s", - i, endNodeHexString.toLocal8Bit().constData()); - - //printOctalCode(endNodeOctcode); - _endNodes.push_back(endNodeOctcode); - - qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode.get()); - myDebugPrintOctalCode(endNodeOctcode.get(), true); - - } -} - -std::tuple JurisdictionMap::getRootAndEndNodeOctalCodes() const { - std::lock_guard lock(_octalCodeMutex); - return std::tuple(_rootOctalCode, _endNodes); -} - -OctalCodePtr JurisdictionMap::getRootOctalCode() const { - std::lock_guard lock(_octalCodeMutex); - return _rootOctalCode; -} - -OctalCodePtrList JurisdictionMap::getEndNodeOctalCodes() const { - std::lock_guard lock(_octalCodeMutex); - return _endNodes; -} - -void JurisdictionMap::init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes) { - std::lock_guard lock(_octalCodeMutex); - _rootOctalCode = rootOctalCode; - _endNodes = endNodes; -} - -JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const { - // to be in our jurisdiction, we must be under the root... - - std::lock_guard lock(_octalCodeMutex); - - // if the node is an ancestor of my root, then we return ABOVE - if (isAncestorOf(nodeOctalCode, _rootOctalCode.get())) { - return ABOVE; - } - - // otherwise... - bool isInJurisdiction = isAncestorOf(_rootOctalCode.get(), nodeOctalCode, childIndex); - // if we're under the root, then we can't be under any of the endpoints - if (isInJurisdiction) { - for (size_t i = 0; i < _endNodes.size(); i++) { - bool isUnderEndNode = isAncestorOf(_endNodes[i].get(), nodeOctalCode); - if (isUnderEndNode) { - isInJurisdiction = false; - break; - } - } - } - return isInJurisdiction ? WITHIN : BELOW; -} - - -bool JurisdictionMap::readFromFile(const char* filename) { - QString settingsFile(filename); - QSettings settings(settingsFile, QSettings::IniFormat); - QString rootCode = settings.value("root","00").toString(); - qCDebug(octree) << "rootCode=" << rootCode; - - std::lock_guard lock(_octalCodeMutex); - _rootOctalCode = hexStringToOctalCode(rootCode); - printOctalCode(_rootOctalCode.get()); - - settings.beginGroup("endNodes"); - const QStringList childKeys = settings.childKeys(); - QHash values; - foreach (const QString &childKey, childKeys) { - QString childValue = settings.value(childKey).toString(); - values.insert(childKey, childValue); - qCDebug(octree) << childKey << "=" << childValue; - - auto octcode = hexStringToOctalCode(childValue); - printOctalCode(octcode.get()); - - _endNodes.push_back(octcode); - } - settings.endGroup(); - return true; -} - -void JurisdictionMap::displayDebugDetails() const { - std::lock_guard lock(_octalCodeMutex); - - QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get()); - - qCDebug(octree) << "root:" << rootNodeValue; - - for (size_t i = 0; i < _endNodes.size(); i++) { - QString value = octalCodeToHexString(_endNodes[i].get()); - qCDebug(octree) << "End node[" << i << "]: " << rootNodeValue; - } -} - - -bool JurisdictionMap::writeToFile(const char* filename) { - QString settingsFile(filename); - QSettings settings(settingsFile, QSettings::IniFormat); - - std::lock_guard lock(_octalCodeMutex); - - QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get()); - - settings.setValue("root", rootNodeValue); - - settings.beginGroup("endNodes"); - for (size_t i = 0; i < _endNodes.size(); i++) { - QString key = QString("endnode%1").arg(i); - QString value = octalCodeToHexString(_endNodes[i].get()); - settings.setValue(key, value); - } - settings.endGroup(); - return true; -} - -std::unique_ptr JurisdictionMap::packEmptyJurisdictionIntoMessage(NodeType_t type) { - int bytes = 0; - auto packet = NLPacket::create(PacketType::Jurisdiction, sizeof(type) + sizeof(bytes)); - - // Pack the Node Type in first byte - packet->writePrimitive(type); - // No root or end node details to pack! - packet->writePrimitive(bytes); - - return packet; // includes header! -} - -std::unique_ptr JurisdictionMap::packIntoPacket() { - auto packet = NLPacket::create(PacketType::Jurisdiction); - - // Pack the Node Type in first byte - NodeType_t type = getNodeType(); - packet->writePrimitive(type); - - // add the root jurisdiction - std::lock_guard lock(_octalCodeMutex); - if (_rootOctalCode) { - size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_rootOctalCode.get())); - // No root or end node details to pack! - packet->writePrimitive(bytes); - packet->write(reinterpret_cast(_rootOctalCode.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end nodes - int endNodeCount = (int)_endNodes.size(); - packet->writePrimitive(endNodeCount); - - for (int i=0; i < endNodeCount; i++) { - auto endNodeCode = _endNodes[i].get(); - size_t bytes = 0; - if (endNodeCode) { - bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode)); - } - packet->writePrimitive(bytes); - packet->write(reinterpret_cast(endNodeCode), bytes); - } - } else { - int bytes = 0; - packet->writePrimitive(bytes); - } - - return packet; -} - -int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) { - // read the root jurisdiction - int bytes = 0; - message.readPrimitive(&bytes); - - std::lock_guard lock(_octalCodeMutex); - _rootOctalCode = nullptr; - _endNodes.clear(); - - if (bytes > 0 && bytes <= message.getBytesLeftToRead()) { - _rootOctalCode = createOctalCodePtr(bytes); - message.read(reinterpret_cast(_rootOctalCode.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end nodes - int endNodeCount = 0; - message.readPrimitive(&endNodeCount); - - for (int i = 0; i < endNodeCount; i++) { - int bytes = 0; - message.readPrimitive(&bytes); - - if (bytes <= message.getBytesLeftToRead()) { - auto endNodeCode = createOctalCodePtr(bytes); - message.read(reinterpret_cast(endNodeCode.get()), bytes); - - // if the endNodeCode was 0 length then don't add it - if (bytes > 0) { - _endNodes.push_back(endNodeCode); - } - } - } - } - - return message.getPosition(); // excludes header -} diff --git a/libraries/octree/src/JurisdictionMap.h b/libraries/octree/src/JurisdictionMap.h deleted file mode 100644 index b5a311c3d9..0000000000 --- a/libraries/octree/src/JurisdictionMap.h +++ /dev/null @@ -1,88 +0,0 @@ -// -// JurisdictionMap.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/1/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_JurisdictionMap_h -#define hifi_JurisdictionMap_h - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -class JurisdictionMap { -public: - enum Area { - ABOVE, - WITHIN, - BELOW - }; - - // standard constructors - JurisdictionMap(NodeType_t type = NodeType::EntityServer); // default constructor - JurisdictionMap(const JurisdictionMap& other); // copy constructor - - // standard assignment - JurisdictionMap& operator=(const JurisdictionMap& other); // copy assignment - - // application constructors - JurisdictionMap(const char* filename); - JurisdictionMap(const char* rootHextString, const char* endNodesHextString); - - ~JurisdictionMap(); - - Area isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const; - - bool writeToFile(const char* filename); - bool readFromFile(const char* filename); - - // Provide an atomic way to get both the rootOctalCode and endNodeOctalCodes. - std::tuple getRootAndEndNodeOctalCodes() const; - OctalCodePtr getRootOctalCode() const; - OctalCodePtrList getEndNodeOctalCodes() const; - - void copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn); - - int unpackFromPacket(ReceivedMessage& message); - std::unique_ptr packIntoPacket(); - - /// Available to pack an empty or unknown jurisdiction into a network packet, used when no JurisdictionMap is available - static std::unique_ptr packEmptyJurisdictionIntoMessage(NodeType_t type); - - void displayDebugDetails() const; - - NodeType_t getNodeType() const { return _nodeType; } - void setNodeType(NodeType_t type) { _nodeType = type; } - -private: - void copyContents(const JurisdictionMap& other); // use assignment instead - void init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes); - - mutable std::mutex _octalCodeMutex; - OctalCodePtr _rootOctalCode { nullptr }; - OctalCodePtrList _endNodes; - NodeType_t _nodeType; -}; - -/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are -/// managing which jurisdictions. -class NodeToJurisdictionMap : public QMap, public ReadWriteLockable {}; -typedef QMap::iterator NodeToJurisdictionMapIterator; - - -#endif // hifi_JurisdictionMap_h diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp deleted file mode 100644 index dfe1a6d872..0000000000 --- a/libraries/octree/src/JurisdictionSender.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// JurisdictionSender.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include -#include -#include -#include "JurisdictionSender.h" - - -JurisdictionSender::JurisdictionSender(JurisdictionMap* map, NodeType_t type) : - ReceivedPacketProcessor(), - _jurisdictionMap(map), - _nodeType(type), - _packetSender(JurisdictionSender::DEFAULT_PACKETS_PER_SECOND) -{ -} - -JurisdictionSender::~JurisdictionSender() { -} - -void JurisdictionSender::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { - if (message->getType() == PacketType::JurisdictionRequest) { - lockRequestingNodes(); - _nodesRequestingJurisdictions.push(sendingNode->getUUID()); - unlockRequestingNodes(); - } -} - -bool JurisdictionSender::process() { - bool continueProcessing = isStillRunning(); - - // call our ReceivedPacketProcessor base class process so we'll get any pending packets - if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) { - int nodeCount = 0; - - lockRequestingNodes(); - while (!_nodesRequestingJurisdictions.empty()) { - - QUuid nodeUUID = _nodesRequestingJurisdictions.front(); - _nodesRequestingJurisdictions.pop(); - SharedNodePointer node = DependencyManager::get()->nodeWithUUID(nodeUUID); - - if (node && node->getActiveSocket()) { - auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket() - : JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType()); - _packetSender.queuePacketForSending(node, std::move(packet)); - nodeCount++; - } - } - unlockRequestingNodes(); - - // set our packets per second to be the number of nodes - _packetSender.setPacketsPerSecond(nodeCount); - - continueProcessing = _packetSender.process(); - } - return continueProcessing; -} diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h deleted file mode 100644 index b2d738cd36..0000000000 --- a/libraries/octree/src/JurisdictionSender.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// JurisdictionSender.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_JurisdictionSender_h -#define hifi_JurisdictionSender_h - -#include -#include - -#include -#include -#include "JurisdictionMap.h" - -/// Will process PacketType::_JURISDICTION_REQUEST packets and send out PacketType::_JURISDICTION packets -/// to requesting parties. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets -/// and adding them to the processing queue by calling queueReceivedPacket() -class JurisdictionSender : public ReceivedPacketProcessor { - Q_OBJECT -public: - static const int DEFAULT_PACKETS_PER_SECOND = 1; - - JurisdictionSender(JurisdictionMap* map, NodeType_t type = NodeType::EntityServer); - ~JurisdictionSender(); - - void setJurisdiction(JurisdictionMap* map) { _jurisdictionMap = map; } - - virtual bool process() override; - - NodeType_t getNodeType() const { return _nodeType; } - void setNodeType(NodeType_t type) { _nodeType = type; } - -protected: - virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; - - /// Locks all the resources of the thread. - void lockRequestingNodes() { _requestingNodeMutex.lock(); } - - /// Unlocks all the resources of the thread. - void unlockRequestingNodes() { _requestingNodeMutex.unlock(); } - - -private: - QMutex _requestingNodeMutex; - JurisdictionMap* _jurisdictionMap; - std::queue _nodesRequestingJurisdictions; - NodeType_t _nodeType; - - PacketSender _packetSender; -}; -#endif // hifi_JurisdictionSender_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3190f25d7e..c63ff2f560 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1020,16 +1020,6 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, return bytesAtThisLevel; } - // If we've been provided a jurisdiction map, then we need to honor it. - if (params.jurisdictionMap) { - // here's how it works... if we're currently above our root jurisdiction, then we proceed normally. - // but once we're in our own jurisdiction, then we need to make sure we're not below it. - if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), CHECK_NODE_ONLY)) { - params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION; - return bytesAtThisLevel; - } - } - ViewFrustum::intersection nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything) { float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, @@ -1152,18 +1142,9 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElementPointer childElement = element->getChildAtIndex(i); - // if the caller wants to include childExistsBits, then include them even if not in view, if however, - // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist - // even if they don't in our local tree - bool notMyJurisdiction = false; - if (params.jurisdictionMap) { - notMyJurisdiction = JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), i); - } - if (params.includeExistsBits) { - // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing - if (childElement || notMyJurisdiction) { - childrenExistInTreeBits += (1 << (7 - i)); - } + // if the caller wants to include childExistsBits, then include them + if (params.includeExistsBits && childElement) { + childrenExistInTreeBits += (1 << (7 - i)); } sortedChildren[i] = childElement; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index ec6a0e810d..1648cb0f47 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -24,7 +24,6 @@ #include #include -#include "JurisdictionMap.h" #include "OctreeElement.h" #include "OctreeElementBag.h" #include "OctreePacketData.h" @@ -62,7 +61,6 @@ const int NO_BOUNDARY_ADJUST = 0; const int LOW_RES_MOVING_ADJUST = 1; #define IGNORE_COVERAGE_MAP NULL -#define IGNORE_JURISDICTION_MAP NULL class EncodeBitstreamParams { public: @@ -77,7 +75,6 @@ public: int boundaryLevelAdjust; float octreeElementSizeScale; bool forceSendScene; - JurisdictionMap* jurisdictionMap; NodeData* nodeData; // output hints from the encode process @@ -87,7 +84,6 @@ public: NULL_NODE, NULL_NODE_DATA, TOO_DEEP, - OUT_OF_JURISDICTION, LOD_SKIP, OUT_OF_VIEW, WAS_IN_VIEW, @@ -105,7 +101,6 @@ public: int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, bool forceSendScene = true, - JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP, NodeData* nodeData = nullptr) : maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), @@ -115,7 +110,6 @@ public: boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), forceSendScene(forceSendScene), - jurisdictionMap(jurisdictionMap), nodeData(nodeData), stopReason(UNKNOWN) { @@ -131,7 +125,6 @@ public: case DIDNT_FIT: qDebug("DIDNT_FIT"); break; case NULL_NODE: qDebug("NULL_NODE"); break; case TOO_DEEP: qDebug("TOO_DEEP"); break; - case OUT_OF_JURISDICTION: qDebug("OUT_OF_JURISDICTION"); break; case LOD_SKIP: qDebug("LOD_SKIP"); break; case OUT_OF_VIEW: qDebug("OUT_OF_VIEW"); break; case WAS_IN_VIEW: qDebug("WAS_IN_VIEW"); break; @@ -148,7 +141,6 @@ public: case DIDNT_FIT: return QString("DIDNT_FIT"); break; case NULL_NODE: return QString("NULL_NODE"); break; case TOO_DEEP: return QString("TOO_DEEP"); break; - case OUT_OF_JURISDICTION: return QString("OUT_OF_JURISDICTION"); break; case LOD_SKIP: return QString("LOD_SKIP"); break; case OUT_OF_VIEW: return QString("OUT_OF_VIEW"); break; case WAS_IN_VIEW: return QString("WAS_IN_VIEW"); break; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 7e46831faa..4f10c9bf79 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -22,13 +22,10 @@ const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::D OctreeEditPacketSender::OctreeEditPacketSender() : - PacketSender(), _shouldSend(true), _maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES), - _releaseQueuedMessagesPending(false), - _serverJurisdictions(NULL) + _releaseQueuedMessagesPending(false) { - } OctreeEditPacketSender::~OctreeEditPacketSender() { @@ -40,34 +37,8 @@ OctreeEditPacketSender::~OctreeEditPacketSender() { bool OctreeEditPacketSender::serversExist() const { - bool hasServers = false; - bool atLeastOneJurisdictionMissing = false; // assume the best - - DependencyManager::get()->eachNodeBreakable([&](const SharedNodePointer& node){ - if (node->getType() == getMyNodeType() && node->getActiveSocket()) { - - QUuid nodeUUID = node->getUUID(); - // If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server - if (_serverJurisdictions) { - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're - // missing at least one jurisdiction - _serverJurisdictions->withReadLock([&] { - if ((*_serverJurisdictions).find(nodeUUID) == (*_serverJurisdictions).end()) { - atLeastOneJurisdictionMissing = true; - } - }); - } - hasServers = true; - } - - if (atLeastOneJurisdictionMissing) { - return false; // no point in looking further - return false from anonymous function - } else { - return true; - } - }); - - return (hasServers && !atLeastOneJurisdictionMissing); + auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); + return node && node->getActiveSocket(); } // This method is called when the edit packet layer has determined that it has a fully formed packet destined for @@ -132,7 +103,7 @@ void OctreeEditPacketSender::queuePacketListToNode(const QUuid& nodeUUID, std::u } void OctreeEditPacketSender::processPreServerExistsPackets() { - assert(serversExist()); // we should only be here if we have jurisdictions + assert(serversExist()); // we should only be here if we have servers // First send out all the single message packets... _pendingPacketsLock.lock(); @@ -150,7 +121,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { _pendingPacketsLock.unlock(); - // if while waiting for the jurisdictions the caller called releaseQueuedMessages() + // if while waiting for the servers the caller called releaseQueuedMessages() // then we want to honor that request now. if (_releaseQueuedMessagesPending) { releaseQueuedMessages(); @@ -178,34 +149,12 @@ void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr packet return; // bail early } - assert(serversExist()); // we must have jurisdictions to be here!! + assert(serversExist()); // we must have servers to be here!! - const unsigned char* octCode = reinterpret_cast(packet->getPayload()) + sizeof(short) + sizeof(quint64); - - // We want to filter out edit messages for servers based on the server's Jurisdiction - // But we can't really do that with a packed message, since each edit message could be destined - // for a different server... So we need to actually manage multiple queued packets... one - // for each server - - DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are getMyNodeType() - if (node->getActiveSocket() && node->getType() == getMyNodeType()) { - QUuid nodeUUID = node->getUUID(); - bool isMyJurisdiction = true; - // we need to get the jurisdiction for this - // here we need to get the "pending packet" for this server - _serverJurisdictions->withReadLock([&] { - const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; - isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); - }); - - if (isMyJurisdiction) { - // make a copy of this packet for this node and queue - auto packetCopy = NLPacket::createCopy(*packet); - queuePacketToNode(nodeUUID, std::move(packetCopy)); - } - } - }); + auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); + if (node && node->getActiveSocket()) { + queuePacketToNode(node->getUUID(), std::move(packet)); + } } @@ -216,8 +165,8 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& return; // bail early } - // If we don't have jurisdictions, then we will simply queue up all of these packets and wait till we have - // jurisdictions for processing + // If we don't have servers, then we will simply queue up all of these packets and wait till we have + // servers for processing if (!serversExist()) { if (_maxPendingMessages > 0) { EditMessagePair messagePair { type, QByteArray(editMessage) }; @@ -235,107 +184,80 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& return; // bail early } - // We want to filter out edit messages for servers based on the server's Jurisdiction - // But we can't really do that with a packed message, since each edit message could be destined - // for a different server... So we need to actually manage multiple queued packets... one - // for each server _packetsQueueLock.lock(); - DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are getMyNodeType() - if (node->getActiveSocket() && node->getType() == getMyNodeType()) { - QUuid nodeUUID = node->getUUID(); - bool isMyJurisdiction = true; + auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); + if (node && node->getActiveSocket()) { + QUuid nodeUUID = node->getUUID(); - if (type == PacketType::EntityErase) { - isMyJurisdiction = true; // send erase messages to all servers - } else if (_serverJurisdictions) { - // we need to get the jurisdiction for this - // here we need to get the "pending packet" for this server - _serverJurisdictions->withReadLock([&] { - if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { - const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; - isMyJurisdiction = (map.isMyJurisdiction(reinterpret_cast(editMessage.data()), - CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); - } else { - isMyJurisdiction = false; - } - }); + // for edit messages, we will attempt to combine multiple edit commands where possible, we + // don't do this for add because we send those reliably + if (type == PacketType::EntityAdd) { + auto newPacket = NLPacketList::create(type, QByteArray(), true, true); + auto nodeClockSkew = node->getClockSkewUsec(); + + // pack sequence number + quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; + newPacket->writePrimitive(sequence); + + // pack in timestamp + quint64 now = usecTimestampNow() + nodeClockSkew; + newPacket->writePrimitive(now); + + + // We call this virtual function that allows our specific type of EditPacketSender to + // fixup the buffer for any clock skew + if (nodeClockSkew != 0) { + adjustEditPacketForClockSkew(type, editMessage, nodeClockSkew); } - if (isMyJurisdiction) { - // for edit messages, we will attempt to combine multiple edit commands where possible, we - // don't do this for add because we send those reliably - if (type == PacketType::EntityAdd) { + newPacket->write(editMessage); - auto newPacket = NLPacketList::create(type, QByteArray(), true, true); - auto nodeClockSkew = node->getClockSkewUsec(); + // release the new packet + releaseQueuedPacketList(nodeUUID, std::move(newPacket)); - // pack sequence number - quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; - newPacket->writePrimitive(sequence); + // tell the sent packet history that we used a sequence number for an untracked packet + auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; + sentPacketHistory.untrackedPacketSent(sequence); + } else { + // only a NLPacket for now + std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; - // pack in timestamp - quint64 now = usecTimestampNow() + nodeClockSkew; - newPacket->writePrimitive(now); + if (!bufferedPacket) { + bufferedPacket = initializePacket(type, node->getClockSkewUsec()); + } else { + // If we're switching type, then we send the last one and start over + if ((type != bufferedPacket->getType() && bufferedPacket->getPayloadSize() > 0) || + (editMessage.size() >= bufferedPacket->bytesAvailableForWrite())) { + // create the new packet and swap it with the packet in _pendingEditPackets + auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); + bufferedPacket.swap(packetToRelease); - // We call this virtual function that allows our specific type of EditPacketSender to - // fixup the buffer for any clock skew - if (nodeClockSkew != 0) { - adjustEditPacketForClockSkew(type, editMessage, nodeClockSkew); - } - - newPacket->write(editMessage); - - // release the new packet - releaseQueuedPacketList(nodeUUID, std::move(newPacket)); - - // tell the sent packet history that we used a sequence number for an untracked packet - auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; - sentPacketHistory.untrackedPacketSent(sequence); - } else { - - std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now - - if (!bufferedPacket) { - bufferedPacket = initializePacket(type, node->getClockSkewUsec()); - } else { - // If we're switching type, then we send the last one and start over - if ((type != bufferedPacket->getType() && bufferedPacket->getPayloadSize() > 0) || - (editMessage.size() >= bufferedPacket->bytesAvailableForWrite())) { - - // create the new packet and swap it with the packet in _pendingEditPackets - auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); - bufferedPacket.swap(packetToRelease); - - // release the previously buffered packet - releaseQueuedPacket(nodeUUID, std::move(packetToRelease)); - } - } - - // This is really the first time we know which server/node this particular edit message - // is going to, so we couldn't adjust for clock skew till now. But here's our chance. - // We call this virtual function that allows our specific type of EditPacketSender to - // fixup the buffer for any clock skew - if (node->getClockSkewUsec() != 0) { - adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); - } - - bufferedPacket->write(editMessage); - + // release the previously buffered packet + releaseQueuedPacket(nodeUUID, std::move(packetToRelease)); } } + + // This is really the first time we know which server/node this particular edit message + // is going to, so we couldn't adjust for clock skew till now. But here's our chance. + // We call this virtual function that allows our specific type of EditPacketSender to + // fixup the buffer for any clock skew + if (node->getClockSkewUsec() != 0) { + adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); + } + + bufferedPacket->write(editMessage); } - }); + } _packetsQueueLock.unlock(); } void OctreeEditPacketSender::releaseQueuedMessages() { - // if we don't yet have jurisdictions then we can't actually release messages yet because we don't - // know where to send them to. Instead, just remember this request and when we eventually get jurisdictions + // if we don't yet have servers then we can't actually release messages yet because we don't + // know where to send them to. Instead, just remember this request and when we eventually get servers // call release again at that time. if (!serversExist()) { _releaseQueuedMessagesPending = true; @@ -397,8 +319,8 @@ std::unique_ptr OctreeEditPacketSender::initializePacket(PacketType ty } bool OctreeEditPacketSender::process() { - // if we have server jurisdiction details, and we have pending pre-jurisdiction packets, then process those - // before doing our normal process step. This processPreJurisdictionPackets() + // if we have servers, and we have pending pre-servers exist packets, then process those + // before doing our normal process step. This processPreServerExistPackets() if (serversExist() && (!_preServerEdits.empty() || !_preServerSingleMessagePackets.empty() )) { processPreServerExistsPackets(); } diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 79c363bec5..8a33eb8b73 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -17,7 +17,6 @@ #include #include -#include "JurisdictionMap.h" #include "SentPacketHistory.h" /// Utility for processing, packing, queueing and sending of outbound edit messages. @@ -49,14 +48,6 @@ public: /// in an application like interface when all octree features are disabled. void setShouldSend(bool shouldSend) { _shouldSend = shouldSend; } - /// call this to inform the OctreeEditPacketSender of the server jurisdictions. This is required for normal operation. - /// The internal contents of the jurisdiction map may change throughout the lifetime of the OctreeEditPacketSender. This map - /// can be set prior to servers being present, so long as the contents of the map accurately reflect the current - /// known jurisdictions. - void setServerJurisdictions(NodeToJurisdictionMap* serverJurisdictions) { - _serverJurisdictions = serverJurisdictions; - } - /// if you're running in non-threaded mode, you must call this method regularly virtual bool process() override; @@ -108,8 +99,6 @@ protected: std::list _preServerEdits; // these will get packed into other larger packets std::list> _preServerSingleMessagePackets; // these will go out as is - NodeToJurisdictionMap* _serverJurisdictions; - QMutex _releaseQueuedPacketMutex; // TODO: add locks for this and _pendingEditPackets diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 09b2d6ddf5..054603440d 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -37,15 +37,13 @@ OctreeSceneStats::OctreeSceneStats() : _incomingBytes(0), _incomingWastedBytes(0), _incomingOctreeSequenceNumberStats(), - _incomingFlightTimeAverage(samples), - _jurisdictionRoot(NULL) + _incomingFlightTimeAverage(samples) { reset(); } // copy constructor -OctreeSceneStats::OctreeSceneStats(const OctreeSceneStats& other) : -_jurisdictionRoot(NULL) { +OctreeSceneStats::OctreeSceneStats(const OctreeSceneStats& other) { copyFromOther(other); } @@ -109,26 +107,6 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _existsInPacketBitsWritten = other._existsInPacketBitsWritten; _treesRemoved = other._treesRemoved; - // before copying the jurisdictions, delete any current values... - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - - // Now copy the values from the other - if (other._jurisdictionRoot) { - auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot.get())); - _jurisdictionRoot = createOctalCodePtr(bytes); - memcpy(_jurisdictionRoot.get(), other._jurisdictionRoot.get(), bytes); - } - for (size_t i = 0; i < other._jurisdictionEndNodes.size(); i++) { - auto& endNodeCode = other._jurisdictionEndNodes[i]; - if (endNodeCode) { - auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get())); - auto endNodeCodeCopy = createOctalCodePtr(bytes); - memcpy(endNodeCodeCopy.get(), endNodeCode.get(), bytes); - _jurisdictionEndNodes.push_back(endNodeCodeCopy); - } - } - _incomingPacket = other._incomingPacket; _incomingBytes = other._incomingBytes; _incomingWastedBytes = other._incomingWastedBytes; @@ -141,8 +119,7 @@ OctreeSceneStats::~OctreeSceneStats() { reset(); } -void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const OctreeElementPointer& root, - JurisdictionMap* jurisdictionMap) { +void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const OctreeElementPointer& root) { reset(); // resets packet and octree stats _isStarted = true; _start = usecTimestampNow(); @@ -153,14 +130,6 @@ void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const Octre _isFullScene = isFullScene; _isMoving = isMoving; - - // setup jurisdictions - if (jurisdictionMap) { - std::tie(_jurisdictionRoot, _jurisdictionEndNodes) = jurisdictionMap->getRootAndEndNodeOctalCodes(); - } else { - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - } } void OctreeSceneStats::sceneCompleted() { @@ -236,9 +205,6 @@ void OctreeSceneStats::reset() { _existsBitsWritten = 0; _existsInPacketBitsWritten = 0; _treesRemoved = 0; - - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); } void OctreeSceneStats::packetSent(int bytes) { @@ -374,29 +340,6 @@ int OctreeSceneStats::packIntoPacket() { _statsPacket->writePrimitive(_existsInPacketBitsWritten); _statsPacket->writePrimitive(_treesRemoved); - // add the root jurisdiction - if (_jurisdictionRoot) { - // copy the - int bytes = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot.get())); - _statsPacket->writePrimitive(bytes); - _statsPacket->write(reinterpret_cast(_jurisdictionRoot.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end elements - int endNodeCount = (int)_jurisdictionEndNodes.size(); - - _statsPacket->writePrimitive(endNodeCount); - - for (int i=0; i < endNodeCount; i++) { - auto& endNodeCode = _jurisdictionEndNodes[i]; - auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get())); - _statsPacket->writePrimitive(bytes); - _statsPacket->write(reinterpret_cast(endNodeCode.get()), bytes); - } - } else { - int bytes = 0; - _statsPacket->writePrimitive(bytes); - } - return _statsPacket->getPayloadSize(); } @@ -458,38 +401,6 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) { packet.readPrimitive(&_existsBitsWritten); packet.readPrimitive(&_existsInPacketBitsWritten); packet.readPrimitive(&_treesRemoved); - // before allocating new juridiction, clean up existing ones - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - - // read the root jurisdiction - int bytes = 0; - packet.readPrimitive(&bytes); - - if (bytes == 0) { - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - } else { - _jurisdictionRoot = createOctalCodePtr(bytes); - packet.read(reinterpret_cast(_jurisdictionRoot.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end elements - _jurisdictionEndNodes.clear(); - - int endNodeCount = 0; - packet.readPrimitive(&endNodeCount); - - for (int i=0; i < endNodeCount; i++) { - int bytes = 0; - - packet.readPrimitive(&bytes); - - auto endNodeCode = createOctalCodePtr(bytes); - packet.read(reinterpret_cast(endNodeCode.get()), bytes); - - _jurisdictionEndNodes.push_back(endNodeCode); - } - } // running averages _elapsedAverage.updateAverage((float)_elapsed); diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index 3774d4287d..78b4dfd26f 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -17,7 +17,6 @@ #include #include -#include "JurisdictionMap.h" #include "OctreePacketData.h" #include "SequenceNumberStats.h" #include "OctalCode.h" @@ -39,7 +38,7 @@ public: OctreeSceneStats& operator= (const OctreeSceneStats& other); // copy assignment /// Call when beginning the computation of a scene. Initializes internal structures - void sceneStarted(bool fullScene, bool moving, const OctreeElementPointer& root, JurisdictionMap* jurisdictionMap); + void sceneStarted(bool fullScene, bool moving, const OctreeElementPointer& root); bool getIsSceneStarted() const { return _isStarted; } /// Call when the computation of a scene is completed. Finalizes internal structures @@ -143,12 +142,6 @@ public: /// \param Item item The item from the stats you're interested in. const char* getItemValue(Item item); - /// Returns OctCode for root element of the jurisdiction of this particular octree server - OctalCodePtr getJurisdictionRoot() const { return _jurisdictionRoot; } - - /// Returns list of OctCodes for end elements of the jurisdiction of this particular octree server - const OctalCodePtrList& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; } - bool isMoving() const { return _isMoving; } bool isFullScene() const { return _isFullScene; } quint64 getTotalElements() const { return _totalElements; } @@ -277,9 +270,6 @@ private: static ItemInfo _ITEMS[]; static const int MAX_ITEM_VALUE_LENGTH = 128; char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH]; - - OctalCodePtr _jurisdictionRoot; - std::vector _jurisdictionEndNodes; }; /// Map between element IDs and their reported OctreeSceneStats. Typically used by classes that need to know which elements sent diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 8913e88cf5..618e8ac469 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -13,12 +13,9 @@ #include "OctreeScriptingInterface.h" -OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender, - JurisdictionListener* jurisdictionListener) : +OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender) : _packetSender(packetSender), - _jurisdictionListener(jurisdictionListener), - _managedPacketSender(false), - _managedJurisdictionListener(false), + _managedPacketSender(false), _initialized(false) { } @@ -28,12 +25,6 @@ OctreeScriptingInterface::~OctreeScriptingInterface() { } void OctreeScriptingInterface::cleanupManagedObjects() { - if (_managedJurisdictionListener) { - _jurisdictionListener->terminate(); - _jurisdictionListener->deleteLater(); - _managedJurisdictionListener = false; - _jurisdictionListener = NULL; - } if (_managedPacketSender) { _packetSender->terminate(); _packetSender->deleteLater(); @@ -46,29 +37,16 @@ void OctreeScriptingInterface::setPacketSender(OctreeEditPacketSender* packetSen _packetSender = packetSender; } -void OctreeScriptingInterface::setJurisdictionListener(JurisdictionListener* jurisdictionListener) { - _jurisdictionListener = jurisdictionListener; -} - void OctreeScriptingInterface::init() { if (_initialized) { return; } - if (_jurisdictionListener) { - _managedJurisdictionListener = false; - } else { - _managedJurisdictionListener = true; - _jurisdictionListener = new JurisdictionListener(getServerNodeType()); - _jurisdictionListener->initialize(true); - } - if (_packetSender) { _managedPacketSender = false; } else { _managedPacketSender = true; _packetSender = createPacketSender(); - _packetSender->setServerJurisdictions(_jurisdictionListener->getJurisdictions()); } if (QCoreApplication::instance()) { diff --git a/libraries/octree/src/OctreeScriptingInterface.h b/libraries/octree/src/OctreeScriptingInterface.h index 86b9730393..c31da94532 100644 --- a/libraries/octree/src/OctreeScriptingInterface.h +++ b/libraries/octree/src/OctreeScriptingInterface.h @@ -14,21 +14,18 @@ #include -#include "JurisdictionListener.h" #include "OctreeEditPacketSender.h" /// handles scripting of Particle commands from JS passed to assigned clients class OctreeScriptingInterface : public QObject { Q_OBJECT public: - OctreeScriptingInterface(OctreeEditPacketSender* packetSender = NULL, JurisdictionListener* jurisdictionListener = NULL); + OctreeScriptingInterface(OctreeEditPacketSender* packetSender = nullptr); ~OctreeScriptingInterface(); OctreeEditPacketSender* getPacketSender() const { return _packetSender; } - JurisdictionListener* getJurisdictionListener() const { return _jurisdictionListener; } void setPacketSender(OctreeEditPacketSender* packetSender); - void setJurisdictionListener(JurisdictionListener* jurisdictionListener); void init(); virtual NodeType_t getServerNodeType() const = 0; @@ -86,9 +83,7 @@ public slots: protected: /// attached OctreeEditPacketSender that handles queuing and sending of packets to VS OctreeEditPacketSender* _packetSender = nullptr; - JurisdictionListener* _jurisdictionListener = nullptr; bool _managedPacketSender; - bool _managedJurisdictionListener; bool _initialized; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7717ceda6f..b91f4dd405 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -594,47 +594,72 @@ void Model::calculateTriangleSets() { } } -void Model::setVisibleInScene(bool newValue, const render::ScenePointer& scene) { - if (_isVisible != newValue) { - _isVisible = newValue; +void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) { + if (_isVisible != isVisible) { + _isVisible = isVisible; + + bool isLayeredInFront = _isLayeredInFront; + bool isLayeredInHUD = _isLayeredInHUD; render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.resetItem(item, _collisionRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + }); } scene->enqueueTransaction(transaction); } } -void Model::setLayeredInFront(bool layered, const render::ScenePointer& scene) { - if (_isLayeredInFront != layered) { - _isLayeredInFront = layered; +void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { + if (_isLayeredInFront != isLayeredInFront) { + _isLayeredInFront = isLayeredInFront; + + bool isVisible = _isVisible; + bool isLayeredInHUD = _isLayeredInHUD; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.resetItem(item, _collisionRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } scene->enqueueTransaction(transaction); } } -void Model::setLayeredInHUD(bool layered, const render::ScenePointer& scene) { - if (_isLayeredInHUD != layered) { - _isLayeredInHUD = layered; +void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene) { + if (_isLayeredInHUD != isLayeredInHUD) { + _isLayeredInHUD = isLayeredInHUD; + + bool isVisible = _isVisible; + bool isLayeredInFront = _isLayeredInFront; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.resetItem(item, _collisionRenderItemsMap[item]); + transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { + data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); + data.setLayer(isLayeredInFront, isLayeredInHUD); + }); } scene->enqueueTransaction(transaction); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 50ccb22131..4df7faac84 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,9 +82,9 @@ public: const QUrl& getURL() const { return _url; } // new Scene/Engine rendering support - void setVisibleInScene(bool newValue, const render::ScenePointer& scene); - void setLayeredInFront(bool layered, const render::ScenePointer& scene); - void setLayeredInHUD(bool layered, const render::ScenePointer& scene); + void setVisibleInScene(bool isVisible, const render::ScenePointer& scene); + void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); + void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; bool needsReload() const { return _needsReload; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 0e793fef21..c69ec1ce84 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -92,8 +92,48 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) { endResetModel(); } +TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) { +} + +int TabletButtonsProxyModel::pageIndex() const { + return _pageIndex; +} + +int TabletButtonsProxyModel::buttonIndex(const QString &uuid) { + if (!sourceModel() || _pageIndex < 0) { + return -1; + } + TabletButtonListModel* model = static_cast(sourceModel()); + for (int i = 0; i < model->rowCount(); i++) { + TabletButtonProxy* bproxy = model->data(model->index(i), ButtonProxyRole).value(); + if (bproxy && bproxy->getUuid().toString().contains(uuid)) { + return i - (_pageIndex*TabletScriptingInterface::ButtonsOnPage); + } + } + return -1; +} + +void TabletButtonsProxyModel::setPageIndex(int pageIndex) +{ + if (_pageIndex == pageIndex) + return; + + _pageIndex = pageIndex; + invalidateFilter(); + emit pageIndexChanged(_pageIndex); +} + +bool TabletButtonsProxyModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const { + Q_UNUSED(sourceParent); + return (sourceRow >= _pageIndex*TabletScriptingInterface::ButtonsOnPage + && sourceRow < (_pageIndex + 1)*TabletScriptingInterface::ButtonsOnPage); +} + TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums"); + qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletButtonsProxyModel"); } TabletScriptingInterface::~TabletScriptingInterface() { @@ -769,6 +809,7 @@ void TabletProxy::sendToQml(const QVariant& msg) { } + OffscreenQmlSurface* TabletProxy::getTabletSurface() { return _qmlOffscreenSurface; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index d24b3b6947..56e3ae257b 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,10 @@ public: enum TabletAudioEvents { ButtonClick, ButtonHover, TabletOpen, TabletHandsIn, TabletHandsOut, Last}; Q_ENUM(TabletAudioEvents) + //Different useful constants + enum TabletConstants { ButtonsColumnsOnPage = 3, ButtonsRowsOnPage = 4, ButtonsOnPage = 12 }; + Q_ENUM(TabletConstants) + TabletScriptingInterface(); virtual ~TabletScriptingInterface(); static const QString QML; @@ -118,6 +123,31 @@ protected: Q_DECLARE_METATYPE(TabletButtonListModel*); +class TabletButtonsProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + + Q_PROPERTY(int pageIndex READ pageIndex WRITE setPageIndex NOTIFY pageIndexChanged) +public: + TabletButtonsProxyModel(QObject* parent = 0); + int pageIndex() const; + Q_INVOKABLE int buttonIndex(const QString& uuid); + +public slots: + void setPageIndex(int pageIndex); + +signals: + void pageIndexChanged(int pageIndex); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + +private: + int _pageIndex { -1 }; +}; + +Q_DECLARE_METATYPE(TabletButtonsProxyModel*); + /**jsdoc * @class TabletProxy * @property name {string} READ_ONLY: name of this tablet @@ -234,6 +264,7 @@ public: QQuickItem* getQmlMenu() const; TabletButtonListModel* getButtons() { return &_buttons; } + signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index cde44e78c9..b3e3134380 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -103,6 +103,7 @@ case 'transactionHistory_linkClicked': tablet.gotoWebScreen(message.marketplaceLink, MARKETPLACES_INJECT_SCRIPT_URL); break; + case 'goToPurchases_fromWalletHome': case 'goToPurchases': tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); break; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index 2b016884f1..fb49de1050 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -29,7 +29,7 @@ var commerceMode = false; var userIsLoggedIn = false; var walletNeedsSetup = false; - var metaverseServerURL = "https://metaverse.highfidelity.com"; + var marketplaceBaseURL = "https://highfidelity.com"; function injectCommonCode(isDirectoryPage) { @@ -58,7 +58,7 @@ ); // Footer. - var isInitialHiFiPage = location.href === metaverseServerURL + "/marketplace?"; + var isInitialHiFiPage = location.href === marketplaceBaseURL + "/marketplace?"; $("body").append( '
' + (!isInitialHiFiPage ? '' : '') + @@ -70,7 +70,7 @@ // Footer actions. $("#back-button").on("click", function () { - (document.referrer !== "") ? window.history.back() : window.location = (metaverseServerURL + "/marketplace?"); + (document.referrer !== "") ? window.history.back() : window.location = (marketplaceBaseURL + "/marketplace?"); }); $("#all-markets").on("click", function () { EventBridge.emitWebEvent(GOTO_DIRECTORY); @@ -89,7 +89,7 @@ window.location = "https://clara.io/library?gameCheck=true&public=true"; }); $('#exploreHifiMarketplace').on('click', function () { - window.location = "http://www.highfidelity.com/marketplace"; + window.location = marketplaceBaseURL + "/marketplace"; }); } @@ -658,9 +658,9 @@ var HIFI_ITEM_PAGE = 3; var pageType = DIRECTORY; - if (location.href.indexOf("highfidelity.com/") !== -1) { pageType = HIFI; } + if (location.href.indexOf(marketplaceBaseURL + "/") !== -1) { pageType = HIFI; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } - if (location.href.indexOf("highfidelity.com/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } + if (location.href.indexOf(marketplaceBaseURL + "/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } injectCommonCode(pageType === DIRECTORY); switch (pageType) { @@ -694,7 +694,10 @@ commerceMode = !!parsedJsonMessage.data.commerceMode; userIsLoggedIn = !!parsedJsonMessage.data.userIsLoggedIn; walletNeedsSetup = !!parsedJsonMessage.data.walletNeedsSetup; - metaverseServerURL = parsedJsonMessage.data.metaverseServerURL; + marketplaceBaseURL = parsedJsonMessage.data.metaverseServerURL; + if (marketplaceBaseURL.indexOf('metaverse.') !== -1) { + marketplaceBaseURL = marketplaceBaseURL.replace('metaverse.', ''); + } injectCode(); } } From a89cfec71c5183344f4625ba0d39f11bc23924aa Mon Sep 17 00:00:00 2001 From: Bruce Brown <1st-BrainStormer@users.noreply.github.com> Date: Thu, 4 Jan 2018 18:20:43 -0800 Subject: [PATCH 2/2] Revert "Update (#1)" This reverts commit 7b1ac247094b67a66353be475630f3ead17f35f1. --- .gitignore | 4 +- assignment-client/src/Agent.cpp | 15 + assignment-client/src/Agent.h | 1 + .../src/octree/OctreeHeadlessViewer.cpp | 176 +++++++++- .../src/octree/OctreeHeadlessViewer.h | 4 + .../src/octree/OctreeSendThread.cpp | 5 +- assignment-client/src/octree/OctreeServer.cpp | 44 +++ assignment-client/src/octree/OctreeServer.h | 4 + .../src/octree/OctreeServerConsts.h | 1 + .../src/scripts/EntityScriptServer.cpp | 15 + .../src/scripts/EntityScriptServer.h | 1 + .../commerce/wallet/SecurityImageChange.qml | 4 +- .../qml/hifi/commerce/wallet/WalletHome.qml | 26 +- .../qml/hifi/tablet/TabletButton.qml | 22 +- .../resources/qml/hifi/tablet/TabletHome.qml | 221 +++--------- interface/resources/qml/js/Utils.jsc | Bin 0 -> 6596 bytes interface/src/Application.cpp | 204 ++++++++++- interface/src/Application.h | 5 +- .../GooglePolyScriptingInterface.cpp | 181 ---------- .../scripting/GooglePolyScriptingInterface.h | 47 --- interface/src/ui/OctreeStatsDialog.cpp | 180 +++++++--- interface/src/ui/OctreeStatsDialog.h | 35 +- interface/src/ui/OctreeStatsProvider.cpp | 229 ++++++------ interface/src/ui/OctreeStatsProvider.h | 9 +- interface/src/ui/overlays/Base3DOverlay.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 31 +- libraries/entities/src/EntityItem.h | 2 +- libraries/networking/src/LimitedNodeList.cpp | 5 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 7 +- libraries/octree/src/JurisdictionListener.cpp | 85 +++++ libraries/octree/src/JurisdictionListener.h | 60 ++++ libraries/octree/src/JurisdictionMap.cpp | 325 ++++++++++++++++++ libraries/octree/src/JurisdictionMap.h | 88 +++++ libraries/octree/src/JurisdictionSender.cpp | 68 ++++ libraries/octree/src/JurisdictionSender.h | 58 ++++ libraries/octree/src/Octree.cpp | 25 +- libraries/octree/src/Octree.h | 8 + .../octree/src/OctreeEditPacketSender.cpp | 216 ++++++++---- libraries/octree/src/OctreeEditPacketSender.h | 11 + libraries/octree/src/OctreeSceneStats.cpp | 95 ++++- libraries/octree/src/OctreeSceneStats.h | 12 +- .../octree/src/OctreeScriptingInterface.cpp | 26 +- .../octree/src/OctreeScriptingInterface.h | 7 +- libraries/render-utils/src/Model.cpp | 55 +-- libraries/render-utils/src/Model.h | 6 +- .../ui/src/ui/TabletScriptingInterface.cpp | 41 --- .../ui/src/ui/TabletScriptingInterface.h | 31 -- scripts/system/commerce/wallet.js | 1 - scripts/system/html/js/marketplacesInject.js | 17 +- 50 files changed, 1828 insertions(+), 891 deletions(-) create mode 100644 interface/resources/qml/js/Utils.jsc delete mode 100644 interface/src/scripting/GooglePolyScriptingInterface.cpp delete mode 100644 interface/src/scripting/GooglePolyScriptingInterface.h create mode 100644 libraries/octree/src/JurisdictionListener.cpp create mode 100644 libraries/octree/src/JurisdictionListener.h create mode 100644 libraries/octree/src/JurisdictionMap.cpp create mode 100644 libraries/octree/src/JurisdictionMap.h create mode 100644 libraries/octree/src/JurisdictionSender.cpp create mode 100644 libraries/octree/src/JurisdictionSender.h diff --git a/.gitignore b/.gitignore index 76ae194c82..665238e7da 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,7 @@ android/.gradle android/app/src/main/jniLibs # VSCode -# List taken from Github Global Ignores master@435c4d92 +# List taken from Github Global Ignores master@435c4d92 # https://github.com/github/gitignore/commits/master/Global/VisualStudioCode.gitignore .vscode/* !.vscode/settings.json @@ -66,7 +66,7 @@ gvr-interface/libs/* # ignore files for various dev environments TAGS *.sw[po] -*.jsc +*.qmlc # ignore QML compilation output *.qmlc diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2fc905c6fd..f166a780ff 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -94,6 +94,7 @@ Agent::Agent(ReceivedMessage& message) : packetReceiver.registerListenerForTypes( { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); + packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); @@ -148,6 +149,17 @@ void Agent::handleOctreePacket(QSharedPointer message, SharedNo } } +void Agent::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { + NodeType_t nodeType; + message->peekPrimitive(&nodeType); + + // PacketType_JURISDICTION, first byte is the node type... + if (nodeType == NodeType::EntityServer) { + DependencyManager::get()->getJurisdictionListener()-> + queueReceivedPacket(message, senderNode); + } +} + void Agent::handleAudioPacket(QSharedPointer message) { _receivedAudioStream.parseData(*message); _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); @@ -471,7 +483,10 @@ void Agent::executeScript() { auto recordingInterface = DependencyManager::get(); _scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); + // we need to make sure that init has been called for our EntityScriptingInterface + // so that it actually has a jurisdiction listener when we ask it for it next entityScriptingInterface->init(); + _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); _entityViewer.init(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 1229f06276..168da185b6 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -73,6 +73,7 @@ private slots: void handleAudioPacket(QSharedPointer message); void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); + void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); void nodeActivated(SharedNodePointer activatedNode); diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.cpp b/assignment-client/src/octree/OctreeHeadlessViewer.cpp index d3b20fb623..4e885da7a5 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.cpp +++ b/assignment-client/src/octree/OctreeHeadlessViewer.cpp @@ -23,6 +23,23 @@ void OctreeHeadlessViewer::queryOctree() { char serverType = getMyNodeType(); PacketType packetType = getMyQueryMessageType(); + NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions(); + + bool wantExtraDebugging = false; + + if (wantExtraDebugging) { + qCDebug(octree) << "OctreeHeadlessViewer::queryOctree() _jurisdictionListener=" << _jurisdictionListener; + qCDebug(octree) << "---------------"; + qCDebug(octree) << "_jurisdictionListener=" << _jurisdictionListener; + qCDebug(octree) << "Jurisdictions..."; + jurisdictions.withReadLock([&] { + for (NodeToJurisdictionMapIterator i = jurisdictions.begin(); i != jurisdictions.end(); ++i) { + qCDebug(octree) << i.key() << ": " << &i.value(); + } + }); + qCDebug(octree) << "---------------"; + } + _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); @@ -34,22 +51,159 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setOctreeSizeScale(_voxelSizeScale); _octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust); - auto nodeList = DependencyManager::get(); + // Iterate all of the nodes, and get a count of how many voxel servers we have... + int totalServers = 0; + int inViewServers = 0; + int unknownJurisdictionServers = 0; - auto node = nodeList->soloNodeOfType(serverType); - if (node && node->getActiveSocket()) { - _octreeQuery.setMaxQueryPacketsPerSecond(getMaxPacketsPerSecond()); + DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ + // only send to the NodeTypes that are serverType + if (node->getActiveSocket() && node->getType() == serverType) { + totalServers++; - auto queryPacket = NLPacket::create(packetType); + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); - // encode the query data - auto packetData = reinterpret_cast(queryPacket->getPayload()); - int packetSize = _octreeQuery.getBroadcastData(packetData); - queryPacket->setPayloadSize(packetSize); + // if we haven't heard from this voxel server, go ahead and send it a query, so we + // can get the jurisdiction... + VoxelPositionSize rootDetails; + bool foundRootDetails = false; + jurisdictions.withReadLock([&] { + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { + unknownJurisdictionServers++; + return; + } + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - // make sure we still have an active socket - nodeList->sendUnreliablePacket(*queryPacket, *node); + auto rootCode = map.getRootOctalCode(); + if (!rootCode) { + return; + } + + voxelDetailsForCode(rootCode.get(), rootDetails); + foundRootDetails = true; + }); + + if (foundRootDetails) { + AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + if ((bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds))) { + inViewServers++; + } + } + } + }); + + if (wantExtraDebugging) { + qCDebug(octree, "Servers: total %d, in view %d, unknown jurisdiction %d", + totalServers, inViewServers, unknownJurisdictionServers); } + + int perServerPPS = 0; + const int SMALL_BUDGET = 10; + int perUnknownServer = SMALL_BUDGET; + int totalPPS = getMaxPacketsPerSecond(); + + // determine PPS based on number of servers + if (inViewServers >= 1) { + // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS + // for each unknown jurisdiction server + perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); + } else { + if (unknownJurisdictionServers > 0) { + perUnknownServer = (totalPPS / unknownJurisdictionServers); + } + } + + if (wantExtraDebugging) { + qCDebug(octree, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); + } + + auto nodeList = DependencyManager::get(); + nodeList->eachNode([&](const SharedNodePointer& node){ + // only send to the NodeTypes that are serverType + if (node->getActiveSocket() && node->getType() == serverType) { + + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); + + bool inView = false; + bool unknownView = false; + + // if we haven't heard from this voxel server, go ahead and send it a query, so we + // can get the jurisdiction... + VoxelPositionSize rootDetails; + bool foundRootDetails = false; + jurisdictions.withReadLock([&] { + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { + unknownView = true; // assume it's in view + if (wantExtraDebugging) { + qCDebug(octree) << "no known jurisdiction for node " << *node << ", assume it's visible."; + } + return; + } + + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; + auto rootCode = map.getRootOctalCode(); + + if (!rootCode) { + if (wantExtraDebugging) { + qCDebug(octree) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; + } + return; + } + voxelDetailsForCode(rootCode.get(), rootDetails); + foundRootDetails = true; + }); + + if (foundRootDetails) { + AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + inView = (bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds)); + } + + if (inView) { + _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS); + if (wantExtraDebugging) { + qCDebug(octree) << "inView for node " << *node << ", give it budget of " << perServerPPS; + } + } else if (unknownView) { + if (wantExtraDebugging) { + qCDebug(octree) << "no known jurisdiction for node " << *node << ", give it budget of " + << perUnknownServer << " to send us jurisdiction."; + } + + // set the query's position/orientation to be degenerate in a manner that will get the scene quickly + // If there's only one server, then don't do this, and just let the normal voxel query pass through + // as expected... this way, we will actually get a valid scene if there is one to be seen + if (totalServers > 1) { + _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); + const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); + _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); + _octreeQuery.setCameraNearClip(0.1f); + _octreeQuery.setCameraFarClip(0.1f); + if (wantExtraDebugging) { + qCDebug(octree) << "Using 'minimal' camera position for node" << *node; + } + } else { + if (wantExtraDebugging) { + qCDebug(octree) << "Using regular camera position for node" << *node; + } + } + _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer); + } else { + _octreeQuery.setMaxQueryPacketsPerSecond(0); + } + + // setup the query packet + auto queryPacket = NLPacket::create(packetType); + + // read the data to our packet and set the payload size to fit the query + int querySize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); + queryPacket->setPayloadSize(querySize); + + // ask the NodeList to send it + nodeList->sendPacket(std::move(queryPacket), *node); + } + }); } diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.h b/assignment-client/src/octree/OctreeHeadlessViewer.h index feb8211c39..5a7544498d 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.h +++ b/assignment-client/src/octree/OctreeHeadlessViewer.h @@ -13,6 +13,7 @@ #define hifi_OctreeHeadlessViewer_h #include +#include #include @@ -22,6 +23,8 @@ class OctreeHeadlessViewer : public OctreeProcessor { public: OctreeHeadlessViewer(); virtual ~OctreeHeadlessViewer() {}; + + void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } OctreeQuery& getOctreeQuery() { return _octreeQuery; } @@ -54,6 +57,7 @@ public slots: unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); } private: + JurisdictionListener* _jurisdictionListener = nullptr; OctreeQuery _octreeQuery; ViewFrustum _viewFrustum; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index d5b9da7353..3ae653307f 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -391,7 +391,8 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData->sceneStart(usecTimestampNow() - CHANGE_FUDGE); // start tracking our stats - nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot()); + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, + _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); preStartNewScene(nodeData, isFullScene); } @@ -506,7 +507,7 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre float octreeSizeScale = nodeData->getOctreeSizeScale(); EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP, viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale, - isFullScene, nodeData); + isFullScene, _myServer->getJurisdiction(), nodeData); // Our trackSend() function is implemented by the server subclass, and will be called back as new entities/data elements are sent params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { _myServer->trackSend(dataID, dataEdited, _nodeUuid); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 42494ea7ee..c535c48dda 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -237,6 +237,8 @@ OctreeServer::OctreeServer(ReceivedMessage& message) : _debugSending(false), _debugReceiving(false), _verboseDebug(false), + _jurisdiction(NULL), + _jurisdictionSender(NULL), _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), @@ -255,6 +257,12 @@ OctreeServer::~OctreeServer() { delete[] _parsedArgV; } + if (_jurisdictionSender) { + _jurisdictionSender->terminating(); + _jurisdictionSender->terminate(); + _jurisdictionSender->deleteLater(); + } + if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); _octreeInboundPacketProcessor->terminate(); @@ -267,6 +275,9 @@ OctreeServer::~OctreeServer() { _persistThread->deleteLater(); } + delete _jurisdiction; + _jurisdiction = NULL; + // cleanup our tree here... qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; _tree.reset(); @@ -922,6 +933,10 @@ void OctreeServer::handleOctreeDataNackPacket(QSharedPointer me } } +void OctreeServer::handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { + _jurisdictionSender->queueReceivedPacket(message, senderNode); +} + void OctreeServer::handleOctreeFileReplacement(QSharedPointer message) { if (!_isFinished && !_isShuttingDown) { // these messages are only allowed to come from the domain server, so make sure that is the case @@ -1096,6 +1111,23 @@ void OctreeServer::readConfiguration() { qDebug() << "statusPort= DISABLED"; } + QString jurisdictionFile; + if (readOptionString(QString("jurisdictionFile"), settingsSectionObject, jurisdictionFile)) { + qDebug("jurisdictionFile=%s", qPrintable(jurisdictionFile)); + qDebug("about to readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile)); + _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionFile)); + qDebug("after readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile)); + } else { + QString jurisdictionRoot; + bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot); + QString jurisdictionEndNodes; + bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes); + + if (hasRoot || hasEndNodes) { + _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes)); + } + } + readOptionBool(QString("verboseDebug"), settingsSectionObject, _verboseDebug); qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug)); @@ -1209,6 +1241,7 @@ void OctreeServer::domainSettingsRequestComplete() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(getMyQueryMessageType(), this, "handleOctreeQueryPacket"); packetReceiver.registerListener(PacketType::OctreeDataNack, this, "handleOctreeDataNackPacket"); + packetReceiver.registerListener(PacketType::JurisdictionRequest, this, "handleJurisdictionRequestPacket"); packetReceiver.registerListener(PacketType::OctreeFileReplacement, this, "handleOctreeFileReplacement"); packetReceiver.registerListener(PacketType::OctreeFileReplacementFromUrl, this, "handleOctreeFileReplacementFromURL"); @@ -1332,6 +1365,13 @@ void OctreeServer::domainSettingsRequestComplete() { _persistThread->initialize(true); } + // set up our jurisdiction broadcaster... + if (_jurisdiction) { + _jurisdiction->setNodeType(getMyNodeType()); + } + _jurisdictionSender = new JurisdictionSender(_jurisdiction, getMyNodeType()); + _jurisdictionSender->initialize(true); + // set up our OctreeServerPacketProcessor _octreeInboundPacketProcessor = new OctreeInboundPacketProcessor(this); _octreeInboundPacketProcessor->initialize(true); @@ -1401,6 +1441,10 @@ void OctreeServer::aboutToFinish() { _octreeInboundPacketProcessor->terminating(); } + if (_jurisdictionSender) { + _jurisdictionSender->terminating(); + } + // Shut down all the send threads for (auto& it : _sendThreads) { auto& sendThread = *it.second; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 0eba914064..f930f299f3 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -44,6 +44,7 @@ public: bool wantsVerboseDebug() const { return _verboseDebug; } OctreePointer getOctree() { return _tree; } + JurisdictionMap* getJurisdiction() { return _jurisdiction; } int getPacketsPerClientPerInterval() const { return std::min(_packetsPerClientPerInterval, std::max(1, getPacketsTotalPerInterval() / std::max(1, getCurrentClientCount()))); } @@ -137,6 +138,7 @@ private slots: void domainSettingsRequestComplete(); void handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeFileReplacement(QSharedPointer message); void handleOctreeFileReplacementFromURL(QSharedPointer message); void removeSendThread(); @@ -188,6 +190,8 @@ protected: bool _debugReceiving; bool _debugTimestampNow; bool _verboseDebug; + JurisdictionMap* _jurisdiction; + JurisdictionSender* _jurisdictionSender; OctreeInboundPacketProcessor* _octreeInboundPacketProcessor; OctreePersistThread* _persistThread; diff --git a/assignment-client/src/octree/OctreeServerConsts.h b/assignment-client/src/octree/OctreeServerConsts.h index 2706b3ef73..30b55b8786 100644 --- a/assignment-client/src/octree/OctreeServerConsts.h +++ b/assignment-client/src/octree/OctreeServerConsts.h @@ -14,6 +14,7 @@ #include #include // for MAX_PACKET_SIZE +#include const int MAX_FILENAME_LENGTH = 1024; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index b4a6b3af93..c8067ce81f 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -79,6 +79,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); + packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); auto avatarHashMap = DependencyManager::set(); @@ -282,8 +283,11 @@ void EntityScriptServer::run() { // Setup Script Engine resetEntitiesScriptEngine(); + // we need to make sure that init has been called for our EntityScriptingInterface + // so that it actually has a jurisdiction listener when we ask it for it next auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); + _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); _entityViewer.init(); @@ -562,6 +566,17 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer mess } } +void EntityScriptServer::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { + NodeType_t nodeType; + message->peekPrimitive(&nodeType); + + // PacketType_JURISDICTION, first byte is the node type... + if (nodeType == NodeType::EntityServer) { + DependencyManager::get()->getJurisdictionListener()-> + queueReceivedPacket(message, senderNode); + } +} + void EntityScriptServer::aboutToFinish() { shutdownScriptEngine(); diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 9c6c4c752e..f9c5e921f0 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -41,6 +41,7 @@ public slots: private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); + void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); void handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode); diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index 2ad2b75553..b261743434 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -66,7 +66,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - Commerce.getSecurityImage(); + commerce.getSecurityImage(); } } Item { @@ -194,7 +194,7 @@ Item { securityImageSubmitButton.text = "Submitting..."; securityImageSubmitButton.enabled = false; var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - Commerce.chooseSecurityImage(securityImagePath); + commerce.chooseSecurityImage(securityImagePath); } } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 42ee44d584..5a5eeeb91f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -197,36 +197,14 @@ Item { anchors.topMargin: 26; anchors.left: parent.left; anchors.leftMargin: 20; - width: paintedWidth; + anchors.right: parent.right; + anchors.rightMargin: 30; height: 30; // Text size size: 22; // Style color: hifi.colors.baseGrayHighlight; } - - RalewaySemiBold { - id: myPurchasesLink; - text: 'My Purchases'; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 26; - anchors.right: parent.right; - anchors.rightMargin: 20; - width: paintedWidth; - height: 30; - y: 4; - // Text size - size: 18; - // Style - color: hifi.colors.baseGrayHighlight; - horizontalAlignment: Text.AlignRight; - - onLinkActivated: { - sendSignalToWallet({method: 'goToPurchases_fromWalletHome'}); - } - } - ListModel { id: tempTransactionHistoryModel; } diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 4d443fb97c..1508367318 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -23,26 +23,11 @@ Item { property double sortOrder: 100 property int stableOrder: 0 property var tabletRoot; - property var flickable: null - property var gridView: null - - property int buttonIndex: -1 - width: 129 height: 129 signal clicked() - Connections { - target: flickable - onMovingChanged: { - //when flick/move started, and hover is on, clean hove state - if (flickable.moving && tabletButton.state.indexOf("hover") !== -1) { - tabletButton.state = (tabletButton.isActive) ? "active state" : "base state"; - } - } - } - function changeProperty(key, value) { tabletButton[key] = value; } @@ -136,10 +121,8 @@ Item { anchors.fill: parent hoverEnabled: true enabled: true - preventStealing: false + preventStealing: true onClicked: { - gridView.currentIndex = buttonIndex - if (tabletButton.inDebugMode) { if (tabletButton.isActive) { tabletButton.isActive = false; @@ -147,15 +130,12 @@ Item { tabletButton.isActive = true; } } - tabletButton.clicked(); if (tabletRoot) { Tablet.playSound(TabletEnums.ButtonClick); } } - onEntered: { - gridView.currentIndex = buttonIndex tabletButton.isEntered = true; Tablet.playSound(TabletEnums.ButtonHover); diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index e934f18ab6..3f9451436c 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -1,10 +1,7 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 +import QtQuick 2.5 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 -import TabletScriptingInterface 1.0 - import "." import "../../styles-uit" import "../audio" as HifiAudio @@ -13,11 +10,7 @@ Item { id: tablet objectName: "tablet" property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system"); - - property var currentGridItems: null - - focus: true - + Rectangle { id: bgTopBar height: 90 @@ -92,6 +85,7 @@ Item { Rectangle { id: bgMain + clip: true gradient: Gradient { GradientStop { position: 0 @@ -108,186 +102,55 @@ Item { anchors.left: parent.left anchors.top: bgTopBar.bottom - SwipeView { - id: swipeView - clip: false - currentIndex: -1 - property int previousIndex: -1 - Repeater { - id: pageRepeater - model: Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage) - onItemAdded: { - item.proxyModel.sourceModel = tabletProxy.buttons; - item.proxyModel.pageIndex = index; - } - - delegate: Item { - id: page - property TabletButtonsProxyModel proxyModel: TabletButtonsProxyModel {} - - GridView { - id: gridView - keyNavigationEnabled: false - highlightFollowsCurrentItem: false - property int previousGridIndex: -1 - anchors { - fill: parent - topMargin: 20 - leftMargin: 30 - rightMargin: 30 - bottomMargin: 0 - } - - function setButtonState(buttonIndex, buttonstate) { - if (buttonIndex < 0 || gridView.contentItem === undefined - || gridView.contentItem.children.length - 1 < buttonIndex) { - return; - } - var itemat = gridView.contentItem.children[buttonIndex].children[0]; - if (itemat.isActive) { - itemat.state = "active state"; - } else { - itemat.state = buttonstate; - } - } - - onCurrentIndexChanged: { - setButtonState(previousGridIndex, "base state"); - setButtonState(currentIndex, "hover state"); - previousGridIndex = currentIndex - } - - cellWidth: width/3 - cellHeight: cellWidth - flow: GridView.LeftToRight - model: page.proxyModel - - delegate: Item { - id: wrapper - width: gridView.cellWidth - height: gridView.cellHeight - - property var proxy: modelData - - TabletButton { - id: tabletButton - anchors.centerIn: parent - gridView: wrapper.GridView.view - buttonIndex: page.proxyModel.buttonIndex(uuid); - flickable: swipeView.contentItem; - onClicked: modelData.clicked() - } - - Connections { - target: modelData; - onPropertiesChanged: { - updateProperties(); - } - } - - Component.onCompleted: updateProperties() - - function updateProperties() { - var keys = Object.keys(modelData.properties).forEach(function (key) { - if (tabletButton[key] !== modelData.properties[key]) { - tabletButton[key] = modelData.properties[key]; - } - }); - } - } - } - } - } - - onCurrentIndexChanged: { - if (swipeView.currentIndex < 0 - || swipeView.itemAt(swipeView.currentIndex) === null - || swipeView.itemAt(swipeView.currentIndex).children[0] === null) { - return; - } - - currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0]; - - currentGridItems.currentIndex = (previousIndex > swipeView.currentIndex ? currentGridItems.count - 1 : 0); - previousIndex = currentIndex; - } - - hoverEnabled: true - anchors { - left: parent.left - right: parent.right - top: parent.top - bottom: pageIndicator.top - } - } - - PageIndicator { - id: pageIndicator - currentIndex: swipeView.currentIndex - - delegate: Item { - width: 15 - height: 15 - - Rectangle { - anchors.centerIn: parent - opacity: index === pageIndicator.currentIndex ? 0.95 : 0.45 - implicitWidth: index === pageIndicator.currentIndex ? 15 : 10 - implicitHeight: implicitWidth - radius: width/2 - color: "white" - Behavior on opacity { - OpacityAnimator { - duration: 100 - } - } - } - } - - interactive: false + GridView { + id: flickable + anchors.top: parent.top + anchors.topMargin: 15 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter - count: swipeView.count - } - } + width: cellWidth * 3 + cellHeight: 145 + cellWidth: 145 + model: tabletProxy.buttons + delegate: Item { + width: flickable.cellWidth + height: flickable.cellHeight + property var proxy: modelData - Component.onCompleted: { - focus = true; - forceActiveFocus(); - } + TabletButton { + id: tabletButton + anchors.centerIn: parent + onClicked: modelData.clicked() + state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + } - Keys.onRightPressed: { - if (!currentGridItems) { - return; - } + Connections { + target: modelData; + onPropertiesChanged: { + updateProperties(); + } + } - var index = currentGridItems.currentIndex; - currentGridItems.moveCurrentIndexRight(); - if (index === currentGridItems.count - 1 && index === currentGridItems.currentIndex) { - if (swipeView.currentIndex < swipeView.count - 1) { - swipeView.incrementCurrentIndex(); + Component.onCompleted: updateProperties() + + function updateProperties() { + var keys = Object.keys(modelData.properties).forEach(function (key) { + if (tabletButton[key] !== modelData.properties[key]) { + tabletButton[key] = modelData.properties[key]; + } + }); + } } } } - Keys.onLeftPressed: { - if (!currentGridItems) { - return; - } - - var index = currentGridItems.currentIndex; - currentGridItems.moveCurrentIndexLeft(); - if (index === 0 && index === currentGridItems.currentIndex) { - if (swipeView.currentIndex > 0) { - swipeView.decrementCurrentIndex(); - } - } - } - Keys.onDownPressed: currentGridItems.moveCurrentIndexDown(); - Keys.onUpPressed: currentGridItems.moveCurrentIndexUp(); + Keys.onRightPressed: flickable.moveCurrentIndexRight(); + Keys.onLeftPressed: flickable.moveCurrentIndexLeft(); + Keys.onDownPressed: flickable.moveCurrentIndexDown(); + Keys.onUpPressed: flickable.moveCurrentIndexUp(); Keys.onReturnPressed: { - if (currentGridItems.currentItem) { - currentGridItems.currentItem.proxy.clicked(); + if (flickable.currentItem) { + flickable.currentItem.proxy.clicked(); if (tabletRoot) { tabletRoot.playButtonClickSound(); } diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc new file mode 100644 index 0000000000000000000000000000000000000000..ab20e996b9469915ac6a89901da175143e6b5024 GIT binary patch literal 6596 zcmcIoZD?EP6@Kh1ckah_<+cmm)~+s7*+{cEDOm|)Y*uPBiCux$Iwl#JYtNP&7t3}W zIXI&o4oU8EkM2n zXjl7O2dDtRuNCd{@)jY-)d!#zenqKY4sn&W{weu)twmlb!$4JTzv65rm+K1vDC#!F zU$|ZVIZ9zlW+S<`HL;hgR&M8~1sQiLyXg~6*Kx4qHtya=?){4Iz`gR%B^6)FqD(EX zPx0NgjXdr9YAbNP75KOnxYqy<89DFo`<=jA05hh+!CUJc)7q5K-I-U<4BwMhw#!Kold03qHB1qPh=(m57jV zQZO*TlsKpO<^4D&)ji|-UBpF<$-`KmCFTK~acFxKqv8qb`vJ}(jwnv6ynF{ogq(=F zep_Ap)wNGud)4)O>UtbUguEF{VOB&&#)x21=BI^yoeI;=cpet< z8yEavN0<0LF8)1^DU2eDE}X7EzTC=9#(VVvU%?VLXPX@E8u^tC$cdhzrY~ z5|TzSE|9{#2}}z<=It55SzSj%iNA*yHv6nZbjwP_N>*aF82-K7|F|4Z{3((gYY*l1 z1HmPNES&HK!VAmo!G#Z7%nSc2m&=jFSbJz;vopy0hR~Acw-O%(%P$^o0YVGQoxRBc zfA58N%nJ{-l0bHGCbwg^#q(qrrDi+!w<_$cdfT#JQtVa6B|0HZKTvD>SPT8{3FK*i zWU(iZU!oSteUbW{j!MrrowDh%hwMA*Wz%5~+1G_Km+UHco!!3?d2`uawWQAO`Fhz^ zFY9DKQ7^k1!8+Li%B~H>BZmbX7dAVWSkh#gI3&0r zaF0rAW;@0YRTR^~w|fH1=rq7T1!gIn>dAFt!Sy*C45#|hZ zyKMQfPE=zR8BZ12Iu&e;jZ`qZ;(XBNe0X7VdI#CX&hyK$=>L{qIw{h|R_2l4RI7AY z^-G-Fg*Pl@c)U6&I`)6~vWKqD3?b!JxCu1uN`cA?Q-i-75ra?*w4> z7DLeZEXfck*xy13exhOT)~XM$^JKYWuGBjYFUK{J-kQV9*AmCcI=9Ipz3t&zt&~o& zbp5o=j@d0M5iMDXSkX$%t~YJ^dxYvnP2X7@RT0fd+JSJgHI(cgqRD9&=_E-h7ipTL zi!Ra}N%Kz9JRJ@v&Ijf=afs?ImCUopaAUf5Bc(P@)^4QL#!&4B4=hC;lN+q^_W+Q1 zP^n|i{5|@(6kNweRp@!g!IB0$&XzP(9WOq8UKl6|MM0Czbbp-MJtdAmS4|C?43SDf)z9}dNlLtGo5xl*UM-i)V9TyEvOFWw5I(m_-&8|fx011{`>NNH;(6Df(rr#QsN>-}$CJna|wOpzoRcq-Fq`bAH8fghvwNyJ`N_RlpJYiGQZuHu}HZ5Pa zdE8c|q5`8P==g;$uId?L_>-ZdTT7Ja(9^jWIyw}4%`oqUj`vkn%QKo+>hkt%Am^R8 zT%)}GyrqJUtqMAFDsNlV@ #include #include -#include #include #include @@ -699,7 +698,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(nullptr, qApp->getOcteeSceneStats()); DependencyManager::set(); DependencyManager::set(); @@ -1191,6 +1189,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo userActivityLogger.logAction("launch", properties); } + // Tell our entity edit sender about our known jurisdictions + _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); _entityEditSender.setMyAvatar(myAvatar.get()); // The entity octree will have to know about MyAvatar for the parentJointName import @@ -4557,7 +4557,7 @@ void Application::reloadResourceCaches() { _lastQueriedTime = 0; _octreeQuery.incrementConnectionID(); - queryOctree(NodeType::EntityServer, PacketType::EntityQuery); + queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); DependencyManager::get()->clearCache(); @@ -5050,7 +5050,7 @@ void Application::update(float deltaTime) { if (queryIsDue || viewIsDifferentEnough) { _lastQueriedTime = now; if (DependencyManager::get()->shouldRenderEntities()) { - queryOctree(NodeType::EntityServer, PacketType::EntityQuery); + queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); } sendAvatarViewFrustum(); _lastQueriedViewFrustum = _viewFrustum; @@ -5271,12 +5271,15 @@ int Application::sendNackPackets() { return packetsSent; } -void Application::queryOctree(NodeType_t serverType, PacketType packetType) { +void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { if (!_settingsLoaded) { return; // bail early if settings are not loaded } + //qCDebug(interfaceapp) << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView(); + bool wantExtraDebugging = getLogger()->extraDebugging(); + ViewFrustum viewFrustum; copyViewFrustum(viewFrustum); _octreeQuery.setCameraPosition(viewFrustum.getPosition()); @@ -5291,22 +5294,147 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); + // Iterate all of the nodes, and get a count of how many octree servers we have... + int totalServers = 0; + int inViewServers = 0; + int unknownJurisdictionServers = 0; + auto nodeList = DependencyManager::get(); - auto node = nodeList->soloNodeOfType(serverType); - if (node && node->getActiveSocket()) { - _octreeQuery.setMaxQueryPacketsPerSecond(getMaxOctreePacketsPerSecond()); + nodeList->eachNode([&](const SharedNodePointer& node) { + // only send to the NodeTypes that are serverType + if (node->getActiveSocket() && node->getType() == serverType) { + totalServers++; - auto queryPacket = NLPacket::create(packetType); + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); - // encode the query data - auto packetData = reinterpret_cast(queryPacket->getPayload()); - int packetSize = _octreeQuery.getBroadcastData(packetData); - queryPacket->setPayloadSize(packetSize); + // if we haven't heard from this voxel server, go ahead and send it a query, so we + // can get the jurisdiction... + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { + unknownJurisdictionServers++; + } else { + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - // make sure we still have an active socket - nodeList->sendUnreliablePacket(*queryPacket, *node); + auto rootCode = map.getRootOctalCode(); + + if (rootCode) { + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode.get(), rootDetails); + AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, + rootDetails.y * TREE_SCALE, + rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE), + rootDetails.s * TREE_SCALE); + if (viewFrustum.cubeIntersectsKeyhole(serverBounds)) { + inViewServers++; + } + } + } + } + }); + + if (wantExtraDebugging) { + qCDebug(interfaceapp, "Servers: total %d, in view %d, unknown jurisdiction %d", + totalServers, inViewServers, unknownJurisdictionServers); } + + int perServerPPS = 0; + const int SMALL_BUDGET = 10; + int perUnknownServer = SMALL_BUDGET; + int totalPPS = getMaxOctreePacketsPerSecond(); + + // determine PPS based on number of servers + if (inViewServers >= 1) { + // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS + // for each unknown jurisdiction server + perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); + } else { + if (unknownJurisdictionServers > 0) { + perUnknownServer = (totalPPS / unknownJurisdictionServers); + } + } + + if (wantExtraDebugging) { + qCDebug(interfaceapp, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); + } + + auto queryPacket = NLPacket::create(packetType); + + nodeList->eachNode([&](const SharedNodePointer& node) { + // only send to the NodeTypes that are serverType + if (node->getActiveSocket() && node->getType() == serverType) { + + // get the server bounds for this server + QUuid nodeUUID = node->getUUID(); + + bool inView = false; + bool unknownView = false; + + // if we haven't heard from this voxel server, go ahead and send it a query, so we + // can get the jurisdiction... + if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { + unknownView = true; // assume it's in view + if (wantExtraDebugging) { + qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", assume it's visible."; + } + } else { + const JurisdictionMap& map = (jurisdictions)[nodeUUID]; + + auto rootCode = map.getRootOctalCode(); + + if (rootCode) { + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode.get(), rootDetails); + AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, + rootDetails.y * TREE_SCALE, + rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE), + rootDetails.s * TREE_SCALE); + + + inView = viewFrustum.cubeIntersectsKeyhole(serverBounds); + } else if (wantExtraDebugging) { + qCDebug(interfaceapp) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; + } + } + + if (inView) { + _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS); + } else if (unknownView) { + if (wantExtraDebugging) { + qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", give it budget of " + << perUnknownServer << " to send us jurisdiction."; + } + + // set the query's position/orientation to be degenerate in a manner that will get the scene quickly + // If there's only one server, then don't do this, and just let the normal voxel query pass through + // as expected... this way, we will actually get a valid scene if there is one to be seen + if (totalServers > 1) { + _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); + const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); + _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); + _octreeQuery.setCameraNearClip(0.1f); + _octreeQuery.setCameraFarClip(0.1f); + if (wantExtraDebugging) { + qCDebug(interfaceapp) << "Using 'minimal' camera position for node" << *node; + } + } else { + if (wantExtraDebugging) { + qCDebug(interfaceapp) << "Using regular camera position for node" << *node; + } + } + _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer); + } else { + _octreeQuery.setMaxQueryPacketsPerSecond(0); + } + + // encode the query data + int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); + queryPacket->setPayloadSize(packetSize); + + // make sure we still have an active socket + nodeList->sendUnreliablePacket(*queryPacket, *node); + } + }); } @@ -5421,6 +5549,11 @@ void Application::clearDomainOctreeDetails() { resetPhysicsReadyInformation(); + // reset our node to stats and node to jurisdiction maps... since these must be changing... + _entityServerJurisdictions.withWriteLock([&] { + _entityServerJurisdictions.clear(); + }); + _octreeServerSceneStats.withWriteLock([&] { _octreeServerSceneStats.clear(); }); @@ -5622,6 +5755,8 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { } int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { + // But, also identify the sender, and keep track of the contained jurisdiction root for this server + // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to int statsMessageLength = 0; @@ -5636,6 +5771,42 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer if (octreeStats.isFullScene()) { _fullSceneReceivedCounter++; } + + // see if this is the first we've heard of this node... + NodeToJurisdictionMap* jurisdiction = nullptr; + QString serverType; + if (sendingNode->getType() == NodeType::EntityServer) { + jurisdiction = &_entityServerJurisdictions; + serverType = "Entity"; + } + + bool found = false; + + jurisdiction->withReadLock([&] { + if (jurisdiction->find(nodeUUID) != jurisdiction->end()) { + found = true; + return; + } + + VoxelPositionSize rootDetails; + voxelDetailsForCode(octreeStats.getJurisdictionRoot().get(), rootDetails); + + qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", + qPrintable(serverType), + (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); + }); + + if (!found) { + // store jurisdiction details for later use + // This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it + // but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the + // details from the OctreeSceneStats to construct the JurisdictionMap + JurisdictionMap jurisdictionMap; + jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes()); + jurisdiction->withWriteLock([&] { + (*jurisdiction)[nodeUUID] = jurisdictionMap; + }); + } }); return statsMessageLength; @@ -5656,7 +5827,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe return !entityServerNode || isPhysicsEnabled(); }); - // setup the packet sender of the script engine's scripting interfaces so + // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->setPacketSender(&_entityEditSender); @@ -5770,7 +5941,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("GooglePoly", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get())); diff --git a/interface/src/Application.h b/interface/src/Application.h index 5267d50cf6..ee16740f20 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -228,6 +228,8 @@ public: FileLogger* getLogger() const { return _logger; } + NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } + float getRenderResolutionScale() const; qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); } @@ -448,7 +450,7 @@ private: void updateThreads(float deltaTime); void updateDialogs(float deltaTime) const; - void queryOctree(NodeType_t serverType, PacketType packetType); + void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); int sendNackPackets(); void sendAvatarViewFrustum(); @@ -569,6 +571,7 @@ private: StDev _idleLoopStdev; float _idleLoopMeasuredJitter; + NodeToJurisdictionMap _entityServerJurisdictions; NodeToOctreeSceneStats _octreeServerSceneStats; ControllerScriptingInterface* _controllerScriptingInterface{ nullptr }; QPointer _logDialog; diff --git a/interface/src/scripting/GooglePolyScriptingInterface.cpp b/interface/src/scripting/GooglePolyScriptingInterface.cpp deleted file mode 100644 index 8ed5d59d07..0000000000 --- a/interface/src/scripting/GooglePolyScriptingInterface.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// -// GooglePolyScriptingInterface.cpp -// interface/src/scripting -// -// Created by Elisa Lupin-Jimenez on 12/3/2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "GooglePolyScriptingInterface.h" -#include "ScriptEngineLogging.h" - -const QString LIST_POLY_URL = "https://poly.googleapis.com/v1/assets?"; -const QString GET_POLY_URL = "https://poly.googleapis.com/v1/assets/model?"; - -const QStringList VALID_FORMATS = QStringList() << "BLOCKS" << "FBX" << "GLTF" << "GLTF2" << "OBJ" << "TILT" << ""; -const QStringList VALID_CATEGORIES = QStringList() << "animals" << "architecture" << "art" << "food" << - "nature" << "objects" << "people" << "scenes" << "technology" << "transport" << ""; - -GooglePolyScriptingInterface::GooglePolyScriptingInterface() { - // nothing to be implemented -} - -void GooglePolyScriptingInterface::setAPIKey(const QString& key) { - _authCode = key; -} - -QString GooglePolyScriptingInterface::getAssetList(const QString& keyword, const QString& category, const QString& format) { - QUrl url = formatURLQuery(keyword, category, format); - if (!url.isEmpty()) { - QByteArray json = parseJSON(url, 0).toJsonDocument().toJson(); - return (QString) json; - } else { - qCDebug(scriptengine) << "Invalid filters were specified."; - return ""; - } -} - -QString GooglePolyScriptingInterface::getFBX(const QString& keyword, const QString& category) { - QUrl url = formatURLQuery(keyword, category, "FBX"); - return getModelURL(url); -} - -QString GooglePolyScriptingInterface::getOBJ(const QString& keyword, const QString& category) { - QUrl url = formatURLQuery(keyword, category, "OBJ"); - return getModelURL(url); -} - -QString GooglePolyScriptingInterface::getBlocks(const QString& keyword, const QString& category) { - QUrl url = formatURLQuery(keyword, category, "BLOCKS"); - return getModelURL(url); -} - -QString GooglePolyScriptingInterface::getGLTF(const QString& keyword, const QString& category) { - QUrl url = formatURLQuery(keyword, category, "GLTF"); - return getModelURL(url); -} - -QString GooglePolyScriptingInterface::getGLTF2(const QString& keyword, const QString& category) { - QUrl url = formatURLQuery(keyword, category, "GLTF2"); - return getModelURL(url); -} - -// This method will not be useful until we support Tilt models -QString GooglePolyScriptingInterface::getTilt(const QString& keyword, const QString& category) { - QUrl url = formatURLQuery(keyword, category, "TILT"); - return getModelURL(url); -} - -// Can provide asset name or full URL to model -QString GooglePolyScriptingInterface::getModelInfo(const QString& input) { - QString name(input); - if (input.contains("poly.googleapis") || input.contains("poly.google.com")) { - QStringList list = input.split("/"); - if (input.contains("poly.googleapis")) { - name = list[4]; - } else { - name = list.last(); - } - } - QString urlString(GET_POLY_URL); - urlString = urlString.replace("model", name) + "key=" + _authCode; - qCDebug(scriptengine) << "Google URL request: " << urlString; - QUrl url(urlString); - QString json = parseJSON(url, 2).toString(); - return json; -} - -int GooglePolyScriptingInterface::getRandIntInRange(int length) { - QTime time = QTime::currentTime(); - qsrand((uint)time.msec()); - return qrand() % length; -} - -QUrl GooglePolyScriptingInterface::formatURLQuery(const QString& keyword, const QString& category, const QString& format) { - QString queries; - if (!VALID_FORMATS.contains(format, Qt::CaseInsensitive) || !VALID_CATEGORIES.contains(category, Qt::CaseInsensitive)) { - return QUrl(""); - } else { - if (!keyword.isEmpty()) { - QString keywords(keyword); - keywords.replace(" ", "+"); - queries.append("&keywords=" + keywords); - } - if (!category.isEmpty()) { - queries.append("&category=" + category); - } - if (!format.isEmpty()) { - queries.append("&format=" + format); - } - QString urlString(LIST_POLY_URL + "key=" + _authCode + queries); - return QUrl(urlString); - } -} - -QString GooglePolyScriptingInterface::getModelURL(const QUrl& url) { - qCDebug(scriptengine) << "Google URL request: " << url; - if (!url.isEmpty()) { - return parseJSON(url, 1).toString(); - } else { - qCDebug(scriptengine) << "Invalid filters were specified."; - return ""; - } -} - -// FIXME: synchronous -QByteArray GooglePolyScriptingInterface::getHTTPRequest(const QUrl& url) { - QNetworkAccessManager manager; - QNetworkReply *response = manager.get(QNetworkRequest(url)); - QEventLoop event; - connect(response, SIGNAL(finished()), &event, SLOT(quit())); - event.exec(); - - return response->readAll(); -} - -// 0 = asset list, 1 = model from asset list, 2 = specific model -QVariant GooglePolyScriptingInterface::parseJSON(const QUrl& url, int fileType) { - QByteArray jsonString = getHTTPRequest(url); - QJsonDocument doc = QJsonDocument::fromJson(jsonString); - QJsonObject obj = doc.object(); - if (obj.isEmpty()) { - qCDebug(scriptengine) << "Assets with specified filters not found"; - return ""; - } - if (obj.keys().first() == "error") { - QString error = obj.value("error").toObject().value("message").toString(); - qCDebug(scriptengine) << error; - return ""; - } - if (fileType == 0 || fileType == 1) { - QJsonArray arr = obj.value("assets").toArray(); - // return model url - if (fileType == 1) { - int random = getRandIntInRange(arr.size()); - QJsonObject json = arr.at(random).toObject(); - // nested JSONs - return json.value("formats").toArray().at(0).toObject().value("root").toObject().value("url"); - } - // return whole asset list - return QJsonDocument(arr); - // return specific object - } else { - return jsonString; - } -} diff --git a/interface/src/scripting/GooglePolyScriptingInterface.h b/interface/src/scripting/GooglePolyScriptingInterface.h deleted file mode 100644 index fdd3597bec..0000000000 --- a/interface/src/scripting/GooglePolyScriptingInterface.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// GooglePolyScriptingInterface.h -// interface/src/scripting -// -// Created by Elisa Lupin-Jimenez on 12/3/2017. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_GooglePolyScriptingInterface_h -#define hifi_GooglePolyScriptingInterface_h - -#include -#include - -class GooglePolyScriptingInterface : public QObject, public Dependency { - Q_OBJECT - -public: - GooglePolyScriptingInterface(); - -public slots: - void setAPIKey(const QString& key); - - QString getAssetList(const QString& keyword, const QString& category, const QString& format); - QString getFBX(const QString& keyword, const QString& category); - QString getOBJ(const QString& keyword, const QString& category); - QString getBlocks(const QString& keyword, const QString& categoryy); - QString getGLTF(const QString& keyword, const QString& category); - QString getGLTF2(const QString& keyword, const QString& category); - QString getTilt(const QString& keyword, const QString& category); - QString getModelInfo(const QString& input); - -private: - QString _authCode; - - QUrl formatURLQuery(const QString& keyword, const QString& category, const QString& format); - QString getModelURL(const QUrl& url); - QByteArray getHTTPRequest(const QUrl& url); - QVariant parseJSON(const QUrl& url, int fileType); - int getRandIntInRange(int length); - -}; - -#endif // hifi_GooglePolyScriptingInterface_h diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index ec5d800042..fc0e6781d7 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -26,17 +26,27 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), - _model(model) + _model(model), + _averageUpdatesPerSecond(SAMPLES_PER_SECOND) { - for (int i = 0; i < MAX_STATS; i++) { - _labels[i] = nullptr; + + _statCount = 0; + _octreeServerLabelsCount = 0; + + for (int i = 0; i < MAX_VOXEL_SERVERS; i++) { + _octreeServerLables[i] = 0; + _extraServerDetails[i] = LESS; } - setWindowTitle("Octree Server Statistics"); + for (int i = 0; i < MAX_STATS; i++) { + _labels[i] = NULL; + } + + this->setWindowTitle("Octree Server Statistics"); // Create layouter _form = new QFormLayout(); - setLayout(_form); + this->QDialog::setLayout(_form); // Setup stat items _serverElements = AddStatItem("Elements on Servers"); @@ -53,14 +63,7 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo _entityUpdateTime = AddStatItem("Entity Update Time"); _entityUpdates = AddStatItem("Entity Updates"); - - - _octreeServerLabel = AddStatItem("Entity Server"); - _labels[_octreeServerLabel]->setTextFormat(Qt::RichText); - _labels[_octreeServerLabel]->setTextInteractionFlags(Qt::TextBrowserInteraction); - connect(_labels[_octreeServerLabel], SIGNAL(linkActivated(const QString&)), - this, SLOT(moreless(const QString&))); - + layout()->setSizeConstraint(QLayout::SetFixedSize); } @@ -71,16 +74,23 @@ void OctreeStatsDialog::RemoveStatItem(int item) { _form->removeWidget(automaticLabel); automaticLabel->deleteLater(); myLabel->deleteLater(); - _labels[item] = nullptr; + _labels[item] = NULL; } void OctreeStatsDialog::moreless(const QString& link) { - if (link == "more") { - _extraServerDetails = MORE; - } else if (link == "most") { - _extraServerDetails = MOST; + QStringList linkDetails = link.split("-"); + const int COMMAND_ITEM = 0; + const int SERVER_NUMBER_ITEM = 1; + QString serverNumberString = linkDetails[SERVER_NUMBER_ITEM]; + QString command = linkDetails[COMMAND_ITEM]; + int serverNumber = serverNumberString.toInt(); + + if (command == "more") { + _extraServerDetails[serverNumber-1] = MORE; + } else if (command == "most") { + _extraServerDetails[serverNumber-1] = MOST; } else { - _extraServerDetails = LESS; + _extraServerDetails[serverNumber-1] = LESS; } } @@ -366,34 +376,91 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { QDialog::paintEvent(event); } void OctreeStatsDialog::showAllOctreeServers() { - showOctreeServersOfType(NodeType::EntityServer); + int serverCount = 0; + + showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", + qApp->getEntityServerJurisdictions()); + + if (_octreeServerLabelsCount > serverCount) { + for (int i = serverCount; i < _octreeServerLabelsCount; i++) { + int serverLabel = _octreeServerLables[i]; + RemoveStatItem(serverLabel); + _octreeServerLables[i] = 0; + } + _octreeServerLabelsCount = serverCount; + } } -void OctreeStatsDialog::showOctreeServersOfType(NodeType_t serverType) { +void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName, + NodeToJurisdictionMap& serverJurisdictions) { + QLocale locale(QLocale::English); - auto node = DependencyManager::get()->soloNodeOfType(serverType); - if (node) { - std::stringstream serverDetails(""); - std::stringstream extraDetails(""); - std::stringstream linkDetails(""); + auto nodeList = DependencyManager::get(); + nodeList->eachNode([&](const SharedNodePointer& node){ + + // only send to the NodeTypes that are NodeType_t_VOXEL_SERVER + if (node->getType() == serverType) { + serverCount++; + + if (serverCount > _octreeServerLabelsCount) { + QString label = QString("%1 Server %2").arg(serverTypeName).arg(serverCount); + int thisServerRow = _octreeServerLables[serverCount-1] = AddStatItem(label.toUtf8().constData()); + _labels[thisServerRow]->setTextFormat(Qt::RichText); + _labels[thisServerRow]->setTextInteractionFlags(Qt::TextBrowserInteraction); + connect(_labels[thisServerRow], SIGNAL(linkActivated(const QString&)), this, SLOT(moreless(const QString&))); + _octreeServerLabelsCount++; + } + + std::stringstream serverDetails(""); + std::stringstream extraDetails(""); + std::stringstream linkDetails(""); + + if (node->getActiveSocket()) { + serverDetails << "active "; + } else { + serverDetails << "inactive "; + } + + QUuid nodeUUID = node->getUUID(); + + // lookup our nodeUUID in the jurisdiction map, if it's missing then we're + // missing at least one jurisdiction + serverJurisdictions.withReadLock([&] { + if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) { + serverDetails << " unknown jurisdiction "; + return; + } + const JurisdictionMap& map = serverJurisdictions[nodeUUID]; - if (node->getActiveSocket()) { - serverDetails << "active "; - } else { - serverDetails << "inactive "; - } + auto rootCode = map.getRootOctalCode(); - QUuid nodeUUID = node->getUUID(); + if (rootCode) { + QString rootCodeHex = octalCodeToHexString(rootCode.get()); - // now lookup stats details for this server... - if (_extraServerDetails != LESS) { - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode.get(), rootDetails); + AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + serverDetails << " jurisdiction: " + << qPrintable(rootCodeHex) + << " [" + << rootDetails.x << ", " + << rootDetails.y << ", " + << rootDetails.z << ": " + << rootDetails.s << "] "; + } else { + serverDetails << " jurisdiction has no rootCode"; + } // root code + }); + + // now lookup stats details for this server... + if (_extraServerDetails[serverCount-1] != LESS) { + NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); + sceneStats->withReadLock([&] { + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + OctreeSceneStats& stats = sceneStats->at(nodeUUID); - switch (_extraServerDetails) { + switch (_extraServerDetails[serverCount - 1]) { case MOST: { extraDetails << "
"; @@ -471,7 +538,7 @@ void OctreeStatsDialog::showOctreeServersOfType(NodeType_t serverType) { " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; serverDetails << "
" << - " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << + " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << " [" << qPrintable(formattedClockSkewString) << "]"; @@ -480,37 +547,38 @@ void OctreeStatsDialog::showOctreeServersOfType(NodeType_t serverType) { " Wasted Bytes: " << qPrintable(incomingWastedBytesString); serverDetails << extraDetails.str(); - if (_extraServerDetails == MORE) { - linkDetails << " [most...]"; - linkDetails << " [less...]"; + if (_extraServerDetails[serverCount - 1] == MORE) { + linkDetails << " " << " [most...]"; + linkDetails << " " << " [less...]"; } else { - linkDetails << " [less...]"; - linkDetails << " [least...]"; + linkDetails << " " << " [less...]"; + linkDetails << " " << " [least...]"; } } break; case LESS: { // nothing } break; + } } - } - }); - } else { - linkDetails << " [more...]"; - linkDetails << " [most...]"; - } - serverDetails << linkDetails.str(); - _labels[_octreeServerLabel]->setText(serverDetails.str().c_str()); - } + }); + } else { + linkDetails << " " << " [more...]"; + linkDetails << " " << " [most...]"; + } + serverDetails << linkDetails.str(); + _labels[_octreeServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); + } // is VOXEL_SERVER + }); } void OctreeStatsDialog::reject() { // Just regularly close upon ESC - QDialog::close(); + this->QDialog::close(); } void OctreeStatsDialog::closeEvent(QCloseEvent* event) { - QDialog::closeEvent(event); + this->QDialog::closeEvent(event); emit closed(); } diff --git a/interface/src/ui/OctreeStatsDialog.h b/interface/src/ui/OctreeStatsDialog.h index 81bf5f251f..67f5c01f65 100644 --- a/interface/src/ui/OctreeStatsDialog.h +++ b/interface/src/ui/OctreeStatsDialog.h @@ -19,6 +19,7 @@ #include #define MAX_STATS 100 +#define MAX_VOXEL_SERVERS 50 #define DEFAULT_COLOR 0 class OctreeStatsDialog : public QDialog { @@ -46,22 +47,18 @@ protected: void RemoveStatItem(int item); void showAllOctreeServers(); - void showOctreeServersOfType(NodeType_t serverType); + void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, + const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions); private: - enum details { - LESS, - MORE, - MOST - }; - QFormLayout* _form { nullptr }; + typedef enum { LESS, MORE, MOST } details; + + QFormLayout* _form; QLabel* _labels[MAX_STATS]; - NodeToOctreeSceneStats* _model { nullptr }; - int _statCount { 0 }; - - int _octreeServerLabel; - + NodeToOctreeSceneStats* _model; + int _statCount; + int _sendingMode; int _serverElements; int _localElements; @@ -75,14 +72,16 @@ private: int _processedPacketsTiming; int _outboundEditPackets; - const int SAMPLES_PER_SECOND { 10 }; - SimpleMovingAverage _averageUpdatesPerSecond { SAMPLES_PER_SECOND }; - quint64 _lastWindowAt { usecTimestampNow() }; - quint64 _lastKnownTrackedEdits { 0 }; + const int SAMPLES_PER_SECOND = 10; + SimpleMovingAverage _averageUpdatesPerSecond; + quint64 _lastWindowAt = usecTimestampNow(); + quint64 _lastKnownTrackedEdits = 0; - quint64 _lastRefresh { 0 }; + quint64 _lastRefresh = 0; - details _extraServerDetails { LESS }; + int _octreeServerLables[MAX_VOXEL_SERVERS]; + int _octreeServerLabelsCount; + details _extraServerDetails[MAX_VOXEL_SERVERS]; }; #endif // hifi_OctreeStatsDialog_h diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index a393660c17..5f40b9916d 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -16,9 +16,9 @@ OctreeStatsProvider::OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model) : QObject(parent), - _model(model), - _statCount(0), - _averageUpdatesPerSecond(SAMPLES_PER_SECOND) + _model(model) + , _statCount(0) + , _averageUpdatesPerSecond(SAMPLES_PER_SECOND) { //schedule updates connect(&_updateTimer, &QTimer::timeout, this, &OctreeStatsProvider::updateOctreeStatsData); @@ -237,105 +237,140 @@ void OctreeStatsProvider::updateOctreeStatsData() { } void OctreeStatsProvider::updateOctreeServers() { - showOctreeServersOfType(NodeType::EntityServer); -} - -void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) { - m_servers.clear(); int serverCount = 0; - auto node = DependencyManager::get()->soloNodeOfType(serverType); - if (node) { - ++serverCount; - - QString lesserDetails; - QString moreDetails; - QString mostDetails; - - if (node->getActiveSocket()) { - lesserDetails += "active "; - } else { - lesserDetails += "inactive "; - } - - QUuid nodeUUID = node->getUUID(); - - // now lookup stats details for this server... - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); - - float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; - float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; - float lastFullPackets = stats.getLastFullTotalPackets(); - float lastFullPPS = lastFullPackets; - if (lastFullSendInSeconds > 0) { - lastFullPPS = lastFullPackets / lastFullSendInSeconds; - } - - mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") - .arg(lastFullEncode) - .arg(lastFullSend) - .arg(lastFullPackets) - .arg(stats.getLastFullTotalBytes()) - .arg(lastFullPPS); - - for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { - OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); - OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - mostDetails += QString("
%1 %2") - .arg(itemInfo.caption).arg(stats.getItemValue(item)); - } - - moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; - - moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") - .arg(stats.getTotalElements()) - .arg(stats.getTotalInternal()) - .arg(stats.getTotalLeaves()); - - const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); - qint64 clockSkewInUsecs = node->getClockSkewUsec(); - qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; - - moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") - .arg(stats.getIncomingPackets()) - .arg(seqStats.getLost()) - .arg(seqStats.getRecovered()); - - moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") - .arg(seqStats.getOutOfOrder()) - .arg(seqStats.getEarly()) - .arg(seqStats.getLate()) - .arg(seqStats.getUnreasonable()); - - moreDetails += QString("
Average Flight Time: %1 msecs") - .arg(stats.getIncomingFlightTimeAverage()); - - moreDetails += QString("
Average Ping Time: %1 msecs") - .arg(node->getPingMs()); - - moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") - .arg(clockSkewInMS) - .arg(formatUsecTime(clockSkewInUsecs)); - - - moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") - .arg(stats.getIncomingBytes()) - .arg(stats.getIncomingWastedBytes()); - } - }); - m_servers.append(lesserDetails); - m_servers.append(moreDetails); - m_servers.append(mostDetails); - } - - if (serverCount != m_serversNum) { + showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", + qApp->getEntityServerJurisdictions()); + if (m_serversNum != serverCount) { m_serversNum = serverCount; emit serversNumChanged(m_serversNum); } +} + +void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName, + NodeToJurisdictionMap& serverJurisdictions) { + + m_servers.clear(); + + auto nodeList = DependencyManager::get(); + nodeList->eachNode([&](const SharedNodePointer& node) { + + // only send to the NodeTypes that are NodeType_t_VOXEL_SERVER + if (node->getType() == serverType) { + serverCount++; + + QString lesserDetails; + QString moreDetails; + QString mostDetails; + + if (node->getActiveSocket()) { + lesserDetails += "active "; + } else { + lesserDetails += "inactive "; + } + + QUuid nodeUUID = node->getUUID(); + + // lookup our nodeUUID in the jurisdiction map, if it's missing then we're + // missing at least one jurisdiction + serverJurisdictions.withReadLock([&] { + if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) { + lesserDetails += " unknown jurisdiction "; + return; + } + const JurisdictionMap& map = serverJurisdictions[nodeUUID]; + + auto rootCode = map.getRootOctalCode(); + + if (rootCode) { + QString rootCodeHex = octalCodeToHexString(rootCode.get()); + + VoxelPositionSize rootDetails; + voxelDetailsForCode(rootCode.get(), rootDetails); + AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); + lesserDetails += QString(" jurisdiction: %1 [%2, %3, %4: %5]") + .arg(rootCodeHex) + .arg(rootDetails.x) + .arg(rootDetails.y) + .arg(rootDetails.z) + .arg(rootDetails.s); + } else { + lesserDetails += " jurisdiction has no rootCode"; + } // root code + }); + + // now lookup stats details for this server... + NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); + sceneStats->withReadLock([&] { + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + OctreeSceneStats& stats = sceneStats->at(nodeUUID); + + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; + float lastFullPackets = stats.getLastFullTotalPackets(); + float lastFullPPS = lastFullPackets; + if (lastFullSendInSeconds > 0) { + lastFullPPS = lastFullPackets / lastFullSendInSeconds; + } + + mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") + .arg(lastFullEncode) + .arg(lastFullSend) + .arg(lastFullPackets) + .arg(stats.getLastFullTotalBytes()) + .arg(lastFullPPS); + + for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { + OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); + OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + mostDetails += QString("
%1 %2") + .arg(itemInfo.caption).arg(stats.getItemValue(item)); + } + + moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; + + moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") + .arg(stats.getTotalElements()) + .arg(stats.getTotalInternal()) + .arg(stats.getTotalLeaves()); + + const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); + qint64 clockSkewInUsecs = node->getClockSkewUsec(); + qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; + + moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") + .arg(stats.getIncomingPackets()) + .arg(seqStats.getLost()) + .arg(seqStats.getRecovered()); + + moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") + .arg(seqStats.getOutOfOrder()) + .arg(seqStats.getEarly()) + .arg(seqStats.getLate()) + .arg(seqStats.getUnreasonable()); + + moreDetails += QString("
Average Flight Time: %1 msecs") + .arg(stats.getIncomingFlightTimeAverage()); + + moreDetails += QString("
Average Ping Time: %1 msecs") + .arg(node->getPingMs()); + + moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") + .arg(clockSkewInMS) + .arg(formatUsecTime(clockSkewInUsecs)); + + + moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") + .arg(stats.getIncomingBytes()) + .arg(stats.getIncomingWastedBytes()); + } + }); + m_servers.append(lesserDetails); + m_servers.append(moreDetails); + m_servers.append(mostDetails); + } // is VOXEL_SERVER + }); emit serversChanged(m_servers); } diff --git a/interface/src/ui/OctreeStatsProvider.h b/interface/src/ui/OctreeStatsProvider.h index 5b3d4d735c..c919ca102f 100644 --- a/interface/src/ui/OctreeStatsProvider.h +++ b/interface/src/ui/OctreeStatsProvider.h @@ -18,6 +18,10 @@ #include "DependencyManager.h" +#define MAX_STATS 100 +#define MAX_VOXEL_SERVERS 50 +#define DEFAULT_COLOR 0 + class OctreeStatsProvider : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -117,7 +121,8 @@ private slots: void updateOctreeStatsData(); protected: void updateOctreeServers(); - void showOctreeServersOfType(NodeType_t serverType); + void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, + const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions); private: NodeToOctreeSceneStats* _model; @@ -131,7 +136,7 @@ private: quint64 _lastRefresh = 0; QTimer _updateTimer; - int m_serversNum { 0 }; + int m_serversNum {0}; QString m_serverElements; QString m_localElements; QString m_localElementsMemory; diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 84a6fe1da4..6922ca87b7 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -212,6 +212,8 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { * parentID set, otherwise the same value as rotation. * @property {boolean} isSolid=false - Synonyms: solid, isFilled, * filled, and filed. Antonyms: isWire and wire. + * Deprecated: The erroneous property spelling "filed" is deprecated and support for it will + * be removed. * @property {boolean} isDashedLine=false - If true, a dashed line is drawn on the overlay's edges. Synonym: * dashed. * @property {boolean} ignoreRayIntersection=false - If true, @@ -239,7 +241,7 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "localRotation" || property == "localOrientation") { return quatToVariant(getLocalOrientation()); } - if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled") { + if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled" || property == "filed") { return _isSolid; } if (property == "isWire" || property == "wire") { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 91e26d0a3c..d0dca2d43e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -686,18 +686,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); } } else if (_simulationOwner.pendingTake(now - maxPingRoundTrip)) { - // we sent a bid already but maybe before this packet was sent from the server + // we sent a bid before this packet could have been sent from the server + // so we ignore it and pretend we own the object's simulation weOwnSimulation = true; if (newSimOwner.getID().isNull()) { - // the entity-server is trying to clear someone else's ownership + // entity-server is trying to clear someone else's ownership + // but we want to own it, therefore we ignore this clear event if (!_simulationOwner.isNull()) { + // someone else really did own it markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; _simulationOwner.clearCurrentOwner(); } - } else if (newSimOwner.getID() == myNodeID) { - // the entity-server is awarding us ownership which is what we want - _simulationOwner.set(newSimOwner); } } else if (newSimOwner.matchesValidID(myNodeID) && !_hasBidOnSimulation) { // entity-server tells us that we have simulation ownership while we never requested this for this EntityItem, @@ -2082,6 +2082,17 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi } EntityDynamicPointer action = _objectActions[actionID]; + + action->setOwnerEntity(nullptr); + action->setIsMine(false); + + if (simulation) { + action->removeFromSimulation(simulation); + } + + bool success = true; + serializeActions(success, _allActionsDataCache); + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; auto removedActionType = action->getType(); if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) { _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; @@ -2098,17 +2109,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi // because they should have been set correctly when the action was added // and/or when children were linked } - action->setOwnerEntity(nullptr); - action->setIsMine(false); _objectActions.remove(actionID); - - if (simulation) { - action->removeFromSimulation(simulation); - } - - bool success = true; - serializeActions(success, _allActionsDataCache); - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; setDynamicDataNeedsTransmit(true); return success; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d8fb3b3ab6..0136590ffa 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -133,7 +133,7 @@ public: static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); - int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); + virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 1b80c3b3af..94bc4eeff6 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -42,10 +42,7 @@ static Setting::Handle LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.Loc const std::set SOLO_NODE_TYPES = { NodeType::AvatarMixer, NodeType::AudioMixer, - NodeType::AssetServer, - NodeType::EntityServer, - NodeType::MessagesMixer, - NodeType::EntityScriptServer + NodeType::AssetServer }; LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 44f86baf40..0a75e8c31b 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(EntityVersion::OwnershipChallengeFix); case PacketType::EntityQuery: - return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); + return static_cast(EntityQueryPacketVersion::ConnectionIdentifier); case PacketType::AvatarIdentity: case PacketType::AvatarData: case PacketType::BulkAvatarData: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index b2f22e2a1f..85f321a198 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -56,8 +56,8 @@ public: ICEServerPeerInformation, ICEServerQuery, OctreeStats, - UNUSED_PACKET_TYPE_1, - UNUSED_PACKET_TYPE_2, + Jurisdiction, + JurisdictionRequest, AssignmentClientStatus, NoisyMute, AvatarIdentity, @@ -212,8 +212,7 @@ enum class EntityScriptCallMethodVersion : PacketVersion { enum class EntityQueryPacketVersion: PacketVersion { JSONFilter = 18, JSONFilterWithFamilyTree = 19, - ConnectionIdentifier = 20, - RemovedJurisdictions = 21 + ConnectionIdentifier = 20 }; enum class AssetServerPacketVersion: PacketVersion { diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp new file mode 100644 index 0000000000..76c5069006 --- /dev/null +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -0,0 +1,85 @@ +// +// JurisdictionListener.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 8/12/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include +#include +#include +#include "JurisdictionListener.h" + +JurisdictionListener::JurisdictionListener(NodeType_t type) : + _nodeType(type), + _packetSender(JurisdictionListener::DEFAULT_PACKETS_PER_SECOND) +{ + setObjectName("Jurisdiction Listener"); + + connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled); + + // tell our NodeList we want to hear about nodes with our node type + DependencyManager::get()->addNodeTypeToInterestSet(type); +} + +void JurisdictionListener::nodeKilled(SharedNodePointer node) { + if (_jurisdictions.find(node->getUUID()) != _jurisdictions.end()) { + _jurisdictions.erase(_jurisdictions.find(node->getUUID())); + } +} + +bool JurisdictionListener::queueJurisdictionRequest() { + auto nodeList = DependencyManager::get(); + + int nodeCount = 0; + + nodeList->eachNode([&](const SharedNodePointer& node) { + if (node->getType() == getNodeType() && node->getActiveSocket()) { + auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0); + _packetSender.queuePacketForSending(node, std::move(packet)); + nodeCount++; + } + }); + + if (nodeCount > 0){ + _packetSender.setPacketsPerSecond(nodeCount); + } else { + _packetSender.setPacketsPerSecond(NO_SERVER_CHECK_RATE); + } + + // keep going if still running + return isStillRunning(); +} + +void JurisdictionListener::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { + if (message->getType() == PacketType::Jurisdiction) { + JurisdictionMap map; + map.unpackFromPacket(*message); + _jurisdictions[message->getSourceID()] = map; + } +} + +bool JurisdictionListener::process() { + bool continueProcessing = isStillRunning(); + + // If we're still running, and we don't have any requests waiting to be sent, then queue our jurisdiction requests + if (continueProcessing && !_packetSender.hasPacketsToSend()) { + queueJurisdictionRequest(); + } + + if (continueProcessing) { + continueProcessing = _packetSender.process(); + } + if (continueProcessing) { + // NOTE: This will sleep if there are no pending packets to process + continueProcessing = ReceivedPacketProcessor::process(); + } + + return continueProcessing; +} diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h new file mode 100644 index 0000000000..7aee1659ff --- /dev/null +++ b/libraries/octree/src/JurisdictionListener.h @@ -0,0 +1,60 @@ +// +// JurisdictionListener.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 8/12/13. +// Copyright 2013 High Fidelity, Inc. +// +// Voxel Packet Sender +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_JurisdictionListener_h +#define hifi_JurisdictionListener_h + +#include +#include +#include + +#include "JurisdictionMap.h" + +/// Sends out PacketType::_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes +/// the PacketType::_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions +/// within the domain. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets +/// and adding them to the processing queue by calling queueReceivedPacket() +class JurisdictionListener : public ReceivedPacketProcessor { + Q_OBJECT +public: + static const int DEFAULT_PACKETS_PER_SECOND = 1; + static const int NO_SERVER_CHECK_RATE = 60; // if no servers yet detected, keep checking at 60fps + + JurisdictionListener(NodeType_t type = NodeType::EntityServer); + + virtual bool process() override; + + NodeToJurisdictionMap* getJurisdictions() { return &_jurisdictions; } + + + NodeType_t getNodeType() const { return _nodeType; } + void setNodeType(NodeType_t type) { _nodeType = type; } + +public slots: + /// Called by NodeList to inform us that a node has been killed. + void nodeKilled(SharedNodePointer node); + +protected: + /// Callback for processing of received packets. Will process any queued PacketType::_JURISDICTION and update the + /// jurisdiction map member variable + virtual void processPacket(QSharedPointer messsage, SharedNodePointer sendingNode) override; + +private: + NodeToJurisdictionMap _jurisdictions; + NodeType_t _nodeType; + + bool queueJurisdictionRequest(); + + PacketSender _packetSender; +}; +#endif // hifi_JurisdictionListener_h diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp new file mode 100644 index 0000000000..fcbc085339 --- /dev/null +++ b/libraries/octree/src/JurisdictionMap.cpp @@ -0,0 +1,325 @@ +// +// JurisdictionMap.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 8/1/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include + +#include +#include +#include + +#include "OctreeLogging.h" +#include "JurisdictionMap.h" + +void myDebugOutputBits(unsigned char byte, bool withNewLine) { + if (isalnum(byte)) { + printf("[ %d (%c): ", byte, byte); + } else { + printf("[ %d (0x%x): ", byte, byte); + } + + for (int i = 0; i < 8; i++) { + printf("%d", byte >> (7 - i) & 1); + } + printf(" ] "); + + if (withNewLine) { + printf("\n"); + } +} + +void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) { + if (!octalCode) { + printf("nullptr"); + } else { + for (size_t i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { + myDebugOutputBits(octalCode[i], false); + } + } + if (withNewLine) { + printf("\n"); + } +} + +// standard assignment +// copy assignment +JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) { + copyContents(other); + return *this; +} + +// Copy constructor +JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(nullptr) { + copyContents(other); +} + +void JurisdictionMap::copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn) { + OctalCodePtr rootCode = rootCodeIn; + if (!rootCode) { + rootCode = createOctalCodePtr(1); + *rootCode = 0; + } + + OctalCodePtrList emptyEndNodes; + init(rootCode, endNodesIn); +} + +void JurisdictionMap::copyContents(const JurisdictionMap& other) { + _nodeType = other._nodeType; + + OctalCodePtr rootOctalCode; + OctalCodePtrList endNodes; + + std::tie(rootOctalCode, endNodes) = other.getRootAndEndNodeOctalCodes(); + + init(rootOctalCode, endNodes); +} + +JurisdictionMap::~JurisdictionMap() { +} + +JurisdictionMap::JurisdictionMap(NodeType_t type) : _rootOctalCode(nullptr) { + _nodeType = type; + OctalCodePtr rootCode = createOctalCodePtr(1); + *rootCode = 0; + + OctalCodePtrList emptyEndNodes; + init(rootCode, emptyEndNodes); +} + +JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(nullptr) { + readFromFile(filename); +} + +JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) { + + qCDebug(octree, "JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)", + rootHexCode, rootHexCode, endNodesHexCodes, endNodesHexCodes); + + _rootOctalCode = hexStringToOctalCode(QString(rootHexCode)); + + qCDebug(octree, "JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode.get()); + myDebugPrintOctalCode(_rootOctalCode.get(), true); + + QString endNodesHexStrings(endNodesHexCodes); + QString delimiterPattern(","); + QStringList endNodeList = endNodesHexStrings.split(delimiterPattern); + + for (int i = 0; i < endNodeList.size(); i++) { + QString endNodeHexString = endNodeList.at(i); + + auto endNodeOctcode = hexStringToOctalCode(endNodeHexString); + + qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeList(%d)=%s", + i, endNodeHexString.toLocal8Bit().constData()); + + //printOctalCode(endNodeOctcode); + _endNodes.push_back(endNodeOctcode); + + qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode.get()); + myDebugPrintOctalCode(endNodeOctcode.get(), true); + + } +} + +std::tuple JurisdictionMap::getRootAndEndNodeOctalCodes() const { + std::lock_guard lock(_octalCodeMutex); + return std::tuple(_rootOctalCode, _endNodes); +} + +OctalCodePtr JurisdictionMap::getRootOctalCode() const { + std::lock_guard lock(_octalCodeMutex); + return _rootOctalCode; +} + +OctalCodePtrList JurisdictionMap::getEndNodeOctalCodes() const { + std::lock_guard lock(_octalCodeMutex); + return _endNodes; +} + +void JurisdictionMap::init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes) { + std::lock_guard lock(_octalCodeMutex); + _rootOctalCode = rootOctalCode; + _endNodes = endNodes; +} + +JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const { + // to be in our jurisdiction, we must be under the root... + + std::lock_guard lock(_octalCodeMutex); + + // if the node is an ancestor of my root, then we return ABOVE + if (isAncestorOf(nodeOctalCode, _rootOctalCode.get())) { + return ABOVE; + } + + // otherwise... + bool isInJurisdiction = isAncestorOf(_rootOctalCode.get(), nodeOctalCode, childIndex); + // if we're under the root, then we can't be under any of the endpoints + if (isInJurisdiction) { + for (size_t i = 0; i < _endNodes.size(); i++) { + bool isUnderEndNode = isAncestorOf(_endNodes[i].get(), nodeOctalCode); + if (isUnderEndNode) { + isInJurisdiction = false; + break; + } + } + } + return isInJurisdiction ? WITHIN : BELOW; +} + + +bool JurisdictionMap::readFromFile(const char* filename) { + QString settingsFile(filename); + QSettings settings(settingsFile, QSettings::IniFormat); + QString rootCode = settings.value("root","00").toString(); + qCDebug(octree) << "rootCode=" << rootCode; + + std::lock_guard lock(_octalCodeMutex); + _rootOctalCode = hexStringToOctalCode(rootCode); + printOctalCode(_rootOctalCode.get()); + + settings.beginGroup("endNodes"); + const QStringList childKeys = settings.childKeys(); + QHash values; + foreach (const QString &childKey, childKeys) { + QString childValue = settings.value(childKey).toString(); + values.insert(childKey, childValue); + qCDebug(octree) << childKey << "=" << childValue; + + auto octcode = hexStringToOctalCode(childValue); + printOctalCode(octcode.get()); + + _endNodes.push_back(octcode); + } + settings.endGroup(); + return true; +} + +void JurisdictionMap::displayDebugDetails() const { + std::lock_guard lock(_octalCodeMutex); + + QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get()); + + qCDebug(octree) << "root:" << rootNodeValue; + + for (size_t i = 0; i < _endNodes.size(); i++) { + QString value = octalCodeToHexString(_endNodes[i].get()); + qCDebug(octree) << "End node[" << i << "]: " << rootNodeValue; + } +} + + +bool JurisdictionMap::writeToFile(const char* filename) { + QString settingsFile(filename); + QSettings settings(settingsFile, QSettings::IniFormat); + + std::lock_guard lock(_octalCodeMutex); + + QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get()); + + settings.setValue("root", rootNodeValue); + + settings.beginGroup("endNodes"); + for (size_t i = 0; i < _endNodes.size(); i++) { + QString key = QString("endnode%1").arg(i); + QString value = octalCodeToHexString(_endNodes[i].get()); + settings.setValue(key, value); + } + settings.endGroup(); + return true; +} + +std::unique_ptr JurisdictionMap::packEmptyJurisdictionIntoMessage(NodeType_t type) { + int bytes = 0; + auto packet = NLPacket::create(PacketType::Jurisdiction, sizeof(type) + sizeof(bytes)); + + // Pack the Node Type in first byte + packet->writePrimitive(type); + // No root or end node details to pack! + packet->writePrimitive(bytes); + + return packet; // includes header! +} + +std::unique_ptr JurisdictionMap::packIntoPacket() { + auto packet = NLPacket::create(PacketType::Jurisdiction); + + // Pack the Node Type in first byte + NodeType_t type = getNodeType(); + packet->writePrimitive(type); + + // add the root jurisdiction + std::lock_guard lock(_octalCodeMutex); + if (_rootOctalCode) { + size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_rootOctalCode.get())); + // No root or end node details to pack! + packet->writePrimitive(bytes); + packet->write(reinterpret_cast(_rootOctalCode.get()), bytes); + + // if and only if there's a root jurisdiction, also include the end nodes + int endNodeCount = (int)_endNodes.size(); + packet->writePrimitive(endNodeCount); + + for (int i=0; i < endNodeCount; i++) { + auto endNodeCode = _endNodes[i].get(); + size_t bytes = 0; + if (endNodeCode) { + bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode)); + } + packet->writePrimitive(bytes); + packet->write(reinterpret_cast(endNodeCode), bytes); + } + } else { + int bytes = 0; + packet->writePrimitive(bytes); + } + + return packet; +} + +int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) { + // read the root jurisdiction + int bytes = 0; + message.readPrimitive(&bytes); + + std::lock_guard lock(_octalCodeMutex); + _rootOctalCode = nullptr; + _endNodes.clear(); + + if (bytes > 0 && bytes <= message.getBytesLeftToRead()) { + _rootOctalCode = createOctalCodePtr(bytes); + message.read(reinterpret_cast(_rootOctalCode.get()), bytes); + + // if and only if there's a root jurisdiction, also include the end nodes + int endNodeCount = 0; + message.readPrimitive(&endNodeCount); + + for (int i = 0; i < endNodeCount; i++) { + int bytes = 0; + message.readPrimitive(&bytes); + + if (bytes <= message.getBytesLeftToRead()) { + auto endNodeCode = createOctalCodePtr(bytes); + message.read(reinterpret_cast(endNodeCode.get()), bytes); + + // if the endNodeCode was 0 length then don't add it + if (bytes > 0) { + _endNodes.push_back(endNodeCode); + } + } + } + } + + return message.getPosition(); // excludes header +} diff --git a/libraries/octree/src/JurisdictionMap.h b/libraries/octree/src/JurisdictionMap.h new file mode 100644 index 0000000000..b5a311c3d9 --- /dev/null +++ b/libraries/octree/src/JurisdictionMap.h @@ -0,0 +1,88 @@ +// +// JurisdictionMap.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 8/1/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_JurisdictionMap_h +#define hifi_JurisdictionMap_h + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +class JurisdictionMap { +public: + enum Area { + ABOVE, + WITHIN, + BELOW + }; + + // standard constructors + JurisdictionMap(NodeType_t type = NodeType::EntityServer); // default constructor + JurisdictionMap(const JurisdictionMap& other); // copy constructor + + // standard assignment + JurisdictionMap& operator=(const JurisdictionMap& other); // copy assignment + + // application constructors + JurisdictionMap(const char* filename); + JurisdictionMap(const char* rootHextString, const char* endNodesHextString); + + ~JurisdictionMap(); + + Area isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const; + + bool writeToFile(const char* filename); + bool readFromFile(const char* filename); + + // Provide an atomic way to get both the rootOctalCode and endNodeOctalCodes. + std::tuple getRootAndEndNodeOctalCodes() const; + OctalCodePtr getRootOctalCode() const; + OctalCodePtrList getEndNodeOctalCodes() const; + + void copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn); + + int unpackFromPacket(ReceivedMessage& message); + std::unique_ptr packIntoPacket(); + + /// Available to pack an empty or unknown jurisdiction into a network packet, used when no JurisdictionMap is available + static std::unique_ptr packEmptyJurisdictionIntoMessage(NodeType_t type); + + void displayDebugDetails() const; + + NodeType_t getNodeType() const { return _nodeType; } + void setNodeType(NodeType_t type) { _nodeType = type; } + +private: + void copyContents(const JurisdictionMap& other); // use assignment instead + void init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes); + + mutable std::mutex _octalCodeMutex; + OctalCodePtr _rootOctalCode { nullptr }; + OctalCodePtrList _endNodes; + NodeType_t _nodeType; +}; + +/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are +/// managing which jurisdictions. +class NodeToJurisdictionMap : public QMap, public ReadWriteLockable {}; +typedef QMap::iterator NodeToJurisdictionMapIterator; + + +#endif // hifi_JurisdictionMap_h diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp new file mode 100644 index 0000000000..dfe1a6d872 --- /dev/null +++ b/libraries/octree/src/JurisdictionSender.cpp @@ -0,0 +1,68 @@ +// +// JurisdictionSender.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 8/12/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include +#include +#include +#include "JurisdictionSender.h" + + +JurisdictionSender::JurisdictionSender(JurisdictionMap* map, NodeType_t type) : + ReceivedPacketProcessor(), + _jurisdictionMap(map), + _nodeType(type), + _packetSender(JurisdictionSender::DEFAULT_PACKETS_PER_SECOND) +{ +} + +JurisdictionSender::~JurisdictionSender() { +} + +void JurisdictionSender::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { + if (message->getType() == PacketType::JurisdictionRequest) { + lockRequestingNodes(); + _nodesRequestingJurisdictions.push(sendingNode->getUUID()); + unlockRequestingNodes(); + } +} + +bool JurisdictionSender::process() { + bool continueProcessing = isStillRunning(); + + // call our ReceivedPacketProcessor base class process so we'll get any pending packets + if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) { + int nodeCount = 0; + + lockRequestingNodes(); + while (!_nodesRequestingJurisdictions.empty()) { + + QUuid nodeUUID = _nodesRequestingJurisdictions.front(); + _nodesRequestingJurisdictions.pop(); + SharedNodePointer node = DependencyManager::get()->nodeWithUUID(nodeUUID); + + if (node && node->getActiveSocket()) { + auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket() + : JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType()); + _packetSender.queuePacketForSending(node, std::move(packet)); + nodeCount++; + } + } + unlockRequestingNodes(); + + // set our packets per second to be the number of nodes + _packetSender.setPacketsPerSecond(nodeCount); + + continueProcessing = _packetSender.process(); + } + return continueProcessing; +} diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h new file mode 100644 index 0000000000..b2d738cd36 --- /dev/null +++ b/libraries/octree/src/JurisdictionSender.h @@ -0,0 +1,58 @@ +// +// JurisdictionSender.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 8/12/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_JurisdictionSender_h +#define hifi_JurisdictionSender_h + +#include +#include + +#include +#include +#include "JurisdictionMap.h" + +/// Will process PacketType::_JURISDICTION_REQUEST packets and send out PacketType::_JURISDICTION packets +/// to requesting parties. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets +/// and adding them to the processing queue by calling queueReceivedPacket() +class JurisdictionSender : public ReceivedPacketProcessor { + Q_OBJECT +public: + static const int DEFAULT_PACKETS_PER_SECOND = 1; + + JurisdictionSender(JurisdictionMap* map, NodeType_t type = NodeType::EntityServer); + ~JurisdictionSender(); + + void setJurisdiction(JurisdictionMap* map) { _jurisdictionMap = map; } + + virtual bool process() override; + + NodeType_t getNodeType() const { return _nodeType; } + void setNodeType(NodeType_t type) { _nodeType = type; } + +protected: + virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; + + /// Locks all the resources of the thread. + void lockRequestingNodes() { _requestingNodeMutex.lock(); } + + /// Unlocks all the resources of the thread. + void unlockRequestingNodes() { _requestingNodeMutex.unlock(); } + + +private: + QMutex _requestingNodeMutex; + JurisdictionMap* _jurisdictionMap; + std::queue _nodesRequestingJurisdictions; + NodeType_t _nodeType; + + PacketSender _packetSender; +}; +#endif // hifi_JurisdictionSender_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index c63ff2f560..3190f25d7e 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1020,6 +1020,16 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, return bytesAtThisLevel; } + // If we've been provided a jurisdiction map, then we need to honor it. + if (params.jurisdictionMap) { + // here's how it works... if we're currently above our root jurisdiction, then we proceed normally. + // but once we're in our own jurisdiction, then we need to make sure we're not below it. + if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), CHECK_NODE_ONLY)) { + params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION; + return bytesAtThisLevel; + } + } + ViewFrustum::intersection nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything) { float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, @@ -1142,9 +1152,18 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElementPointer childElement = element->getChildAtIndex(i); - // if the caller wants to include childExistsBits, then include them - if (params.includeExistsBits && childElement) { - childrenExistInTreeBits += (1 << (7 - i)); + // if the caller wants to include childExistsBits, then include them even if not in view, if however, + // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist + // even if they don't in our local tree + bool notMyJurisdiction = false; + if (params.jurisdictionMap) { + notMyJurisdiction = JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), i); + } + if (params.includeExistsBits) { + // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing + if (childElement || notMyJurisdiction) { + childrenExistInTreeBits += (1 << (7 - i)); + } } sortedChildren[i] = childElement; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 1648cb0f47..ec6a0e810d 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -24,6 +24,7 @@ #include #include +#include "JurisdictionMap.h" #include "OctreeElement.h" #include "OctreeElementBag.h" #include "OctreePacketData.h" @@ -61,6 +62,7 @@ const int NO_BOUNDARY_ADJUST = 0; const int LOW_RES_MOVING_ADJUST = 1; #define IGNORE_COVERAGE_MAP NULL +#define IGNORE_JURISDICTION_MAP NULL class EncodeBitstreamParams { public: @@ -75,6 +77,7 @@ public: int boundaryLevelAdjust; float octreeElementSizeScale; bool forceSendScene; + JurisdictionMap* jurisdictionMap; NodeData* nodeData; // output hints from the encode process @@ -84,6 +87,7 @@ public: NULL_NODE, NULL_NODE_DATA, TOO_DEEP, + OUT_OF_JURISDICTION, LOD_SKIP, OUT_OF_VIEW, WAS_IN_VIEW, @@ -101,6 +105,7 @@ public: int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, bool forceSendScene = true, + JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP, NodeData* nodeData = nullptr) : maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), @@ -110,6 +115,7 @@ public: boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), forceSendScene(forceSendScene), + jurisdictionMap(jurisdictionMap), nodeData(nodeData), stopReason(UNKNOWN) { @@ -125,6 +131,7 @@ public: case DIDNT_FIT: qDebug("DIDNT_FIT"); break; case NULL_NODE: qDebug("NULL_NODE"); break; case TOO_DEEP: qDebug("TOO_DEEP"); break; + case OUT_OF_JURISDICTION: qDebug("OUT_OF_JURISDICTION"); break; case LOD_SKIP: qDebug("LOD_SKIP"); break; case OUT_OF_VIEW: qDebug("OUT_OF_VIEW"); break; case WAS_IN_VIEW: qDebug("WAS_IN_VIEW"); break; @@ -141,6 +148,7 @@ public: case DIDNT_FIT: return QString("DIDNT_FIT"); break; case NULL_NODE: return QString("NULL_NODE"); break; case TOO_DEEP: return QString("TOO_DEEP"); break; + case OUT_OF_JURISDICTION: return QString("OUT_OF_JURISDICTION"); break; case LOD_SKIP: return QString("LOD_SKIP"); break; case OUT_OF_VIEW: return QString("OUT_OF_VIEW"); break; case WAS_IN_VIEW: return QString("WAS_IN_VIEW"); break; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 4f10c9bf79..7e46831faa 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -22,10 +22,13 @@ const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::D OctreeEditPacketSender::OctreeEditPacketSender() : + PacketSender(), _shouldSend(true), _maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES), - _releaseQueuedMessagesPending(false) + _releaseQueuedMessagesPending(false), + _serverJurisdictions(NULL) { + } OctreeEditPacketSender::~OctreeEditPacketSender() { @@ -37,8 +40,34 @@ OctreeEditPacketSender::~OctreeEditPacketSender() { bool OctreeEditPacketSender::serversExist() const { - auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); - return node && node->getActiveSocket(); + bool hasServers = false; + bool atLeastOneJurisdictionMissing = false; // assume the best + + DependencyManager::get()->eachNodeBreakable([&](const SharedNodePointer& node){ + if (node->getType() == getMyNodeType() && node->getActiveSocket()) { + + QUuid nodeUUID = node->getUUID(); + // If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server + if (_serverJurisdictions) { + // lookup our nodeUUID in the jurisdiction map, if it's missing then we're + // missing at least one jurisdiction + _serverJurisdictions->withReadLock([&] { + if ((*_serverJurisdictions).find(nodeUUID) == (*_serverJurisdictions).end()) { + atLeastOneJurisdictionMissing = true; + } + }); + } + hasServers = true; + } + + if (atLeastOneJurisdictionMissing) { + return false; // no point in looking further - return false from anonymous function + } else { + return true; + } + }); + + return (hasServers && !atLeastOneJurisdictionMissing); } // This method is called when the edit packet layer has determined that it has a fully formed packet destined for @@ -103,7 +132,7 @@ void OctreeEditPacketSender::queuePacketListToNode(const QUuid& nodeUUID, std::u } void OctreeEditPacketSender::processPreServerExistsPackets() { - assert(serversExist()); // we should only be here if we have servers + assert(serversExist()); // we should only be here if we have jurisdictions // First send out all the single message packets... _pendingPacketsLock.lock(); @@ -121,7 +150,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { _pendingPacketsLock.unlock(); - // if while waiting for the servers the caller called releaseQueuedMessages() + // if while waiting for the jurisdictions the caller called releaseQueuedMessages() // then we want to honor that request now. if (_releaseQueuedMessagesPending) { releaseQueuedMessages(); @@ -149,12 +178,34 @@ void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr packet return; // bail early } - assert(serversExist()); // we must have servers to be here!! + assert(serversExist()); // we must have jurisdictions to be here!! - auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); - if (node && node->getActiveSocket()) { - queuePacketToNode(node->getUUID(), std::move(packet)); - } + const unsigned char* octCode = reinterpret_cast(packet->getPayload()) + sizeof(short) + sizeof(quint64); + + // We want to filter out edit messages for servers based on the server's Jurisdiction + // But we can't really do that with a packed message, since each edit message could be destined + // for a different server... So we need to actually manage multiple queued packets... one + // for each server + + DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ + // only send to the NodeTypes that are getMyNodeType() + if (node->getActiveSocket() && node->getType() == getMyNodeType()) { + QUuid nodeUUID = node->getUUID(); + bool isMyJurisdiction = true; + // we need to get the jurisdiction for this + // here we need to get the "pending packet" for this server + _serverJurisdictions->withReadLock([&] { + const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; + isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); + }); + + if (isMyJurisdiction) { + // make a copy of this packet for this node and queue + auto packetCopy = NLPacket::createCopy(*packet); + queuePacketToNode(nodeUUID, std::move(packetCopy)); + } + } + }); } @@ -165,8 +216,8 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& return; // bail early } - // If we don't have servers, then we will simply queue up all of these packets and wait till we have - // servers for processing + // If we don't have jurisdictions, then we will simply queue up all of these packets and wait till we have + // jurisdictions for processing if (!serversExist()) { if (_maxPendingMessages > 0) { EditMessagePair messagePair { type, QByteArray(editMessage) }; @@ -184,80 +235,107 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& return; // bail early } + // We want to filter out edit messages for servers based on the server's Jurisdiction + // But we can't really do that with a packed message, since each edit message could be destined + // for a different server... So we need to actually manage multiple queued packets... one + // for each server _packetsQueueLock.lock(); - auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); - if (node && node->getActiveSocket()) { - QUuid nodeUUID = node->getUUID(); + DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ + // only send to the NodeTypes that are getMyNodeType() + if (node->getActiveSocket() && node->getType() == getMyNodeType()) { + QUuid nodeUUID = node->getUUID(); + bool isMyJurisdiction = true; - // for edit messages, we will attempt to combine multiple edit commands where possible, we - // don't do this for add because we send those reliably - if (type == PacketType::EntityAdd) { - auto newPacket = NLPacketList::create(type, QByteArray(), true, true); - auto nodeClockSkew = node->getClockSkewUsec(); - - // pack sequence number - quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; - newPacket->writePrimitive(sequence); - - // pack in timestamp - quint64 now = usecTimestampNow() + nodeClockSkew; - newPacket->writePrimitive(now); - - - // We call this virtual function that allows our specific type of EditPacketSender to - // fixup the buffer for any clock skew - if (nodeClockSkew != 0) { - adjustEditPacketForClockSkew(type, editMessage, nodeClockSkew); + if (type == PacketType::EntityErase) { + isMyJurisdiction = true; // send erase messages to all servers + } else if (_serverJurisdictions) { + // we need to get the jurisdiction for this + // here we need to get the "pending packet" for this server + _serverJurisdictions->withReadLock([&] { + if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { + const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; + isMyJurisdiction = (map.isMyJurisdiction(reinterpret_cast(editMessage.data()), + CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); + } else { + isMyJurisdiction = false; + } + }); } + if (isMyJurisdiction) { - newPacket->write(editMessage); + // for edit messages, we will attempt to combine multiple edit commands where possible, we + // don't do this for add because we send those reliably + if (type == PacketType::EntityAdd) { - // release the new packet - releaseQueuedPacketList(nodeUUID, std::move(newPacket)); + auto newPacket = NLPacketList::create(type, QByteArray(), true, true); + auto nodeClockSkew = node->getClockSkewUsec(); - // tell the sent packet history that we used a sequence number for an untracked packet - auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; - sentPacketHistory.untrackedPacketSent(sequence); - } else { - // only a NLPacket for now - std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; + // pack sequence number + quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; + newPacket->writePrimitive(sequence); - if (!bufferedPacket) { - bufferedPacket = initializePacket(type, node->getClockSkewUsec()); - } else { - // If we're switching type, then we send the last one and start over - if ((type != bufferedPacket->getType() && bufferedPacket->getPayloadSize() > 0) || - (editMessage.size() >= bufferedPacket->bytesAvailableForWrite())) { + // pack in timestamp + quint64 now = usecTimestampNow() + nodeClockSkew; + newPacket->writePrimitive(now); - // create the new packet and swap it with the packet in _pendingEditPackets - auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); - bufferedPacket.swap(packetToRelease); - // release the previously buffered packet - releaseQueuedPacket(nodeUUID, std::move(packetToRelease)); + // We call this virtual function that allows our specific type of EditPacketSender to + // fixup the buffer for any clock skew + if (nodeClockSkew != 0) { + adjustEditPacketForClockSkew(type, editMessage, nodeClockSkew); + } + + newPacket->write(editMessage); + + // release the new packet + releaseQueuedPacketList(nodeUUID, std::move(newPacket)); + + // tell the sent packet history that we used a sequence number for an untracked packet + auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; + sentPacketHistory.untrackedPacketSent(sequence); + } else { + + std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now + + if (!bufferedPacket) { + bufferedPacket = initializePacket(type, node->getClockSkewUsec()); + } else { + // If we're switching type, then we send the last one and start over + if ((type != bufferedPacket->getType() && bufferedPacket->getPayloadSize() > 0) || + (editMessage.size() >= bufferedPacket->bytesAvailableForWrite())) { + + // create the new packet and swap it with the packet in _pendingEditPackets + auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); + bufferedPacket.swap(packetToRelease); + + // release the previously buffered packet + releaseQueuedPacket(nodeUUID, std::move(packetToRelease)); + } + } + + // This is really the first time we know which server/node this particular edit message + // is going to, so we couldn't adjust for clock skew till now. But here's our chance. + // We call this virtual function that allows our specific type of EditPacketSender to + // fixup the buffer for any clock skew + if (node->getClockSkewUsec() != 0) { + adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); + } + + bufferedPacket->write(editMessage); + } } - - // This is really the first time we know which server/node this particular edit message - // is going to, so we couldn't adjust for clock skew till now. But here's our chance. - // We call this virtual function that allows our specific type of EditPacketSender to - // fixup the buffer for any clock skew - if (node->getClockSkewUsec() != 0) { - adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); - } - - bufferedPacket->write(editMessage); } - } + }); _packetsQueueLock.unlock(); } void OctreeEditPacketSender::releaseQueuedMessages() { - // if we don't yet have servers then we can't actually release messages yet because we don't - // know where to send them to. Instead, just remember this request and when we eventually get servers + // if we don't yet have jurisdictions then we can't actually release messages yet because we don't + // know where to send them to. Instead, just remember this request and when we eventually get jurisdictions // call release again at that time. if (!serversExist()) { _releaseQueuedMessagesPending = true; @@ -319,8 +397,8 @@ std::unique_ptr OctreeEditPacketSender::initializePacket(PacketType ty } bool OctreeEditPacketSender::process() { - // if we have servers, and we have pending pre-servers exist packets, then process those - // before doing our normal process step. This processPreServerExistPackets() + // if we have server jurisdiction details, and we have pending pre-jurisdiction packets, then process those + // before doing our normal process step. This processPreJurisdictionPackets() if (serversExist() && (!_preServerEdits.empty() || !_preServerSingleMessagePackets.empty() )) { processPreServerExistsPackets(); } diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 8a33eb8b73..79c363bec5 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -17,6 +17,7 @@ #include #include +#include "JurisdictionMap.h" #include "SentPacketHistory.h" /// Utility for processing, packing, queueing and sending of outbound edit messages. @@ -48,6 +49,14 @@ public: /// in an application like interface when all octree features are disabled. void setShouldSend(bool shouldSend) { _shouldSend = shouldSend; } + /// call this to inform the OctreeEditPacketSender of the server jurisdictions. This is required for normal operation. + /// The internal contents of the jurisdiction map may change throughout the lifetime of the OctreeEditPacketSender. This map + /// can be set prior to servers being present, so long as the contents of the map accurately reflect the current + /// known jurisdictions. + void setServerJurisdictions(NodeToJurisdictionMap* serverJurisdictions) { + _serverJurisdictions = serverJurisdictions; + } + /// if you're running in non-threaded mode, you must call this method regularly virtual bool process() override; @@ -99,6 +108,8 @@ protected: std::list _preServerEdits; // these will get packed into other larger packets std::list> _preServerSingleMessagePackets; // these will go out as is + NodeToJurisdictionMap* _serverJurisdictions; + QMutex _releaseQueuedPacketMutex; // TODO: add locks for this and _pendingEditPackets diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 054603440d..09b2d6ddf5 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -37,13 +37,15 @@ OctreeSceneStats::OctreeSceneStats() : _incomingBytes(0), _incomingWastedBytes(0), _incomingOctreeSequenceNumberStats(), - _incomingFlightTimeAverage(samples) + _incomingFlightTimeAverage(samples), + _jurisdictionRoot(NULL) { reset(); } // copy constructor -OctreeSceneStats::OctreeSceneStats(const OctreeSceneStats& other) { +OctreeSceneStats::OctreeSceneStats(const OctreeSceneStats& other) : +_jurisdictionRoot(NULL) { copyFromOther(other); } @@ -107,6 +109,26 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _existsInPacketBitsWritten = other._existsInPacketBitsWritten; _treesRemoved = other._treesRemoved; + // before copying the jurisdictions, delete any current values... + _jurisdictionRoot = nullptr; + _jurisdictionEndNodes.clear(); + + // Now copy the values from the other + if (other._jurisdictionRoot) { + auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot.get())); + _jurisdictionRoot = createOctalCodePtr(bytes); + memcpy(_jurisdictionRoot.get(), other._jurisdictionRoot.get(), bytes); + } + for (size_t i = 0; i < other._jurisdictionEndNodes.size(); i++) { + auto& endNodeCode = other._jurisdictionEndNodes[i]; + if (endNodeCode) { + auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get())); + auto endNodeCodeCopy = createOctalCodePtr(bytes); + memcpy(endNodeCodeCopy.get(), endNodeCode.get(), bytes); + _jurisdictionEndNodes.push_back(endNodeCodeCopy); + } + } + _incomingPacket = other._incomingPacket; _incomingBytes = other._incomingBytes; _incomingWastedBytes = other._incomingWastedBytes; @@ -119,7 +141,8 @@ OctreeSceneStats::~OctreeSceneStats() { reset(); } -void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const OctreeElementPointer& root) { +void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const OctreeElementPointer& root, + JurisdictionMap* jurisdictionMap) { reset(); // resets packet and octree stats _isStarted = true; _start = usecTimestampNow(); @@ -130,6 +153,14 @@ void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const Octre _isFullScene = isFullScene; _isMoving = isMoving; + + // setup jurisdictions + if (jurisdictionMap) { + std::tie(_jurisdictionRoot, _jurisdictionEndNodes) = jurisdictionMap->getRootAndEndNodeOctalCodes(); + } else { + _jurisdictionRoot = nullptr; + _jurisdictionEndNodes.clear(); + } } void OctreeSceneStats::sceneCompleted() { @@ -205,6 +236,9 @@ void OctreeSceneStats::reset() { _existsBitsWritten = 0; _existsInPacketBitsWritten = 0; _treesRemoved = 0; + + _jurisdictionRoot = nullptr; + _jurisdictionEndNodes.clear(); } void OctreeSceneStats::packetSent(int bytes) { @@ -340,6 +374,29 @@ int OctreeSceneStats::packIntoPacket() { _statsPacket->writePrimitive(_existsInPacketBitsWritten); _statsPacket->writePrimitive(_treesRemoved); + // add the root jurisdiction + if (_jurisdictionRoot) { + // copy the + int bytes = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot.get())); + _statsPacket->writePrimitive(bytes); + _statsPacket->write(reinterpret_cast(_jurisdictionRoot.get()), bytes); + + // if and only if there's a root jurisdiction, also include the end elements + int endNodeCount = (int)_jurisdictionEndNodes.size(); + + _statsPacket->writePrimitive(endNodeCount); + + for (int i=0; i < endNodeCount; i++) { + auto& endNodeCode = _jurisdictionEndNodes[i]; + auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get())); + _statsPacket->writePrimitive(bytes); + _statsPacket->write(reinterpret_cast(endNodeCode.get()), bytes); + } + } else { + int bytes = 0; + _statsPacket->writePrimitive(bytes); + } + return _statsPacket->getPayloadSize(); } @@ -401,6 +458,38 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) { packet.readPrimitive(&_existsBitsWritten); packet.readPrimitive(&_existsInPacketBitsWritten); packet.readPrimitive(&_treesRemoved); + // before allocating new juridiction, clean up existing ones + _jurisdictionRoot = nullptr; + _jurisdictionEndNodes.clear(); + + // read the root jurisdiction + int bytes = 0; + packet.readPrimitive(&bytes); + + if (bytes == 0) { + _jurisdictionRoot = nullptr; + _jurisdictionEndNodes.clear(); + } else { + _jurisdictionRoot = createOctalCodePtr(bytes); + packet.read(reinterpret_cast(_jurisdictionRoot.get()), bytes); + + // if and only if there's a root jurisdiction, also include the end elements + _jurisdictionEndNodes.clear(); + + int endNodeCount = 0; + packet.readPrimitive(&endNodeCount); + + for (int i=0; i < endNodeCount; i++) { + int bytes = 0; + + packet.readPrimitive(&bytes); + + auto endNodeCode = createOctalCodePtr(bytes); + packet.read(reinterpret_cast(endNodeCode.get()), bytes); + + _jurisdictionEndNodes.push_back(endNodeCode); + } + } // running averages _elapsedAverage.updateAverage((float)_elapsed); diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index 78b4dfd26f..3774d4287d 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -17,6 +17,7 @@ #include #include +#include "JurisdictionMap.h" #include "OctreePacketData.h" #include "SequenceNumberStats.h" #include "OctalCode.h" @@ -38,7 +39,7 @@ public: OctreeSceneStats& operator= (const OctreeSceneStats& other); // copy assignment /// Call when beginning the computation of a scene. Initializes internal structures - void sceneStarted(bool fullScene, bool moving, const OctreeElementPointer& root); + void sceneStarted(bool fullScene, bool moving, const OctreeElementPointer& root, JurisdictionMap* jurisdictionMap); bool getIsSceneStarted() const { return _isStarted; } /// Call when the computation of a scene is completed. Finalizes internal structures @@ -142,6 +143,12 @@ public: /// \param Item item The item from the stats you're interested in. const char* getItemValue(Item item); + /// Returns OctCode for root element of the jurisdiction of this particular octree server + OctalCodePtr getJurisdictionRoot() const { return _jurisdictionRoot; } + + /// Returns list of OctCodes for end elements of the jurisdiction of this particular octree server + const OctalCodePtrList& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; } + bool isMoving() const { return _isMoving; } bool isFullScene() const { return _isFullScene; } quint64 getTotalElements() const { return _totalElements; } @@ -270,6 +277,9 @@ private: static ItemInfo _ITEMS[]; static const int MAX_ITEM_VALUE_LENGTH = 128; char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH]; + + OctalCodePtr _jurisdictionRoot; + std::vector _jurisdictionEndNodes; }; /// Map between element IDs and their reported OctreeSceneStats. Typically used by classes that need to know which elements sent diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 618e8ac469..8913e88cf5 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -13,9 +13,12 @@ #include "OctreeScriptingInterface.h" -OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender) : +OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender, + JurisdictionListener* jurisdictionListener) : _packetSender(packetSender), - _managedPacketSender(false), + _jurisdictionListener(jurisdictionListener), + _managedPacketSender(false), + _managedJurisdictionListener(false), _initialized(false) { } @@ -25,6 +28,12 @@ OctreeScriptingInterface::~OctreeScriptingInterface() { } void OctreeScriptingInterface::cleanupManagedObjects() { + if (_managedJurisdictionListener) { + _jurisdictionListener->terminate(); + _jurisdictionListener->deleteLater(); + _managedJurisdictionListener = false; + _jurisdictionListener = NULL; + } if (_managedPacketSender) { _packetSender->terminate(); _packetSender->deleteLater(); @@ -37,16 +46,29 @@ void OctreeScriptingInterface::setPacketSender(OctreeEditPacketSender* packetSen _packetSender = packetSender; } +void OctreeScriptingInterface::setJurisdictionListener(JurisdictionListener* jurisdictionListener) { + _jurisdictionListener = jurisdictionListener; +} + void OctreeScriptingInterface::init() { if (_initialized) { return; } + if (_jurisdictionListener) { + _managedJurisdictionListener = false; + } else { + _managedJurisdictionListener = true; + _jurisdictionListener = new JurisdictionListener(getServerNodeType()); + _jurisdictionListener->initialize(true); + } + if (_packetSender) { _managedPacketSender = false; } else { _managedPacketSender = true; _packetSender = createPacketSender(); + _packetSender->setServerJurisdictions(_jurisdictionListener->getJurisdictions()); } if (QCoreApplication::instance()) { diff --git a/libraries/octree/src/OctreeScriptingInterface.h b/libraries/octree/src/OctreeScriptingInterface.h index c31da94532..86b9730393 100644 --- a/libraries/octree/src/OctreeScriptingInterface.h +++ b/libraries/octree/src/OctreeScriptingInterface.h @@ -14,18 +14,21 @@ #include +#include "JurisdictionListener.h" #include "OctreeEditPacketSender.h" /// handles scripting of Particle commands from JS passed to assigned clients class OctreeScriptingInterface : public QObject { Q_OBJECT public: - OctreeScriptingInterface(OctreeEditPacketSender* packetSender = nullptr); + OctreeScriptingInterface(OctreeEditPacketSender* packetSender = NULL, JurisdictionListener* jurisdictionListener = NULL); ~OctreeScriptingInterface(); OctreeEditPacketSender* getPacketSender() const { return _packetSender; } + JurisdictionListener* getJurisdictionListener() const { return _jurisdictionListener; } void setPacketSender(OctreeEditPacketSender* packetSender); + void setJurisdictionListener(JurisdictionListener* jurisdictionListener); void init(); virtual NodeType_t getServerNodeType() const = 0; @@ -83,7 +86,9 @@ public slots: protected: /// attached OctreeEditPacketSender that handles queuing and sending of packets to VS OctreeEditPacketSender* _packetSender = nullptr; + JurisdictionListener* _jurisdictionListener = nullptr; bool _managedPacketSender; + bool _managedJurisdictionListener; bool _initialized; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b91f4dd405..7717ceda6f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -594,72 +594,47 @@ void Model::calculateTriangleSets() { } } -void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene) { - if (_isVisible != isVisible) { - _isVisible = isVisible; - - bool isLayeredInFront = _isLayeredInFront; - bool isLayeredInHUD = _isLayeredInHUD; +void Model::setVisibleInScene(bool newValue, const render::ScenePointer& scene) { + if (_isVisible != newValue) { + _isVisible = newValue; render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); - }); + transaction.resetItem(item, _modelMeshRenderItemsMap[item]); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); - }); + transaction.resetItem(item, _collisionRenderItemsMap[item]); } scene->enqueueTransaction(transaction); } } -void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { - if (_isLayeredInFront != isLayeredInFront) { - _isLayeredInFront = isLayeredInFront; - - bool isVisible = _isVisible; - bool isLayeredInHUD = _isLayeredInHUD; +void Model::setLayeredInFront(bool layered, const render::ScenePointer& scene) { + if (_isLayeredInFront != layered) { + _isLayeredInFront = layered; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); + transaction.resetItem(item, _modelMeshRenderItemsMap[item]); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); + transaction.resetItem(item, _collisionRenderItemsMap[item]); } scene->enqueueTransaction(transaction); } } -void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene) { - if (_isLayeredInHUD != isLayeredInHUD) { - _isLayeredInHUD = isLayeredInHUD; - - bool isVisible = _isVisible; - bool isLayeredInFront = _isLayeredInFront; +void Model::setLayeredInHUD(bool layered, const render::ScenePointer& scene) { + if (_isLayeredInHUD != layered) { + _isLayeredInHUD = layered; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); + transaction.resetItem(item, _modelMeshRenderItemsMap[item]); } foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) { - data.setKey(isVisible, isLayeredInFront || isLayeredInHUD); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); + transaction.resetItem(item, _collisionRenderItemsMap[item]); } scene->enqueueTransaction(transaction); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4df7faac84..50ccb22131 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,9 +82,9 @@ public: const QUrl& getURL() const { return _url; } // new Scene/Engine rendering support - void setVisibleInScene(bool isVisible, const render::ScenePointer& scene); - void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); - void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); + void setVisibleInScene(bool newValue, const render::ScenePointer& scene); + void setLayeredInFront(bool layered, const render::ScenePointer& scene); + void setLayeredInHUD(bool layered, const render::ScenePointer& scene); bool needsFixupInScene() const; bool needsReload() const { return _needsReload; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index c69ec1ce84..0e793fef21 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -92,48 +92,8 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) { endResetModel(); } -TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent) - : QSortFilterProxyModel(parent) { -} - -int TabletButtonsProxyModel::pageIndex() const { - return _pageIndex; -} - -int TabletButtonsProxyModel::buttonIndex(const QString &uuid) { - if (!sourceModel() || _pageIndex < 0) { - return -1; - } - TabletButtonListModel* model = static_cast(sourceModel()); - for (int i = 0; i < model->rowCount(); i++) { - TabletButtonProxy* bproxy = model->data(model->index(i), ButtonProxyRole).value(); - if (bproxy && bproxy->getUuid().toString().contains(uuid)) { - return i - (_pageIndex*TabletScriptingInterface::ButtonsOnPage); - } - } - return -1; -} - -void TabletButtonsProxyModel::setPageIndex(int pageIndex) -{ - if (_pageIndex == pageIndex) - return; - - _pageIndex = pageIndex; - invalidateFilter(); - emit pageIndexChanged(_pageIndex); -} - -bool TabletButtonsProxyModel::filterAcceptsRow(int sourceRow, - const QModelIndex &sourceParent) const { - Q_UNUSED(sourceParent); - return (sourceRow >= _pageIndex*TabletScriptingInterface::ButtonsOnPage - && sourceRow < (_pageIndex + 1)*TabletScriptingInterface::ButtonsOnPage); -} - TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums"); - qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletButtonsProxyModel"); } TabletScriptingInterface::~TabletScriptingInterface() { @@ -809,7 +769,6 @@ void TabletProxy::sendToQml(const QVariant& msg) { } - OffscreenQmlSurface* TabletProxy::getTabletSurface() { return _qmlOffscreenSurface; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 56e3ae257b..d24b3b6947 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -47,10 +46,6 @@ public: enum TabletAudioEvents { ButtonClick, ButtonHover, TabletOpen, TabletHandsIn, TabletHandsOut, Last}; Q_ENUM(TabletAudioEvents) - //Different useful constants - enum TabletConstants { ButtonsColumnsOnPage = 3, ButtonsRowsOnPage = 4, ButtonsOnPage = 12 }; - Q_ENUM(TabletConstants) - TabletScriptingInterface(); virtual ~TabletScriptingInterface(); static const QString QML; @@ -123,31 +118,6 @@ protected: Q_DECLARE_METATYPE(TabletButtonListModel*); -class TabletButtonsProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - - Q_PROPERTY(int pageIndex READ pageIndex WRITE setPageIndex NOTIFY pageIndexChanged) -public: - TabletButtonsProxyModel(QObject* parent = 0); - int pageIndex() const; - Q_INVOKABLE int buttonIndex(const QString& uuid); - -public slots: - void setPageIndex(int pageIndex); - -signals: - void pageIndexChanged(int pageIndex); - -protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - -private: - int _pageIndex { -1 }; -}; - -Q_DECLARE_METATYPE(TabletButtonsProxyModel*); - /**jsdoc * @class TabletProxy * @property name {string} READ_ONLY: name of this tablet @@ -264,7 +234,6 @@ public: QQuickItem* getQmlMenu() const; TabletButtonListModel* getButtons() { return &_buttons; } - signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index b3e3134380..cde44e78c9 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -103,7 +103,6 @@ case 'transactionHistory_linkClicked': tablet.gotoWebScreen(message.marketplaceLink, MARKETPLACES_INJECT_SCRIPT_URL); break; - case 'goToPurchases_fromWalletHome': case 'goToPurchases': tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH); break; diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js index fb49de1050..2b016884f1 100644 --- a/scripts/system/html/js/marketplacesInject.js +++ b/scripts/system/html/js/marketplacesInject.js @@ -29,7 +29,7 @@ var commerceMode = false; var userIsLoggedIn = false; var walletNeedsSetup = false; - var marketplaceBaseURL = "https://highfidelity.com"; + var metaverseServerURL = "https://metaverse.highfidelity.com"; function injectCommonCode(isDirectoryPage) { @@ -58,7 +58,7 @@ ); // Footer. - var isInitialHiFiPage = location.href === marketplaceBaseURL + "/marketplace?"; + var isInitialHiFiPage = location.href === metaverseServerURL + "/marketplace?"; $("body").append( '
' + (!isInitialHiFiPage ? '' : '') + @@ -70,7 +70,7 @@ // Footer actions. $("#back-button").on("click", function () { - (document.referrer !== "") ? window.history.back() : window.location = (marketplaceBaseURL + "/marketplace?"); + (document.referrer !== "") ? window.history.back() : window.location = (metaverseServerURL + "/marketplace?"); }); $("#all-markets").on("click", function () { EventBridge.emitWebEvent(GOTO_DIRECTORY); @@ -89,7 +89,7 @@ window.location = "https://clara.io/library?gameCheck=true&public=true"; }); $('#exploreHifiMarketplace').on('click', function () { - window.location = marketplaceBaseURL + "/marketplace"; + window.location = "http://www.highfidelity.com/marketplace"; }); } @@ -658,9 +658,9 @@ var HIFI_ITEM_PAGE = 3; var pageType = DIRECTORY; - if (location.href.indexOf(marketplaceBaseURL + "/") !== -1) { pageType = HIFI; } + if (location.href.indexOf("highfidelity.com/") !== -1) { pageType = HIFI; } if (location.href.indexOf("clara.io/") !== -1) { pageType = CLARA; } - if (location.href.indexOf(marketplaceBaseURL + "/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } + if (location.href.indexOf("highfidelity.com/marketplace/items/") !== -1) { pageType = HIFI_ITEM_PAGE; } injectCommonCode(pageType === DIRECTORY); switch (pageType) { @@ -694,10 +694,7 @@ commerceMode = !!parsedJsonMessage.data.commerceMode; userIsLoggedIn = !!parsedJsonMessage.data.userIsLoggedIn; walletNeedsSetup = !!parsedJsonMessage.data.walletNeedsSetup; - marketplaceBaseURL = parsedJsonMessage.data.metaverseServerURL; - if (marketplaceBaseURL.indexOf('metaverse.') !== -1) { - marketplaceBaseURL = marketplaceBaseURL.replace('metaverse.', ''); - } + metaverseServerURL = parsedJsonMessage.data.metaverseServerURL; injectCode(); } }