diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e70375e47..db29892798 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6755,7 +6755,7 @@ void Application::updateWindowTitle() const { DependencyManager::get< MessagesClient >()->sendLocalMessage("Toolbar-DomainChanged", ""); } -void Application::clearDomainOctreeDetails() { +void Application::clearDomainOctreeDetails(bool clearAll) { // before we delete all entities get MyAvatar's AvatarEntityData ready getMyAvatar()->prepareAvatarEntityDataForReload(); @@ -6774,7 +6774,8 @@ void Application::clearDomainOctreeDetails() { }); // reset the model renderer - getEntities()->clear(); + qDebug() << "-----> clearAll: " << clearAll; + clearAll ? getEntities()->clear() : getEntities()->clearDomainEntities(); auto skyStage = DependencyManager::get()->getSkyStage(); @@ -6812,7 +6813,7 @@ void Application::goToErrorDomainURL(QUrl errorDomainURL) { void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; - clearDomainOctreeDetails(); + clearDomainOctreeDetails(false); } void Application::nodeAdded(SharedNodePointer node) const { @@ -6898,7 +6899,7 @@ void Application::nodeKilled(SharedNodePointer node) { QMetaObject::invokeMethod(DependencyManager::get().data(), "audioMixerKilled"); } else if (node->getType() == NodeType::EntityServer) { // we lost an entity server, clear all of the domain octree details - clearDomainOctreeDetails(); + clearDomainOctreeDetails(false); } else if (node->getType() == NodeType::AssetServer) { // asset server going away - check if we have the asset browser showing diff --git a/interface/src/Application.h b/interface/src/Application.h index 4c6d45b8c3..05d6135a93 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -469,7 +469,7 @@ private slots: void onDesktopRootItemCreated(QQuickItem* qmlContext); void onDesktopRootContextCreated(QQmlContext* qmlContext); void showDesktop(); - void clearDomainOctreeDetails(); + void clearDomainOctreeDetails(bool clearAll = true); void onAboutToQuit(); void onPresent(quint32 frameCount); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 380998321f..23b2bda555 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -197,9 +197,8 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() { }); } -void EntityTreeRenderer::clear() { - leaveAllEntities(); - +void EntityTreeRenderer::stopEntityScripts() { + leaveAllEntities(); // unload and stop the engine if (_entitiesScriptEngine) { // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread @@ -211,6 +210,42 @@ void EntityTreeRenderer::clear() { if (_wantScripts && !_shuttingDown) { resetEntitiesScriptEngine(); } +} + +void EntityTreeRenderer::clearDomainEntities() { + stopEntityScripts(); + + std::unordered_map savedEntities; + // remove all entities from the scene + _space->clear(); + auto scene = _viewState->getMain3DScene(); + if (scene) { + render::Transaction transaction; + for (const auto& entry : _entitiesInScene) { + const auto& renderer = entry.second; + const EntityItemPointer& entityItem = renderer->getEntity(); + if (entityItem->isDomainEntity()) { + renderer->removeFromScene(scene, transaction); + } else { + savedEntities[entry.first] = entry.second; + } + } + scene->enqueueTransaction(transaction); + } else { + qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown"; + } + _entitiesInScene.clear(); + _renderablesToUpdate = savedEntities; + _entitiesInScene = savedEntities; + + // reset the zone to the default (while we load the next scene) + _layeredZones.clear(); + + OctreeProcessor::clearDomainEntities(); +} + +void EntityTreeRenderer::clear() { + stopEntityScripts(); // remove all entities from the scene _space->clear(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index b4f0bda703..03d8ca9ff3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -86,6 +86,7 @@ public: virtual void init() override; /// clears the tree + virtual void clearDomainEntities() override; virtual void clear() override; /// reloads the entity scripts, calling unload and preload @@ -161,6 +162,7 @@ private: bool findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar = nullptr); bool applyLayeredZones(); + void stopEntityScripts(); void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index fb1a11d43f..a603d0004b 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -70,6 +70,39 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { return std::static_pointer_cast(newElement); } +void EntityTree::eraseDomainEntities() { + emit clearingEntities(); + + if (_simulation) { + _simulation->clearEntities(); + } + _staleProxies.clear(); + QHash localMap; + localMap.swap(_entityMap); + QHash savedEntities; + this->withWriteLock([&] { + foreach(EntityItemPointer entity, localMap) { + EntityTreeElementPointer element = entity->getElement(); + if (element) { + element->cleanupDomainEntities(); + } + + if (!entity->isDomainEntity()) { + savedEntities[entity->getEntityItemID()] = entity; + } + } + }); + localMap.clear(); + _entityMap = savedEntities; + + resetClientEditStats(); + clearDeletedEntities(); + + { + QWriteLocker locker(&_needsParentFixupLock); + _needsParentFixup.clear(); + } +} void EntityTree::eraseAllOctreeElements(bool createNewRoot) { emit clearingEntities(); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 9181a4851c..efd994acd2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -74,6 +74,8 @@ public: return std::static_pointer_cast(_rootElement); } + + virtual void eraseDomainEntities() override; virtual void eraseAllOctreeElements(bool createNewRoot = true) override; virtual void readBitstreamToTree(const unsigned char* bitstream, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2ece6835ea..8c65dd1c45 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -683,6 +683,23 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI return foundEntity; } +void EntityTreeElement::cleanupDomainEntities() { + withWriteLock([&] { + EntityItems savedEntities; + foreach(EntityItemPointer entity, _entityItems) { + if (entity->isDomainEntity()) { + entity->preDelete(); + entity->_element = NULL; + } else { + savedEntities.push_back(entity); + } + } + + _entityItems = savedEntities; + }); + bumpChangedContent(); +} + void EntityTreeElement::cleanupEntities() { withWriteLock([&] { foreach(EntityItemPointer entity, _entityItems) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index aed19eed15..34947fae5c 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -189,6 +189,7 @@ public: EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const; void getEntitiesInside(const AACube& box, QVector& foundEntities); + void cleanupDomainEntities(); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities bool removeEntityItem(EntityItemPointer entity, bool deletion = false); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index eef23493f6..200b3ebd60 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -149,6 +149,7 @@ public: OctreeElementPointer getRoot() { return _rootElement; } + virtual void eraseDomainEntities() { _isDirty = true; }; virtual void eraseAllOctreeElements(bool createNewRoot = true); virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args); diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index 206ff399d9..b3ae0ed113 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -197,6 +197,14 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe } } + +void OctreeProcessor::clearDomainEntities() { + if (_tree) { + _tree->withWriteLock([&] { + _tree->eraseDomainEntities(); + }); + } +} void OctreeProcessor::clear() { if (_tree) { _tree->withWriteLock([&] { diff --git a/libraries/octree/src/OctreeProcessor.h b/libraries/octree/src/OctreeProcessor.h index 1bc3bd10f9..a65531a4d7 100644 --- a/libraries/octree/src/OctreeProcessor.h +++ b/libraries/octree/src/OctreeProcessor.h @@ -43,6 +43,7 @@ public: virtual void init(); /// clears the tree + virtual void clearDomainEntities(); virtual void clear(); float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); }