diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a0030bc12..d7f9a7ca47 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2498,6 +2498,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo pauseUntilLoginDetermined(); } +void Application::setFailedToConnectToEntityServer() { + _failedToConnectToEntityServer = true; +} + void Application::updateVerboseLogging() { auto menu = Menu::getInstance(); if (!menu) { @@ -5912,7 +5916,7 @@ void Application::resetPhysicsReadyInformation() { _gpuTextureMemSizeStabilityCount = 0; _gpuTextureMemSizeAtLastCheck = 0; _physicsEnabled = false; - _octreeProcessor.startEntitySequence(); + _octreeProcessor.startSafeLanding(); } @@ -6162,6 +6166,24 @@ void Application::updateSecondaryCameraViewFrustum() { static bool domainLoadingInProgress = false; +void Application::tryToEnablePhysics() { + bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + + if (gpuTextureMemSizeStable() || !enableInterstitial) { + _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; + _lastQueriedViews.clear(); // Force new view. + + // process octree stats packets are sent in between full sends of a scene (this isn't currently true). + // We keep physics disabled until we've received a full scene and everything near the avatar in that + // scene is ready to compute its collision shape. + if (getMyAvatar()->isReadyForPhysics()) { + _physicsEnabled = true; + setIsInterstitialMode(false); + getMyAvatar()->updateMotionBehaviorFromMenu(); + } + } +} + void Application::update(float deltaTime) { PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_graphicsEngine._renderFrameCount + 1); @@ -6169,7 +6191,6 @@ void Application::update(float deltaTime) { return; } - if (!_physicsEnabled) { if (!domainLoadingInProgress) { PROFILE_ASYNC_BEGIN(app, "Scene Loading", ""); @@ -6178,24 +6199,16 @@ void Application::update(float deltaTime) { // we haven't yet enabled physics. we wait until we think we have all the collision information // for nearby entities before starting bullet up. - quint64 now = usecTimestampNow(); - if (isServerlessMode() || _octreeProcessor.isLoadSequenceComplete()) { - bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); - - if (gpuTextureMemSizeStable() || !enableInterstitial) { - // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway - _lastPhysicsCheckTime = now; - _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; - _lastQueriedViews.clear(); // Force new view. - - // process octree stats packets are sent in between full sends of a scene (this isn't currently true). - // We keep physics disabled until we've received a full scene and everything near the avatar in that - // scene is ready to compute its collision shape. - if (getMyAvatar()->isReadyForPhysics()) { - _physicsEnabled = true; - setIsInterstitialMode(false); - getMyAvatar()->updateMotionBehaviorFromMenu(); - } + if (isServerlessMode()) { + tryToEnablePhysics(); + } else if (_failedToConnectToEntityServer) { + if (_octreeProcessor.safeLandingIsActive()) { + _octreeProcessor.stopSafeLanding(); + } + } else { + _octreeProcessor.updateSafeLanding(); + if (_octreeProcessor.safeLandingIsComplete()) { + tryToEnablePhysics(); } } } else if (domainLoadingInProgress) { @@ -7144,13 +7157,17 @@ void Application::resettingDomain() { clearDomainOctreeDetails(false); } -void Application::nodeAdded(SharedNodePointer node) const { +void Application::nodeAdded(SharedNodePointer node) { if (node->getType() == NodeType::EntityServer) { - if (!_failedToConnectToEntityServer) { + if (_failedToConnectToEntityServer && !_entityServerConnectionTimer.isActive()) { + _failedToConnectToEntityServer = false; + _octreeProcessor.stopSafeLanding(); + _octreeProcessor.startSafeLanding(); + } else if (_entityServerConnectionTimer.isActive()) { _entityServerConnectionTimer.stop(); - _entityServerConnectionTimer.setInterval(ENTITY_SERVER_CONNECTION_TIMEOUT); - _entityServerConnectionTimer.start(); } + _entityServerConnectionTimer.setInterval(ENTITY_SERVER_CONNECTION_TIMEOUT); + _entityServerConnectionTimer.start(); } } @@ -7160,7 +7177,6 @@ void Application::nodeActivated(SharedNodePointer node) { #if !defined(DISABLE_QML) auto offscreenUi = getOffscreenUI(); - if (offscreenUi) { auto nodeList = DependencyManager::get(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 2cea492d56..2d6821bbd9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -512,7 +512,7 @@ private slots: void loadSettings(); void saveSettings() const; - void setFailedToConnectToEntityServer() { _failedToConnectToEntityServer = true; } + void setFailedToConnectToEntityServer(); bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); @@ -527,7 +527,7 @@ private slots: void domainURLChanged(QUrl domainURL); void updateWindowTitle() const; - void nodeAdded(SharedNodePointer node) const; + void nodeAdded(SharedNodePointer node); void nodeActivated(SharedNodePointer node); void nodeKilled(SharedNodePointer node); static void packetSent(quint64 length); @@ -564,6 +564,7 @@ private: void cleanupBeforeQuit(); void idle(); + void tryToEnablePhysics(); void update(float deltaTime); // Various helper functions called during update() @@ -786,8 +787,6 @@ private: qint64 _gpuTextureMemSizeStabilityCount { 0 }; qint64 _gpuTextureMemSizeAtLastCheck { 0 }; - quint64 _lastPhysicsCheckTime { usecTimestampNow() }; // when did we last check to see if physics was ready - bool _keyboardDeviceHasFocus { true }; ConnectionMonitor _connectionMonitor; diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 6b07e6717c..c6f908e039 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -63,7 +63,6 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag // construct a new packet from the piggybacked one auto buffer = std::unique_ptr(new char[piggybackBytes]); memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggybackBytes); - auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr()); message = QSharedPointer::create(*newPacket); } else { @@ -80,7 +79,6 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag const QUuid& senderUUID = sendingNode->getUUID(); if (!versionDebugSuppressMap.contains(senderUUID, packetType)) { - qDebug() << "Was stats packet? " << wasStatsPacket; qDebug() << "OctreePacketProcessor - piggyback packet version mismatch on" << packetType << "- Sender" << senderUUID << "sent" << (int) message->getVersion() << "but" @@ -115,7 +113,9 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag auto renderer = qApp->getEntities(); if (renderer) { renderer->processDatagram(*message, sendingNode); - _safeLanding->noteReceivedsequenceNumber(renderer->getLastOctreeMessageSequence()); + if (_safeLanding && _safeLanding->isTracking()) { + _safeLanding->addToSequence(renderer->getLastOctreeMessageSequence()); + } } } } break; @@ -124,7 +124,9 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag // Read sequence # OCTREE_PACKET_SEQUENCE completionNumber; message->readPrimitive(&completionNumber); - _safeLanding->setCompletionSequenceNumbers(0, completionNumber); + if (_safeLanding) { + _safeLanding->finishSequence(0, completionNumber); + } } break; default: { @@ -133,6 +135,31 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag } } -void OctreePacketProcessor::startEntitySequence() { - _safeLanding->startEntitySequence(qApp->getEntities()); +void OctreePacketProcessor::startSafeLanding() { + if (_safeLanding) { + _safeLanding->startTracking(qApp->getEntities()); + } +} + +void OctreePacketProcessor::updateSafeLanding() { + if (_safeLanding) { + _safeLanding->updateTracking(); + } +} + +void OctreePacketProcessor::stopSafeLanding() { + if (_safeLanding) { + _safeLanding->stopTracking(); + } +} + +bool OctreePacketProcessor::safeLandingIsActive() const { + return _safeLanding && _safeLanding->isTracking(); +} + +bool OctreePacketProcessor::safeLandingIsComplete() const { + if (_safeLanding) { + return _safeLanding->trackingIsComplete(); + } + return false; } diff --git a/interface/src/octree/OctreePacketProcessor.h b/interface/src/octree/OctreePacketProcessor.h index d6ffb942e6..eacc15f62d 100644 --- a/interface/src/octree/OctreePacketProcessor.h +++ b/interface/src/octree/OctreePacketProcessor.h @@ -25,8 +25,12 @@ public: OctreePacketProcessor(); ~OctreePacketProcessor(); - void startEntitySequence(); - bool isLoadSequenceComplete() const { return _safeLanding->isLoadSequenceComplete(); } + void startSafeLanding(); + void updateSafeLanding(); + void stopSafeLanding(); + bool safeLandingIsActive() const; + bool safeLandingIsComplete() const; + float domainLoadingProgress() const { return _safeLanding->loadingProgressPercentage(); } signals: diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index 2e11de508b..bcce86f9f9 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -33,61 +33,45 @@ bool SafeLanding::SequenceLessThan::operator()(const int& a, const int& b) const return lessThanWraparound(a, b); } -void SafeLanding::startEntitySequence(QSharedPointer entityTreeRenderer) { - +void SafeLanding::startTracking(QSharedPointer entityTreeRenderer) { if (!entityTreeRenderer.isNull()) { auto entityTree = entityTreeRenderer->getTree(); - if (entityTree) { + if (entityTree && !_trackingEntities) { Locker lock(_lock); _entityTreeRenderer = entityTreeRenderer; _trackedEntities.clear(); - _trackingEntities = true; _maxTrackedEntityCount = 0; + _initialStart = INVALID_SEQUENCE; + _initialEnd = INVALID_SEQUENCE; + _sequenceNumbers.clear(); + _trackingEntities = true; + _startTime = usecTimestampNow(); + connect(std::const_pointer_cast(entityTree).get(), &EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity, Qt::DirectConnection); connect(std::const_pointer_cast(entityTree).get(), &EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity); - _sequenceNumbers.clear(); - _initialStart = INVALID_SEQUENCE; - _initialEnd = INVALID_SEQUENCE; - _startTime = usecTimestampNow(); EntityTreeRenderer::setEntityLoadingPriorityFunction(&ElevatedPriority); } } } -void SafeLanding::stopEntitySequence() { - Locker lock(_lock); - _trackingEntities = false; - _maxTrackedEntityCount = 0; - _trackedEntityStabilityCount = 0; - _initialStart = INVALID_SEQUENCE; - _initialEnd = INVALID_SEQUENCE; - _trackedEntities.clear(); - _sequenceNumbers.clear(); -} - void SafeLanding::addTrackedEntity(const EntityItemID& entityID) { - if (_trackingEntities) { + if (_trackingEntities && _entityTreeRenderer) { Locker lock(_lock); + auto entityTree = _entityTreeRenderer->getTree(); + if (entityTree) { + EntityItemPointer entity = entityTree->findEntityByID(entityID); + if (entity && !entity->isLocalEntity() && entity->getCreated() < _startTime) { + _trackedEntities.emplace(entityID, entity); - if (_entityTreeRenderer.isNull() || _entityTreeRenderer->getTree() == nullptr) { - return; - } - - EntityItemPointer entity = _entityTreeRenderer->getTree()->findEntityByID(entityID); - - if (entity && !entity->isLocalEntity() && entity->getCreated() < _startTime) { - - _trackedEntities.emplace(entityID, entity); - int trackedEntityCount = (int)_trackedEntities.size(); - - if (trackedEntityCount > _maxTrackedEntityCount) { - _maxTrackedEntityCount = trackedEntityCount; - _trackedEntityStabilityCount = 0; + int trackedEntityCount = (int)_trackedEntities.size(); + if (trackedEntityCount > _maxTrackedEntityCount) { + _maxTrackedEntityCount = trackedEntityCount; + _trackedEntityStabilityCount = 0; + } } - //qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName(); } } } @@ -97,32 +81,94 @@ void SafeLanding::deleteTrackedEntity(const EntityItemID& entityID) { _trackedEntities.erase(entityID); } -void SafeLanding::setCompletionSequenceNumbers(int first, int last) { +void SafeLanding::finishSequence(int first, int last) { Locker lock(_lock); - if (_initialStart == INVALID_SEQUENCE) { + if (_trackingEntities) { _initialStart = first; _initialEnd = last; } } -void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) { +void SafeLanding::addToSequence(int sequenceNumber) { + Locker lock(_lock); if (_trackingEntities) { - Locker lock(_lock); _sequenceNumbers.insert(sequenceNumber); } } -bool SafeLanding::isLoadSequenceComplete() { - if ((isEntityLoadingComplete() && isSequenceNumbersComplete()) || qApp->failedToConnectToEntityServer()) { - Locker lock(_lock); - _initialStart = INVALID_SEQUENCE; - _initialEnd = INVALID_SEQUENCE; - _entityTreeRenderer.clear(); - _trackingEntities = false; // Don't track anything else that comes in. - EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority); +void SafeLanding::updateTracking() { + if (!_trackingEntities || !_entityTreeRenderer) { + return; } - return !_trackingEntities; + { + Locker lock(_lock); + bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); + auto entityMapIter = _trackedEntities.begin(); + while (entityMapIter != _trackedEntities.end()) { + auto entity = entityMapIter->second; + bool isVisuallyReady = true; + if (enableInterstitial) { + auto entityRenderable = _entityTreeRenderer->renderableForEntityId(entityMapIter->first); + if (!entityRenderable) { + _entityTreeRenderer->addingEntity(entityMapIter->first); + } + isVisuallyReady = entity->isVisuallyReady() || (!entityRenderable && !entity->isParentPathComplete()); + } + if (isEntityPhysicsReady(entity) && isVisuallyReady) { + entityMapIter = _trackedEntities.erase(entityMapIter); + } else { + if (!isVisuallyReady) { + entity->requestRenderUpdate(); + } + entityMapIter++; + } + } + if (enableInterstitial) { + _trackedEntityStabilityCount++; + } + } + + if (_trackedEntities.empty()) { + // no more tracked entities --> check sequenceNumbers + if (_initialStart != INVALID_SEQUENCE) { + bool shouldStop = false; + { + Locker lock(_lock); + int sequenceSize = _initialStart <= _initialEnd ? _initialEnd - _initialStart: + _initialEnd + SEQUENCE_MODULO - _initialStart; + auto startIter = _sequenceNumbers.find(_initialStart); + auto endIter = _sequenceNumbers.find(_initialEnd - 1); + + bool missingSequenceNumbers = qApp->isMissingSequenceNumbers(); + shouldStop = (sequenceSize == 0 || + (startIter != _sequenceNumbers.end() && + endIter != _sequenceNumbers.end() && + ((distance(startIter, endIter) == sequenceSize - 1) || !missingSequenceNumbers))); + } + if (shouldStop) { + stopTracking(); + } + } + } +} + +void SafeLanding::stopTracking() { + Locker lock(_lock); + _trackingEntities = false; + if (_entityTreeRenderer) { + auto entityTree = _entityTreeRenderer->getTree(); + disconnect(std::const_pointer_cast(entityTree).get(), + &EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity); + disconnect(std::const_pointer_cast(entityTree).get(), + &EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity); + _entityTreeRenderer.reset(); + } + EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority); +} + +bool SafeLanding::trackingIsComplete() const { + return !_trackingEntities && (_initialStart != INVALID_SEQUENCE); } float SafeLanding::loadingProgressPercentage() { @@ -141,29 +187,6 @@ float SafeLanding::loadingProgressPercentage() { return entityReadyPercentage; } -bool SafeLanding::isSequenceNumbersComplete() { - if (_initialStart != INVALID_SEQUENCE) { - Locker lock(_lock); - int sequenceSize = _initialStart <= _initialEnd ? _initialEnd - _initialStart: - _initialEnd + SEQUENCE_MODULO - _initialStart; - auto startIter = _sequenceNumbers.find(_initialStart); - auto endIter = _sequenceNumbers.find(_initialEnd - 1); - - bool missingSequenceNumbers = qApp->isMissingSequenceNumbers(); - if (sequenceSize == 0 || - (startIter != _sequenceNumbers.end() - && endIter != _sequenceNumbers.end() - && ((distance(startIter, endIter) == sequenceSize - 1) || !missingSequenceNumbers))) { - bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); - if (!enableInterstitial) { - _trackingEntities = false; // Don't track anything else that comes in. - } - return true; - } - } - return false; -} - bool SafeLanding::isEntityPhysicsReady(const EntityItemPointer& entity) { if (entity && !entity->getCollisionless()) { const auto& entityType = entity->getType(); @@ -181,52 +204,9 @@ bool SafeLanding::isEntityPhysicsReady(const EntityItemPointer& entity) { } } } - return true; } -bool SafeLanding::isEntityLoadingComplete() { - Locker lock(_lock); - - - auto entityTree = qApp->getEntities(); - auto entityMapIter = _trackedEntities.begin(); - - bool enableInterstitial = DependencyManager::get()->getDomainHandler().getInterstitialModeEnabled(); - - while (entityMapIter != _trackedEntities.end()) { - auto entity = entityMapIter->second; - - bool isVisuallyReady = true; - - if (enableInterstitial) { - auto entityRenderable = entityTree->renderableForEntityId(entityMapIter->first); - if (!entityRenderable) { - entityTree->addingEntity(entityMapIter->first); - } - - isVisuallyReady = entity->isVisuallyReady() || (!entityRenderable && !entity->isParentPathComplete()); - } - - if (isEntityPhysicsReady(entity) && isVisuallyReady) { - entityMapIter = _trackedEntities.erase(entityMapIter); - } else { - if (!isVisuallyReady) { - entity->requestRenderUpdate(); - } - - entityMapIter++; - } - } - - if (enableInterstitial) { - _trackedEntityStabilityCount++; - } - - - return _trackedEntities.empty(); -} - float SafeLanding::ElevatedPriority(const EntityItem& entityItem) { return entityItem.getCollisionless() ? 0.0f : 10.0f; } diff --git a/interface/src/octree/SafeLanding.h b/interface/src/octree/SafeLanding.h index 428ca15bdc..2f1db2366f 100644 --- a/interface/src/octree/SafeLanding.h +++ b/interface/src/octree/SafeLanding.h @@ -25,11 +25,14 @@ class EntityItemID; class SafeLanding : public QObject { public: - void startEntitySequence(QSharedPointer entityTreeRenderer); - void stopEntitySequence(); - void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive. - void noteReceivedsequenceNumber(int sequenceNumber); - bool isLoadSequenceComplete(); + void startTracking(QSharedPointer entityTreeRenderer); + void updateTracking(); + void stopTracking(); + bool isTracking() const { return _trackingEntities; } + bool trackingIsComplete() const; + + void finishSequence(int first, int last); // 'last' exclusive. + void addToSequence(int sequenceNumber); float loadingProgressPercentage(); private slots: @@ -37,10 +40,8 @@ private slots: void deleteTrackedEntity(const EntityItemID& entityID); private: - bool isSequenceNumbersComplete(); bool isEntityPhysicsReady(const EntityItemPointer& entity); void debugDumpSequenceIDs() const; - bool isEntityLoadingComplete(); std::mutex _lock; using Locker = std::lock_guard;