From 7bf2b98dc254cf81ec62b25656812734cdfae81a Mon Sep 17 00:00:00 2001 From: Julien Frantz Date: Mon, 21 Oct 2024 12:20:20 +0200 Subject: [PATCH 1/5] mayaUsd.lib.proxyAccessor: parent/unparent python functions accept ufe paths as argument. --- lib/mayaUsd/nodes/proxyAccessor.py | 36 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/mayaUsd/nodes/proxyAccessor.py b/lib/mayaUsd/nodes/proxyAccessor.py index d7b4862226..37e7dc9fd2 100644 --- a/lib/mayaUsd/nodes/proxyAccessor.py +++ b/lib/mayaUsd/nodes/proxyAccessor.py @@ -90,10 +90,12 @@ def isUfeUsdPath(ufeObject): lastSegment = ufeObject.path().segments[segmentCount-1] return Sdf.Path.IsValidPathString(str(lastSegment)) +def _createUfeSceneItem(ufePathStr): + return ufe.Hierarchy.createItem(ufe.PathString.path(ufePathStr)) + def createUfeSceneItem(dagPath, sdfPath=None): - ufePath = ufe.PathString.path('{},{}'.format(dagPath,sdfPath) if sdfPath != None else '{}'.format(dagPath)) - ufeItem = ufe.Hierarchy.createItem(ufePath) - return ufeItem + ufePathStr = '{},{}'.format(dagPath,sdfPath) if sdfPath != None else '{}'.format(dagPath) + return _createUfeSceneItem(ufePathStr) def createXformOps(ufeObject): selDag, selPrim = getDagAndPrimFromUfe(ufeObject) @@ -323,18 +325,18 @@ def parentItems(ufeChildren, ufeParent, connect=True): # Cannot use 'visibility' here because it's already used by orphan manager connectParentChildAttr(parentVisibilityAttr, childDagPath, 'lodVisibility', connect) -def __parent(doParenting, forceUnparenting=False): - ufeSelection = iter(ufe.GlobalSelection.get()) - ufeSelectionList = [] - for ufeItem in ufeSelection: - ufeSelectionList.append(ufeItem) - - # clearing this selection so nobody will try to use it. - # next steps can result in new selection being made due to potential call to createAccessPlug - ufeSelection = None +def __parent(*ufeItemPathStrings, doParenting=True, forceUnparenting=False): + if ufeItemPathStrings: + ufeSelectionList = [_createUfeSceneItem(pStr) for pStr in ufeItemPathStrings] + else: + ufeSelection = iter(ufe.GlobalSelection.get()) + ufeSelectionList = [ufeItem for ufeItem in ufeSelection] + # clearing this selection so nobody will try to use it. + # next steps can result in new selection being made due to potential call to createAccessPlug + ufeSelection = None if len(ufeSelectionList) < 2: - print("Select at least two objects. DAG child/ren and USD parent at the end") + print("Provide or select at least two objects. DAG child/ren and USD parent at the end") return ufeParent = ufeSelectionList[-1] @@ -345,11 +347,11 @@ def __parent(doParenting, forceUnparenting=False): parentItems(ufeChildren, ufeParent, doParenting) -def parent(force=False): - __parent(True, forceUnparenting=force) +def parent(*ufeItemPathStrings, force=False): + __parent(*ufeItemPathStrings, doParenting=True, forceUnparenting=force) -def unparent(): - __parent(False) +def unparent(*ufeItemPathStrings): + __parent(*ufeItemPathStrings, doParenting=False) def connectItems(ufeObjectSrc, ufeObjectDst, attrToConnect): connectMayaToUsd = isUfeUsdPath(ufeObjectDst) From 008b0da02614858c69db628c03468dd7b9478f82 Mon Sep 17 00:00:00 2001 From: Julien Frantz Date: Mon, 21 Oct 2024 12:21:07 +0200 Subject: [PATCH 2/5] ProxyAccessorUndoItem: parentPulledObject does not change anymore the global selection. --- lib/mayaUsd/fileio/utils/proxyAccessorUtil.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/mayaUsd/fileio/utils/proxyAccessorUtil.cpp b/lib/mayaUsd/fileio/utils/proxyAccessorUtil.cpp index 08b4cf558f..d9fcb3c5e1 100644 --- a/lib/mayaUsd/fileio/utils/proxyAccessorUtil.cpp +++ b/lib/mayaUsd/fileio/utils/proxyAccessorUtil.cpp @@ -37,20 +37,13 @@ MStatus ProxyAccessorUndoItem::parentPulledObject( const auto ufeChildPath = MayaUsd::ufe::dagPathToUfe(pulledDagPath).pop(); // Quick workaround to reuse some POC code - to rewrite later - - // Communication to current proxyAccessor code is through the global selection. - // This is not logically necessary, and should be re-written to avoid going through - // the global selection. static const MString kPyTrueLiteral("True"); static const MString kPyFalseLiteral("False"); MString pyCommand; pyCommand.format( "from mayaUsd.lib import proxyAccessor as pa\n" - "import maya.cmds as cmds\n" - "cmds.select('^1s', '^2s')\n" - "pa.parent(force=^3s)\n" - "cmds.select(clear=True)\n", + "pa.parent('^1s', '^2s', force=^3s)\n", Ufe::PathString::string(ufeChildPath).c_str(), Ufe::PathString::string(ufeParentPath).c_str(), force ? kPyTrueLiteral : kPyFalseLiteral); From 776e65d97277f7c096029c02e14e202431b81751 Mon Sep 17 00:00:00 2001 From: Julien Frantz Date: Mon, 28 Oct 2024 18:14:36 +0100 Subject: [PATCH 3/5] OrphanedNodesManager: Fix crash when renaming a prim with AE open. This crash occurs when the Attribute Editor is visible and displaying a USD prim that is being renamed, while we are updating proxyAccessor connections for its descendant pulled objects. --- lib/mayaUsd/fileio/orphanedNodesManager.cpp | 24 +++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/mayaUsd/fileio/orphanedNodesManager.cpp b/lib/mayaUsd/fileio/orphanedNodesManager.cpp index af27d63c2d..3f9e524f19 100644 --- a/lib/mayaUsd/fileio/orphanedNodesManager.cpp +++ b/lib/mayaUsd/fileio/orphanedNodesManager.cpp @@ -29,11 +29,17 @@ #include #include +#include #include #include #include #include +// Workaround to avoid a crash that occurs when the Attribute Editor is visible +// and displaying a USD prim that is being renamed, while we are updating proxyAccessor +// connections for its descendant pulled objects. +#define MAYA_USD_AE_CRASH_ON_RENAME_WORKAROUND + // For Tf diagnostics macros. PXR_NAMESPACE_USING_DIRECTIVE @@ -163,8 +169,22 @@ void renamePulledObject( for (const PullVariantInfo& info : trieNode->data()) { const MDagPath& mayaPath = info.editedAsMayaRoot; TF_VERIFY(writePullInformation(pulledPath, mayaPath)); - if (usdPathChanged) { - TF_VERIFY(reparentPulledObject(mayaPath, pulledPath.pop())); + if (usdPathChanged && mayaPath.isValid()) { +#ifdef MAYA_USD_AE_CRASH_ON_RENAME_WORKAROUND + // Update the proxyAccessor connections on idle to avoid a crash when + // attribute editor is visible and showing the ancestor USD prim beeing renamed. + if (MGlobal::mayaState() == MGlobal::kInteractive) { + using ReparentArgs = std::pair; + MGlobal::executeTaskOnIdle( + [](void* data) { + const auto* args = static_cast(data); + TF_VERIFY(reparentPulledObject(args->first, args->second)); + delete args; + }, + new ReparentArgs(mayaPath, pulledPath.pop())); + } else +#endif + TF_VERIFY(reparentPulledObject(mayaPath, pulledPath.pop())); } } } From 5cef4856d3db071dd61c2e6f00842b54406f1a34 Mon Sep 17 00:00:00 2001 From: Sean Donnelly <23455376+seando-adsk@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:08:49 -0500 Subject: [PATCH 4/5] simple clang-format fix --- lib/mayaUsd/fileio/orphanedNodesManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mayaUsd/fileio/orphanedNodesManager.cpp b/lib/mayaUsd/fileio/orphanedNodesManager.cpp index 3f9e524f19..ec7c8ab998 100644 --- a/lib/mayaUsd/fileio/orphanedNodesManager.cpp +++ b/lib/mayaUsd/fileio/orphanedNodesManager.cpp @@ -36,7 +36,7 @@ #include // Workaround to avoid a crash that occurs when the Attribute Editor is visible -// and displaying a USD prim that is being renamed, while we are updating proxyAccessor +// and displaying a USD prim that is being renamed, while we are updating proxyAccessor // connections for its descendant pulled objects. #define MAYA_USD_AE_CRASH_ON_RENAME_WORKAROUND From a5a1178e797c7f2ae7c1db006002374e5dfe5668 Mon Sep 17 00:00:00 2001 From: Julien Frantz Date: Wed, 20 Nov 2024 19:35:13 +0100 Subject: [PATCH 5/5] mayaUsd.lib.proxyAccessor: fix Python 2 syntax compatibility --- lib/mayaUsd/nodes/proxyAccessor.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/mayaUsd/nodes/proxyAccessor.py b/lib/mayaUsd/nodes/proxyAccessor.py index 37e7dc9fd2..680a7c1355 100644 --- a/lib/mayaUsd/nodes/proxyAccessor.py +++ b/lib/mayaUsd/nodes/proxyAccessor.py @@ -325,7 +325,7 @@ def parentItems(ufeChildren, ufeParent, connect=True): # Cannot use 'visibility' here because it's already used by orphan manager connectParentChildAttr(parentVisibilityAttr, childDagPath, 'lodVisibility', connect) -def __parent(*ufeItemPathStrings, doParenting=True, forceUnparenting=False): +def __parent(doParenting, forceUnparenting, *ufeItemPathStrings): if ufeItemPathStrings: ufeSelectionList = [_createUfeSceneItem(pStr) for pStr in ufeItemPathStrings] else: @@ -347,11 +347,13 @@ def __parent(*ufeItemPathStrings, doParenting=True, forceUnparenting=False): parentItems(ufeChildren, ufeParent, doParenting) -def parent(*ufeItemPathStrings, force=False): - __parent(*ufeItemPathStrings, doParenting=True, forceUnparenting=force) +def parent(*ufeItemPathStrings, **kwargs): + # Use **kwargs instead of keyword-only arguments after varargs for python2 compat. + forceUnparenting = kwargs.get('force', False) + __parent(True, forceUnparenting, *ufeItemPathStrings) def unparent(*ufeItemPathStrings): - __parent(*ufeItemPathStrings, doParenting=False) + __parent(False, False, *ufeItemPathStrings) def connectItems(ufeObjectSrc, ufeObjectDst, attrToConnect): connectMayaToUsd = isUfeUsdPath(ufeObjectDst)