From 09b498f9b25618d59688b27de2525c10719ba368 Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Mon, 3 Apr 2023 15:32:03 -0400 Subject: [PATCH 1/3] MAYA-128199 fix erro on save The problem was that when saving an anoynous layer, the stage changes since the root layer changes identity. We need to set the target layer, but not on the current stage, but on the new computed stage. Also, I added error messages when a save operation fails. - Add a helper function to retrieve the proxy shape node from its node name. - Pass the new layer to the helper function that sets the new proxy path of the proxy shape. - Make sure that all layer info contain th eproxy shape path since it is needed to update the target layer when a target anonymous layer is saved. - Renamed the saveRootLayer function to updateRootLayer since it is not saving the layer, it is updating the proxy shape. --- lib/mayaUsd/nodes/layerManager.cpp | 24 ++++++-- lib/mayaUsd/utils/util.cpp | 20 ++++--- lib/mayaUsd/utils/util.h | 5 ++ lib/mayaUsd/utils/utilSerialization.cpp | 72 ++++++++++++++++-------- lib/mayaUsd/utils/utilSerialization.h | 9 ++- lib/usd/ui/layerEditor/layerTreeItem.cpp | 7 ++- 6 files changed, 98 insertions(+), 39 deletions(-) diff --git a/lib/mayaUsd/nodes/layerManager.cpp b/lib/mayaUsd/nodes/layerManager.cpp index fc63179ec5..3a51494021 100644 --- a/lib/mayaUsd/nodes/layerManager.cpp +++ b/lib/mayaUsd/nodes/layerManager.cpp @@ -163,10 +163,10 @@ void convertAnonymousLayersRecursive( parentPtr._proxyPath = basename; } else if (stage->GetSessionLayer() == layer) { parentPtr._layerParent = nullptr; - parentPtr._proxyPath.clear(); + parentPtr._proxyPath = basename; } else { parentPtr._layerParent = layer; - parentPtr._proxyPath.clear(); + parentPtr._proxyPath = basename; } std::vector sublayers = layer->GetSubLayerPaths(); @@ -788,7 +788,12 @@ BatchSaveResult LayerDatabase::saveUsdToUsdFiles() SdfLayerHandleVector allLayers = info.stage->GetLayerStack(false); for (auto layer : allLayers) { if (layer->PermissionToSave()) { - MayaUsd::utils::saveLayerWithFormat(layer); + if (!MayaUsd::utils::saveLayerWithFormat(layer)) { + MString errMsg; + MString layerName(layer->GetDisplayName().c_str()); + errMsg.format("Could not save layer ^1s.", layerName); + MGlobal::displayError(errMsg); + } } } } @@ -814,14 +819,22 @@ void LayerDatabase::convertAnonymousLayers( // to convertAnonymousLayersRecursive root = stage->GetRootLayer(); if (root->IsAnonymous()) { + const bool wasTargetLayer = (stage->GetEditTarget().GetLayer() == root); PXR_NS::SdfFileFormat::FileFormatArguments args; std::string newFileName = MayaUsd::utils::generateUniqueFileName(proxyName); if (UsdMayaUtilFileSystem::requireUsdPathsRelativeToMayaSceneFile()) { newFileName = UsdMayaUtilFileSystem::getPathRelativeToMayaSceneFile(newFileName); } - MayaUsd::utils::saveLayerWithFormat(root, newFileName); + if (!MayaUsd::utils::saveLayerWithFormat(root, newFileName)) { + MString errMsg; + MString layerName(root->GetDisplayName().c_str()); + errMsg.format("Could not save layer ^1s.", layerName); + MGlobal::displayError(errMsg); + } - MayaUsd::utils::setNewProxyPath(pShape->name(), UsdMayaUtil::convert(newFileName)); + SdfLayerRefPtr newLayer = SdfLayer::FindOrOpen(newFileName); + MayaUsd::utils::setNewProxyPath( + pShape->name(), UsdMayaUtil::convert(newFileName), newLayer, wasTargetLayer); } SdfLayerHandle session = stage->GetSessionLayer(); @@ -830,6 +843,7 @@ void LayerDatabase::convertAnonymousLayers( saveUsdLayerToMayaFile(session, true); + // TODO: should update the target layer of the proxy shape if the session was the target. setValueForAttr( proxyNode, MayaUsdProxyShapeBase::sessionLayerNameAttr, diff --git a/lib/mayaUsd/utils/util.cpp b/lib/mayaUsd/utils/util.cpp index 7efd90a3a3..ab2cf25e5e 100644 --- a/lib/mayaUsd/utils/util.cpp +++ b/lib/mayaUsd/utils/util.cpp @@ -240,18 +240,22 @@ MStatus UsdMayaUtil::GetMObjectByName(const std::string& nodeName, MObject& mObj return GetMObjectByName(MString(nodeName.c_str()), mObj); } -UsdStageRefPtr UsdMayaUtil::GetStageByProxyName(const std::string& proxyPath) +MayaUsdProxyShapeBase* UsdMayaUtil::GetProxyShapeByProxyName(const std::string& proxyPath) { MObject mobj; MStatus status = UsdMayaUtil::GetMObjectByName(proxyPath, mobj); - if (status == MStatus::kSuccess) { - MFnDependencyNode fn; - fn.setObject(mobj); - MayaUsdProxyShapeBase* pShape = static_cast(fn.userNode()); - return pShape ? pShape->getUsdStage() : nullptr; - } + if (status != MStatus::kSuccess) + return nullptr; - return nullptr; + MFnDependencyNode fn; + fn.setObject(mobj); + return static_cast(fn.userNode()); +} + +UsdStageRefPtr UsdMayaUtil::GetStageByProxyName(const std::string& proxyPath) +{ + MayaUsdProxyShapeBase* pShape = UsdMayaUtil::GetProxyShapeByProxyName(proxyPath); + return pShape ? pShape->getUsdStage() : nullptr; } MStatus UsdMayaUtil::GetPlugByName(const std::string& attrPath, MPlug& plug) diff --git a/lib/mayaUsd/utils/util.h b/lib/mayaUsd/utils/util.h index 16cac1a73a..45e9348ef1 100644 --- a/lib/mayaUsd/utils/util.h +++ b/lib/mayaUsd/utils/util.h @@ -17,6 +17,7 @@ #define PXRUSDMAYA_UTIL_H #include +#include #include #include @@ -185,6 +186,10 @@ MStatus GetMObjectByName(const std::string& nodeName, MObject& mObj); MAYAUSD_CORE_PUBLIC MStatus GetMObjectByName(const MString& nodeName, MObject& mObj); +/// Gets the proxy shape node named \p nodeName. +MAYAUSD_CORE_PUBLIC +MayaUsdProxyShapeBase* GetProxyShapeByProxyName(const std::string& nodeName); + /// Gets the UsdStage for the proxy shape node named \p nodeName. MAYAUSD_CORE_PUBLIC UsdStageRefPtr GetStageByProxyName(const std::string& nodeName); diff --git a/lib/mayaUsd/utils/utilSerialization.cpp b/lib/mayaUsd/utils/utilSerialization.cpp index f0650d416e..eebf5096ee 100644 --- a/lib/mayaUsd/utils/utilSerialization.cpp +++ b/lib/mayaUsd/utils/utilSerialization.cpp @@ -17,7 +17,10 @@ #include #include +#include +#include #include +#include #include #include @@ -52,6 +55,7 @@ class RecursionDetector }; void populateChildren( + const std::string& proxyPath, const UsdStageRefPtr& stage, SdfLayerRefPtr layer, RecursionDetector* recursionDetector, @@ -71,13 +75,13 @@ void populateChildren( auto subLayer = PXR_NS::SdfLayer::FindOrOpen(actualPath); if (subLayer && !recursionDetector->contains(subLayer->GetRealPath())) { populateChildren( - stage, subLayer, recursionDetector, anonLayersToSave, dirtyLayersToSave); + proxyPath, stage, subLayer, recursionDetector, anonLayersToSave, dirtyLayersToSave); if (subLayer->IsAnonymous()) { MayaUsd::utils::LayerInfo info; info.stage = stage; info.layer = subLayer; - info.parent._proxyPath.clear(); + info.parent._proxyPath = proxyPath; info.parent._layerParent = layer; anonLayersToSave.push_back(info); } else if (subLayer->IsDirty()) { @@ -89,30 +93,40 @@ void populateChildren( recursionDetector->pop(); } -bool saveRootLayer(SdfLayerRefPtr layer, const std::string& proxy, bool savePathAsRelative) +void updateTargetLayer(const std::string& proxyNodeName, const SdfLayerRefPtr& layer) { - if (!layer || proxy.empty() || layer->IsAnonymous()) { - return false; + if (MayaUsdProxyShapeBase* proxyShape = UsdMayaUtil::GetProxyShapeByProxyName(proxyNodeName)) { + proxyShape->getUsdStage()->SetEditTarget(layer); } +} + +void updateRootLayer( + const std::string& proxy, + const std::string& layerPath, + const SdfLayerRefPtr& layer, + bool isTargetLayer) +{ + // Upda the root layer of the given proxy shape + if (layerPath.empty() || proxy.empty()) + return; - std::string fp = layer->GetRealPath(); #ifdef _WIN32 // Building a string that includes a file path for an executeCommand call // can be problematic, easier to just switch the path separator. - fp = TfStringReplace(fp, "\\", "/"); + const std::string fp = TfStringReplace(layerPath, "\\", "/"); +#else + const std::string& fp = layerPath; #endif - if (savePathAsRelative) { - fp = UsdMayaUtilFileSystem::getPathRelativeToMayaSceneFile(fp); - } - - MayaUsd::utils::setNewProxyPath(MString(proxy.c_str()), MString(fp.c_str())); - - return true; + MayaUsd::utils::setNewProxyPath(MString(proxy.c_str()), MString(fp.c_str()), layer, isTargetLayer); } void updateAllCachedStageWithLayer(SdfLayerRefPtr originalLayer, const std::string& newFilePath) { + // Update all known stage caches managed by the Maya USD plugin that contained + // stages using the original anonymous layer so that new stagesusing new saved + // layer are created with the load rules and the muted layers of the original + // stage. SdfLayerRefPtr newLayer = SdfLayer::FindOrOpen(newFilePath); if (!newLayer) { TF_WARN("The filename %s is an invalid file name for a layer.", newFilePath.c_str()); @@ -205,14 +219,21 @@ USDUnsavedEditsOption serializeUsdEditsLocationOption() } } // namespace MAYAUSD_NS_DEF -void setNewProxyPath(const MString& proxyNodeName, const MString& newValue) +void setNewProxyPath( + const MString& proxyNodeName, + const MString& newRootLayerPath, + const SdfLayerRefPtr& layer, + bool isTargetLayer) { MString script; - script.format("setAttr -type \"string\" ^1s.filePath \"^2s\"", proxyNodeName, newValue); + script.format("setAttr -type \"string\" ^1s.filePath \"^2s\"", proxyNodeName, newRootLayerPath); MGlobal::executeCommand( script, /*display*/ true, /*undo*/ false); + + if (isTargetLayer) + updateTargetLayer(proxyNodeName.asChar(), layer); } static bool isCompatibleWithSave( @@ -300,7 +321,9 @@ SdfLayerRefPtr saveAnonymousLayer( const bool wasTargetLayer = (stage->GetEditTarget().GetLayer() == anonLayer); - saveLayerWithFormat(anonLayer, filePath, formatArg); + if (!saveLayerWithFormat(anonLayer, filePath, formatArg)) { + return nullptr; + } const bool isSubLayer = (parent._layerParent != nullptr); std::string relativePathAnchor; @@ -326,14 +349,12 @@ SdfLayerRefPtr saveAnonymousLayer( if (newLayer) { if (isSubLayer) { updateSubLayer(parent._layerParent, anonLayer, filePath); + updateTargetLayer(parent._proxyPath, newLayer); } else if (!parent._proxyPath.empty()) { - saveRootLayer(newLayer, parent._proxyPath, savePathAsRelative); + updateRootLayer(parent._proxyPath, filePath, newLayer, wasTargetLayer); } } - if (wasTargetLayer) - stage->SetEditTarget(newLayer); - return newLayer; } @@ -383,7 +404,7 @@ void getLayersToSaveFromProxy(const std::string& proxyPath, StageLayersToSave& l auto root = stage->GetRootLayer(); populateChildren( - stage, root, nullptr, layersInfo._anonLayers, layersInfo._dirtyFileBackedLayers); + proxyPath, stage, root, nullptr, layersInfo._anonLayers, layersInfo._dirtyFileBackedLayers); if (root->IsAnonymous()) { LayerInfo info; info.stage = stage; @@ -397,7 +418,12 @@ void getLayersToSaveFromProxy(const std::string& proxyPath, StageLayersToSave& l auto session = stage->GetSessionLayer(); populateChildren( - stage, session, nullptr, layersInfo._anonLayers, layersInfo._dirtyFileBackedLayers); + proxyPath, + stage, + session, + nullptr, + layersInfo._anonLayers, + layersInfo._dirtyFileBackedLayers); } } // namespace utils diff --git a/lib/mayaUsd/utils/utilSerialization.h b/lib/mayaUsd/utils/utilSerialization.h index 6501e16950..3e87bd44db 100644 --- a/lib/mayaUsd/utils/utilSerialization.h +++ b/lib/mayaUsd/utils/utilSerialization.h @@ -62,10 +62,15 @@ MAYAUSD_CORE_PUBLIC USDUnsavedEditsOption serializeUsdEditsLocationOption(); /*! \brief Utility function to update the file path attribute on the proxy shape - when an anonymous root layer gets exported to disk. + when an anonymous root layer gets exported to disk. Also optionally updates + the target layer if the anonymous layer was the target layer. */ MAYAUSD_CORE_PUBLIC -void setNewProxyPath(const MString& proxyNodeName, const MString& newValue); +void setNewProxyPath( + const MString& proxyNodeName, + const MString& newValue, + const SdfLayerRefPtr& layer, + bool isTargetLayer); struct LayerParent { diff --git a/lib/usd/ui/layerEditor/layerTreeItem.cpp b/lib/usd/ui/layerEditor/layerTreeItem.cpp index c67305a314..25f6d55c89 100644 --- a/lib/usd/ui/layerEditor/layerTreeItem.cpp +++ b/lib/usd/ui/layerEditor/layerTreeItem.cpp @@ -352,7 +352,12 @@ void LayerTreeItem::saveEditsNoPrompt() if (!isSessionLayer()) saveAnonymousLayer(); } else { - MayaUsd::utils::saveLayerWithFormat(layer()); + if (!MayaUsd::utils::saveLayerWithFormat(layer())) { + MString errMsg; + MString layerName(layer()->GetDisplayName().c_str()); + errMsg.format("Could not save layer ^1s.", layerName); + MGlobal::displayError(errMsg); + } } } From 68fb83848c767e4e5e80fb39767cac0add2c2a9b Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Mon, 3 Apr 2023 15:36:15 -0400 Subject: [PATCH 2/3] MAYA-128199 code format --- lib/mayaUsd/utils/utilSerialization.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mayaUsd/utils/utilSerialization.cpp b/lib/mayaUsd/utils/utilSerialization.cpp index eebf5096ee..768edeef3d 100644 --- a/lib/mayaUsd/utils/utilSerialization.cpp +++ b/lib/mayaUsd/utils/utilSerialization.cpp @@ -118,7 +118,8 @@ void updateRootLayer( const std::string& fp = layerPath; #endif - MayaUsd::utils::setNewProxyPath(MString(proxy.c_str()), MString(fp.c_str()), layer, isTargetLayer); + MayaUsd::utils::setNewProxyPath( + MString(proxy.c_str()), MString(fp.c_str()), layer, isTargetLayer); } void updateAllCachedStageWithLayer(SdfLayerRefPtr originalLayer, const std::string& newFilePath) From c777ada8d99a10fae7f8736c455775808a67a02c Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Mon, 3 Apr 2023 17:01:07 -0400 Subject: [PATCH 3/3] MAYA-128199 build fix for Maya 2019 --- lib/mayaUsd/utils/utilSerialization.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mayaUsd/utils/utilSerialization.cpp b/lib/mayaUsd/utils/utilSerialization.cpp index 768edeef3d..272918de2e 100644 --- a/lib/mayaUsd/utils/utilSerialization.cpp +++ b/lib/mayaUsd/utils/utilSerialization.cpp @@ -17,8 +17,6 @@ #include #include -#include -#include #include #include #include