Maya API + inherited nodes + connectionMade = boom

My current node tree:


MpXTransform (MT)
          |------- MyNodeBase  (NB)
                               |------- Subclassed Again  (SA)

I am having issues performing any “normal” operations on a node via the virtual overrides.

The (NB) node defines a bunch of attributes. I want to manage it’s layer within it’s class (who wouldn’t!)

So say I have a name attribute in the NB node. The SA node gets the name attribute via the inheritance and all is well. I can see it in Maya, I can manipulate it via connections, set, get, etc…

Now, when I connect it, I have the virtual “connectionMade” overridden in the base (NB) class.

SA has no connectionMade virtual – so! it rightly flows up from SA–>NB and does indeed use the virtual defined there.

Now the problem:


MStatus NB::connectionBroken( const MPlug& plug, const MPlug& otherPlug, bool asSrc )
{
	MObject thisNode = this->thisMObject();
	MPlug controlPlug( thisNode, control );

	if (plug == control)
	{
		MSG_INFO( "Disconnection made from Control input" );
	}
        return MS::kUnknownParameter;
}

Does not seem to work when in fact I connect the control plug of any node inherited from the NB node.

I threw some prints in there to make sure it is calling the virtual, and it does, however the plug address is no where close to the defined address of the static MObject control attribute defined in the base class.

I am thinking that the bottom class (SA) “attributes” defined in the upper class (NB) are somehow not referring to the baseClass attributes.

If anyone has experience trying the same thing (with inheritance and discovering the attributes, etc…) or can see that I am just doing something completely broken =) help is very appreciated.

Cheers.

Jeez, didnt mean to scare everyone away! =)

I still do not have a good solution … I could make my own “attrbute changed” event catchall, but that is plain ugly.

And what’s the point if one is provided. Although, … :frowning:

Maybe what I am doing is a bad idear? Though there are Maya nodes with 5+ sub-classes.

Are you 100% sure that your MObject is referring to the correct node?
Have you tried printing the name of the plug that you are getting?
Where’s some more code, from your SA class, showing how you’re calling NB::connectionBroken?

[QUOTE=dbsmith;10467]Are you 100% sure that your MObject is referring to the correct node?
Have you tried printing the name of the plug that you are getting?
Where’s some more code, from your SA class, showing how you’re calling NB::connectionBroken?[/QUOTE]

I dont directly call it, that ia a call thrown by Maya itself when connections are broken.

I did print out the MObjects I am mucking with, they are the actual objects.

Here is a kicker: If I do something like try to match the first few letters of the attribute name (the incomming plug name) against one I am looking for, like attribute = “pushPosition” it will match.

It simply does not work using the mechanism the API tell sme to use i.e. comparing the static defined PLUG to the incomming PLUG. And rightly so, cause if I dump their addresses they are not referring to the same address space.

This is why I am confused.

I’d love to post the actual code =( Viacom might slap my face.

I will try to boil down some code to post.

Cheers for the suggestion.

I threw some prints in there to make sure it is calling the virtual, and it does, however the plug address is no where close to the defined address of the static MObject control attribute defined in the base class.

The equality operator you’re using is overloaded to either compare two plugs or a plug and an attribute. You’re using the second here, which is completely valid. The plug is an MPlug, not an MObject like your attribute, so their addresses couldn’t possibly be the same; they’re referring to completely different data structures that need their own space in memory. The MPlug does carry a pointer to an attribute, though. You can use MPlug::attribute() to get at the attribute. It returns an MObject by what looks like value, though, so even comparing addresses between your control attribute and the return value of plug.attribute() may not tell you whether your code is working.

What may be more revealing is to compare the address of static attribute “control” between your two classes, NB and SA, by instantiating each of them. That way you can make sure the plugin registration process isn’t somehow creating two separate static attributes. (You’d expect there’d be a link error in that case, though, if they’re named the same…)

Post up your initialize methods, I’d like to see how you’re creating the attribute.



MObject nanWorld::control;

MStatus nanWorld::initialize()
{
	NAS_CHECK_RETURN_ERR( nanNode::initialize(), "nanWorld::init" );

	MStatus status;
	MFnGenericAttribute		gAttr;

	// The control / transform
	{
		control = gAttr.create( "control", "ctrl", &status);
		NAS_CHECK_RETURN_ERR( status, "nanWorld::init.gAttr.create:control");

		NAS_CHECK_RETURN_ERR( gAttr.addAccept(MFnData::kMesh), "nanWorld::init.gAttr.create:control");
		NAS_CHECK_RETURN_ERR( gAttr.addAccept(MFnData::kNurbsCurve), "nanWorld::init.gAttr.create:control");
		NAS_CHECK_RETURN_ERR( gAttr.addAccept(MFnData::kNurbsSurface), "nanWorld::init.gAttr.create:control");
		NAS_CHECK_RETURN_ERR( gAttr.addAccept(MFnData::kSubdSurface), "nanWorld::init.gAttr.create:control");
	}
	NAS_CHECK_RETURN_ERR( addAttribute( control ), "nanWorld::init.control.add" );


MStatus nanWorld::connectionBroken( const MPlug& plug, const MPlug& otherPlug, bool asSrc )
{
	if (plug.attribute() == control)
	{
		MObject otherNode = otherPlug.node();
		MSG_INFO( "Disconnection made from Nick World Control input" );
		return MS::kSuccess;
	}
	return MS::kUnknownParameter;
}

NAS_CHECK_RETURN_ERR is the standard macro cruft to check MStatus results.

nanNode::initialize() is obviously calling the superclass nanNode who is a sub-class of MPxTransform.

SOOO, if that is the case, what is teh best way to “nicely” resolve equality of an incomming MPlug to verify which “attr” she be using?

As you can see I did try the .attrbute() as well, but obviously, as you mentioned, there is no equality becuase one is an instanced form of the static with it’s own memory space.

I’d hate to compare it by name o.0 a) strings are ugly! b) two+ nodes could easily use the same name for different attributes.

Thanks for the help! I was starting to think I had an asphasic moment and no one knew wtf I was on about.

Cheers.

I wrote a whole paragraph then had an OHHHHH WAIT moment as I re-read your code.

MObject nanWorld::control;

nanWorld is your subclass? This is important. You have a static member variable in your superclass. When you declared it in your cpp file, you should have declared

static MObject nanNode::control;

You then overrode it in the subclass with a non-static member. This is not the same variable at all. Now you have two. And nanWorld will prefer the one that is closest to it in scope, the one you declared in its own namespace.

So, first thing:

[ul]
Pull the MObject nanWorld::control declaration. Not only is it wrong because it’s non-static, it’s unnecessary. You’re inheriting the static member from nanNode.[/ul]

Second thing (this is the track I was on first):

[ul]
Don’t create the attr more than once. You’re actually creating it three times. Initialize is not like a constructor. It is meant to get called only once, on plugin load, for each class. You’re assigning values to control when you initialize nanNode, then again when you call nanNode’s initialize a second time in nanWorld’s initialize, and again in the body of nanWorld’s initialize.[/ul]

Third thing:

[ul]
Use inheritAttributesFrom instead of addAttribute in the subclass. I’m not sure what it does if you recycle. It might work, but I suspect the registration process will gag on it. Currently it doesn’t error because you aren’t recycling, you’re using a spankin’ new attr (see first point.)[/ul]

I hope that helps. Let us know!

[QUOTE=Bronwen;10499]I wrote a whole paragraph then had an OHHHHH WAIT moment as I re-read your code.

nanWorld is your subclass? This is important. You have a static member variable in your superclass. When you declared it in your cpp file, you should have declared

static MObject nanNode::control;

You then overrode it in the subclass with a non-static member. This is not the same variable at all. Now you have two. And nanWorld will prefer the one that is closest to it in scope, the one you declared in its own namespace.
[/QUOTE]

o no!

Actually, yeah, almost =)

I am actually declaring that particular variable in the correct sub-class.

nanNode has his own, and does not declare any of the statics from this sub-class.

Just a gross overview:

nanNode has a tagging system with attrs
nanWorld(s) contain control and geoManager attrs
then there are child (the nanNode and nanWorld are technically abstract and should never be directly instanced).

So, we have something like nanChar <-- nanWorld <-- nanNode <-- MPxTransform (yes I know, Maya Asset-ish).

So each sub-class has his/her own attrs, only declared inside the initialize of that class.

Now, the first problem I had many weeks ago (posted on here someplace) was that I had failed to initialize the base class initializers in the sub-classes.

I thought that was fixed by calling the ancestor initializers from the child, but maybe that is a bad thing.

So, technically, I can’t use inheritAttributesFrom since the ancestor is not creating the statics in each of the leaf children classes, unless I should be using that to “down” cast the attributes instead of calling the initializers (which is prolly what you meant to convey to me and I am merely thick ATM).

I just lost my c++ programmer street cred. Thank you so much.

BTW, your presentation @ GDC this year was awesome too! not that I am sure I did not say it a few times in person =)

I will go hammer it out another attempt and shower much praise.

Cheers!

Well, I can not get inheritAttributesFrom to work.

If I replace the initialize callbacks to the usper class with inherits:

NAS_CHECK( inheritAttributesFrom(“nanWorld”), “wth”);

On a startup all I get are immediate crashes with complaints about pure virtual function calls. That is typical of a sub-class calling a base class function that has yet to be overridden.

Which makes no sense because the documentation clear states that the use case for inheritsAttributesFrom is to only be utilized from the initialize function of the sub-class. o.0

Just for reference, http://tech-artists.org/forum/showthread.php?p=10505#post10505 , is the original problem, which seems like it has not gone away per se, but was masked by the initializers being used in the sub-classes.

Same question I have over there: What is the best practice to do node heirarchies in the Maya API ? Has anyone done one ? ever? Seems AD is kinda anathema to the idea. :frowning:

In your superclass, you’re defining control. In your subclass, you’re re-defining it, not overriding it. Then you’re expecting the superclass to treat “control” as though it’s polymorphic. It isn’t. The only way to get your superclass to recognize the attribute “control” in the superclass as the same “control” in the subclass if for them to be the exact same. That means only defining “control” in your superclass, then having the subclass inherit it and not touch it at all.

I’ve not used inheritAttributesFrom, but I have seen it used in other examples, so it must work. Without debugging the code I’m not sure what state you were in when it failed, and not having used inheritAttributesFrom, I’m not even sure I’d recognize a problem from just a code snippet. I’m pretty sure inheritAttributesFrom is your only option, though, unless you want to have a bunch of duplicated code.

There’s a number of examples of its use in the cortex-vfx maya source code, like this one. In that case, class ProceduralHolder inherits ParameterisedHolderComponentShape, which is created using class template ParameterisedHolder. So just look at how ParameterisedHolder’s initialize, and ProceduralHolder’s initialize, and you’ll see that there is no duplication of attrs and no redundant initialize of the superclass. (I should have posted that last bit about the redundant initialize in your other thread.)

[QUOTE=Bronwen;10573]In your superclass, you’re defining control. In your subclass, you’re re-defining it, not overriding it. Then you’re expecting the superclass to treat “control” as though it’s polymorphic. It isn’t. The only way to get your superclass to recognize the attribute “control” in the superclass as the same “control” in the subclass if for them to be the exact same. That means only defining “control” in your superclass, then having the subclass inherit it and not touch it at all.[/QUOTE]

That is awesome material to look at, thanks!

You suggestions also have worked (kind of); now the problem is that 2012 is a baby.

If I compile down to 2008 or 2009, works 100%, exactly as it should, with inheritAttributes, etc…

2012 halts after trying to load all the nodes and tosses a pure virtual function call error and completely blows out of Maya (access violation(s) seem to be happening in the shared.dll).

I have an email into the Autodesk guys, but if anyone else has had problems compiling down to 2012 and have seen the same issue, any information on that would be great.

Otherwise, you have resolved the actual problem I had, and for that I owe some drinks!

Cheers!