Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAYA-105175: Rewrote the rename restriction algorithm from scratch to cover more edge cases. #786

Merged
merged 11 commits into from
Sep 24, 2020

Conversation

HamedSabri-adsk
Copy link
Contributor

This PR makes a major improvement in the way "Rename" restriction behaves in Maya.

@HamedSabri-adsk HamedSabri-adsk added ufe-usd Related to UFE-USD plugin in Maya-Usd workflows Related to in-context workflows labels Sep 21, 2020
//! Returns the layer in composition arc where HasSpecs is set to true
MAYA_USD_UTILS_PUBLIC
std::vector<SdfLayerHandle> layerInCompositionArcsWithSpec(const UsdPrim& prim);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up the usd utility functions. We no longer use them.

UsdPrimCompositionQuery is a nice utility but doesn't deal with SubLayer comp arcs. For the sake of this task, I stopped using it altogether.

commandName.c_str(),
prim.GetName().GetString().c_str(),
layerDisplayName.c_str());
throw std::runtime_error(err.c_str());
}
}
Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk Sep 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This algorithm heavily relies on using "Prim's PrimStack" rather than "Stage's LayerStack" which makes it much easier to interrogate about the SdfPrimSpec(s) in different composition arcs.

Comment on lines 147 to 163
if(spec->GetSpecifier() == SdfSpecifierOver && spec->HasReferences()) {
break;
}

// if the over exist in the session layer
if (spec->GetSpecifier() == SdfSpecifierOver) {
auto sessionLayer = prim.GetStage()->GetSessionLayer();
if (sessionLayer == spec->GetLayer()){
layerDisplayName.append("[" + spec->GetLayer()->GetDisplayName() + "]" + ",");
}
}

// if the def primspec is in another layer other than current stage's local layer.
if (spec->GetSpecifier() == SdfSpecifierDef && primSpec->GetLayer() != spec->GetLayer()) {
layerDisplayName.append("[" + spec->GetLayer()->GetDisplayName() + "]" + ",");
break;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle different cases around "over" specifier.

if(!parentPrim.IsPseudoRoot()){
ufe::applyCommandRestriction(childPrim, "reparent");
ufe::applyCommandRestriction(parentPrim, "reparent");
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unconditionally applying the restriction rules here but realized that If parent prim is the pseudo-root, no def primSpec will be found and instead USD returns the "over".

This case happens when one tries to parent a prim under proxy shape ('/').

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So does that mean there are no restrictions for children of the pseudo-root? That would be surprising! If I have a child of the pseudo-root with opinions on a stronger layer, I shouldn't be able to rename it, no?

}
else

if(!layerDisplayName.empty())
Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk Sep 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified the logic by removing the redundant primSpec check and loop in primStack.

if (sessionLayer == spec->GetLayer()){
layerDisplayName.append("[" + spec->GetLayer()->GetDisplayName() + "]" + ",");
}
layerDisplayName.append("[" + spec->GetLayer()->GetDisplayName() + "]" + ",");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove redundant check to distinguish if the "over" specifier is in the session layer.

Hamed Sabri added 4 commits September 21, 2020 18:54
- remove unnecessary primSpec->GetLayer() == spec->GetLayer() check
- comment clean up
if(!parentPrim.IsPseudoRoot()){
ufe::applyCommandRestriction(childPrim, "reparent");
ufe::applyCommandRestriction(parentPrim, "reparent");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So does that mean there are no restrictions for children of the pseudo-root? That would be surprising! If I have a child of the pseudo-root with opinions on a stronger layer, I shouldn't be able to rename it, no?

prim.GetName().GetString().c_str(),
layerDisplayNames.c_str());
throw std::runtime_error(err.c_str());
// if exists a def sepc
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: 'sepc'.

}
}

if(!layerDisplayName.empty()) {
layerDisplayName.pop_back();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the pop_back()?

Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the pop_back is just for make up purposes in the error message. It just removes the last "," in the case where there are multiple layers:

[bob],[foo],

I pop back the last "," so it looks

[bob],[foo]

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you've explained this to me once before... A shortened version of your explanation would make a great code comment.

}
else {
// if exist a primSpec with reference
if(spec->HasReferences()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should comment on why we abort the loop here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason for the skipping the reference is to not clash with the over that may be created in the stage's local sessioLayer or other layers.

Consider the case, where we have a stage that has opened a USD file called RefExample.usda and in that file we have
a prim with over which has an external reference to another Usd file called HelloWorld.usda.

RefExample.usda

over "refSphere2" (
    prepend references = @./HelloWorld.usda@
)

HelloWorld.usda

#usda 1.0
(
    defaultPrim = "hello"
)

def Xform "hello"
{
	...........
}

All PrimStack knows at this point is that "refSphere2" has two specs in 2 different places in order from strong to weak:

RefExample.usda  --->  over
HelloWorld.usda  --->  def

Now in line 161, I unconditionally check if there is an override and then record it's layer name which then results in error message to be displayed which is not desirable:

// if exists an over sepc
if (spec->GetSpecifier() == SdfSpecifierOver) {
    layerDisplayName.append("[" + layerName + "]" + ",");
}

one should be able to rename "refSphere2" since it is created in "RefExample.usda" and itself doesn't have any other "over" in the stage's local layers.

This is why I previously had a condition to check if the "over" was created in sessioLayer or not.

Hope this makes sense.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. Can you distill this into a code comment somehow? I know it's a bit challenging, you don't want to have a 2-page code comment, but it would still be nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh yes of course! I was planning to do it after the planning meeting.

test/lib/ufe/testRename.py Show resolved Hide resolved
commandName.c_str(),
prim.GetName().GetString().c_str(),
prim.GetName().GetString().c_str(),
message.c_str(),
layerDisplayName.c_str());
throw std::runtime_error(err.c_str());
}
Copy link
Contributor Author

@HamedSabri-adsk HamedSabri-adsk Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppt-adsk

  • polished the algorithm slightly to make it easier to reason about the code and added appropriate comments.
  • added proper messaging. we now only need to deal with two messages ( no more fancy words ) :
  1. Cannot rename something because It is defined on another layer
  2. Cannot rename something because It has a stronger opinion on another layer

please see 2472eec .

Also ignore my typo in the commit message: I meant "polished" not "published". Sigh..............

_parentLayer = parentPrim.IsPseudoRoot()
? parent->prim().GetStage()->GetEditTarget().GetLayer()
: MayaUsdUtils::defPrimSpecLayer(parentPrim);
_childLayer = childPrim.GetStage()->GetEditTarget().GetLayer();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppt-adsk clean up the legacy old code for getting the appropriate layer for _parentLayer .

ufe::applyCommandRestriction in line 71 and 72 will always put us in a position to use appropriate layer to use for performing the parent operation.

if (prim.IsPseudoRoot()){
return;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppt-adsk per out offline discussion, PseudoRoot() is a special case and should be treated differently.

After some thinking, it makes more sense to simply return early if we are dealing with the root layer.

@HamedSabri-adsk HamedSabri-adsk added the ready-for-merge Development process is finished, PR is ready for merge label Sep 23, 2020
@@ -25,6 +25,8 @@

#include <mayaUsdUtils/util.h>

#include <iostream>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just noticed I left out to clean up this iostream. Will have it remove in another PR.

@kxl-adsk kxl-adsk merged commit 91d0bfe into dev Sep 24, 2020
@kxl-adsk kxl-adsk deleted the sabri/MAYA-105175/rewrite_rename_restriction branch September 24, 2020 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-for-merge Development process is finished, PR is ready for merge ufe-usd Related to UFE-USD plugin in Maya-Usd workflows Related to in-context workflows
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants