mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #14694 from danteruiz/delete-only-domain-entities
case 20595: case 20563: Do not delete local entities when switching domains.
This commit is contained in:
commit
45ec44423b
14 changed files with 200 additions and 25 deletions
|
@ -6757,7 +6757,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();
|
||||
|
||||
|
@ -6776,7 +6776,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
});
|
||||
|
||||
// reset the model renderer
|
||||
getEntities()->clear();
|
||||
clearAll ? getEntities()->clear() : getEntities()->clearNonLocalEntities();
|
||||
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
|
||||
|
@ -6814,7 +6814,7 @@ void Application::goToErrorDomainURL(QUrl errorDomainURL) {
|
|||
void Application::resettingDomain() {
|
||||
_notifiedPacketVersionMismatchThisDomain = false;
|
||||
|
||||
clearDomainOctreeDetails();
|
||||
clearDomainOctreeDetails(false);
|
||||
}
|
||||
|
||||
void Application::nodeAdded(SharedNodePointer node) const {
|
||||
|
@ -6900,7 +6900,7 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -197,9 +197,57 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
|||
});
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::stopNonLocalEntityScripts() {
|
||||
leaveNonLocalEntities();
|
||||
// unload and stop the engine
|
||||
if (_entitiesScriptEngine) {
|
||||
QList<EntityItemID> entitiesWithEntityScripts = _entitiesScriptEngine->getListOfEntityScriptIDs();
|
||||
|
||||
foreach (const EntityItemID& entityID, entitiesWithEntityScripts) {
|
||||
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
|
||||
|
||||
if (entityItem) {
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clearNonLocalEntities() {
|
||||
stopNonLocalEntityScripts();
|
||||
|
||||
std::unordered_map<EntityItemID, EntityRendererPointer> 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->isLocalEntity()) {
|
||||
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";
|
||||
}
|
||||
|
||||
_renderablesToUpdate = savedEntities;
|
||||
_entitiesInScene = savedEntities;
|
||||
|
||||
_layeredZones.clearNonLocalLayeredZones();
|
||||
|
||||
OctreeProcessor::clearNonLocalEntities();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clear() {
|
||||
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,8 +259,8 @@ void EntityTreeRenderer::clear() {
|
|||
if (_wantScripts && !_shuttingDown) {
|
||||
resetEntitiesScriptEngine();
|
||||
}
|
||||
|
||||
// remove all entities from the scene
|
||||
|
||||
_space->clear();
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (scene) {
|
||||
|
@ -507,8 +555,7 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityIt
|
|||
auto entityTree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
||||
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
|
||||
entityTree->evalEntitiesInSphere(_avatarPosition, radius,
|
||||
PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES)), entityIDs);
|
||||
entityTree->evalEntitiesInSphere(_avatarPosition, radius, PickFilter(), entityIDs);
|
||||
|
||||
LayeredZones oldLayeredZones(std::move(_layeredZones));
|
||||
_layeredZones.clear();
|
||||
|
@ -614,6 +661,26 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
return didUpdate;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveNonLocalEntities() {
|
||||
if (_tree && !_shuttingDown) {
|
||||
QVector<EntityItemID> currentLocalEntitiesInside;
|
||||
foreach (const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
|
||||
if (!entityItem->isLocalEntity()) {
|
||||
emit leaveEntity(entityID);
|
||||
if (_entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
}
|
||||
} else {
|
||||
currentLocalEntitiesInside.push_back(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
_currentEntitiesInside = currentLocalEntitiesInside;
|
||||
forceRecheckEntities();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::leaveAllEntities() {
|
||||
if (_tree && !_shuttingDown) {
|
||||
|
||||
|
@ -1136,6 +1203,29 @@ EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::clearNonLocalLayeredZones() {
|
||||
std::set<LayeredZone> localLayeredZones;
|
||||
std::map<QUuid, iterator> newMap;
|
||||
|
||||
for (auto iter = begin(); iter != end(); iter++) {
|
||||
LayeredZone layeredZone = *iter;
|
||||
|
||||
if (layeredZone.zone->isLocalEntity()) {
|
||||
bool success;
|
||||
iterator it;
|
||||
std::tie(it, success) = localLayeredZones.insert(layeredZone);
|
||||
|
||||
if (success) {
|
||||
newMap.emplace(layeredZone.id, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<LayeredZone>::operator=(localLayeredZones);
|
||||
_map = newMap;
|
||||
_skyboxLayer = empty() ? end() : begin();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::LayeredZones::clear() {
|
||||
std::set<LayeredZone>::clear();
|
||||
_map.clear();
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
virtual void init() override;
|
||||
|
||||
/// clears the tree
|
||||
virtual void clearNonLocalEntities() override;
|
||||
virtual void clear() override;
|
||||
|
||||
/// reloads the entity scripts, calling unload and preload
|
||||
|
@ -161,6 +162,7 @@ private:
|
|||
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
|
||||
|
||||
bool applyLayeredZones();
|
||||
void stopNonLocalEntityScripts();
|
||||
|
||||
void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false);
|
||||
|
||||
|
@ -169,6 +171,7 @@ private:
|
|||
|
||||
QScriptValueList createEntityArgs(const EntityItemID& entityID);
|
||||
bool checkEnterLeaveEntities();
|
||||
void leaveNonLocalEntities();
|
||||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
|
@ -219,6 +222,7 @@ private:
|
|||
LayeredZones& operator=(LayeredZones&&) = delete;
|
||||
|
||||
void clear();
|
||||
void clearNonLocalLayeredZones();
|
||||
std::pair<iterator, bool> insert(const LayeredZone& layer);
|
||||
void update(std::shared_ptr<ZoneEntityItem> zone);
|
||||
bool contains(const LayeredZones& other);
|
||||
|
|
|
@ -986,7 +986,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
|
|||
shouldSendDeleteToServer = false;
|
||||
} else {
|
||||
// only delete local entities, server entities will round trip through the server filters
|
||||
if (entity->isAvatarEntity() || _entityTree->isServerlessMode()) {
|
||||
if (!entity->isDomainEntity() || _entityTree->isServerlessMode()) {
|
||||
shouldSendDeleteToServer = false;
|
||||
_entityTree->deleteEntity(entityID);
|
||||
|
||||
|
|
|
@ -70,6 +70,49 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) {
|
|||
return std::static_pointer_cast<OctreeElement>(newElement);
|
||||
}
|
||||
|
||||
void EntityTree::eraseNonLocalEntities() {
|
||||
emit clearingEntities();
|
||||
|
||||
if (_simulation) {
|
||||
// This will clear all entities host types including local entities, because local entities
|
||||
// are not in the physics simulation
|
||||
_simulation->clearEntities();
|
||||
}
|
||||
_staleProxies.clear();
|
||||
QHash<EntityItemID, EntityItemPointer> localMap;
|
||||
localMap.swap(_entityMap);
|
||||
QHash<EntityItemID, EntityItemPointer> savedEntities;
|
||||
this->withWriteLock([&] {
|
||||
foreach(EntityItemPointer entity, localMap) {
|
||||
EntityTreeElementPointer element = entity->getElement();
|
||||
if (element) {
|
||||
element->cleanupNonLocalEntities();
|
||||
}
|
||||
|
||||
if (entity->isLocalEntity()) {
|
||||
savedEntities[entity->getEntityItemID()] = entity;
|
||||
}
|
||||
}
|
||||
});
|
||||
localMap.clear();
|
||||
_entityMap = savedEntities;
|
||||
|
||||
resetClientEditStats();
|
||||
clearDeletedEntities();
|
||||
|
||||
{
|
||||
QWriteLocker locker(&_needsParentFixupLock);
|
||||
QVector<EntityItemWeakPointer> localEntitiesNeedsParentFixup;
|
||||
|
||||
foreach (EntityItemWeakPointer entityItem, _needsParentFixup) {
|
||||
if (!entityItem.expired() && entityItem.lock()->isLocalEntity()) {
|
||||
localEntitiesNeedsParentFixup.push_back(entityItem);
|
||||
}
|
||||
}
|
||||
|
||||
_needsParentFixup = localEntitiesNeedsParentFixup;
|
||||
}
|
||||
}
|
||||
void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
||||
emit clearingEntities();
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ public:
|
|||
return std::static_pointer_cast<EntityTreeElement>(_rootElement);
|
||||
}
|
||||
|
||||
|
||||
virtual void eraseNonLocalEntities() override;
|
||||
virtual void eraseAllOctreeElements(bool createNewRoot = true) override;
|
||||
|
||||
virtual void readBitstreamToTree(const unsigned char* bitstream,
|
||||
|
|
|
@ -683,6 +683,23 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI
|
|||
return foundEntity;
|
||||
}
|
||||
|
||||
void EntityTreeElement::cleanupNonLocalEntities() {
|
||||
withWriteLock([&] {
|
||||
EntityItems savedEntities;
|
||||
foreach(EntityItemPointer entity, _entityItems) {
|
||||
if (!entity->isLocalEntity()) {
|
||||
entity->preDelete();
|
||||
entity->_element = NULL;
|
||||
} else {
|
||||
savedEntities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
_entityItems = savedEntities;
|
||||
});
|
||||
bumpChangedContent();
|
||||
}
|
||||
|
||||
void EntityTreeElement::cleanupEntities() {
|
||||
withWriteLock([&] {
|
||||
foreach(EntityItemPointer entity, _entityItems) {
|
||||
|
|
|
@ -189,6 +189,7 @@ public:
|
|||
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
|
||||
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
void cleanupNonLocalEntities();
|
||||
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
|
||||
bool removeEntityItem(EntityItemPointer entity, bool deletion = false);
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
|
||||
OctreeElementPointer getRoot() { return _rootElement; }
|
||||
|
||||
virtual void eraseNonLocalEntities() { _isDirty = true; };
|
||||
virtual void eraseAllOctreeElements(bool createNewRoot = true);
|
||||
|
||||
virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
|
|
|
@ -197,6 +197,14 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void OctreeProcessor::clearNonLocalEntities() {
|
||||
if (_tree) {
|
||||
_tree->withWriteLock([&] {
|
||||
_tree->eraseNonLocalEntities();
|
||||
});
|
||||
}
|
||||
}
|
||||
void OctreeProcessor::clear() {
|
||||
if (_tree) {
|
||||
_tree->withWriteLock([&] {
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
virtual void init();
|
||||
|
||||
/// clears the tree
|
||||
virtual void clearNonLocalEntities();
|
||||
virtual void clear();
|
||||
|
||||
float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); }
|
||||
|
|
|
@ -2407,6 +2407,11 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR
|
|||
}
|
||||
}
|
||||
|
||||
QList<EntityItemID> ScriptEngine::getListOfEntityScriptIDs() {
|
||||
QReadLocker locker{ &_entityScriptsLock };
|
||||
return _entityScripts.keys();
|
||||
}
|
||||
|
||||
void ScriptEngine::unloadAllEntityScripts() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
|
|
|
@ -145,6 +145,9 @@ public:
|
|||
|
||||
QString getFilename() const;
|
||||
|
||||
|
||||
QList<EntityItemID> getListOfEntityScriptIDs();
|
||||
|
||||
/**jsdoc
|
||||
* Stop the current script.
|
||||
* @function Script.stop
|
||||
|
|
Loading…
Reference in a new issue