Extension Attribute of MPxData


#1

I’m writing a C++ plugin using the Maya API.
I have a custom data-type, that I want to expose to all Dag nodes as an extension-attribute.

I’ve searched the documentation, the DevKit examples, in forums and just by google search. I couldn’t find any example of how to do that (I’m starting to think that what I’m trying to do is not possible or not supported by Maya).

There are examples on how to add dynamic-attributes, but that is not what I’m afte.
I’ve been able to expose it as a dynamic-attribute, but I then need to add it to every node that is being queried/edited, if it doesn’t exist, and this gets complicated when supporting undo (even using MDGModifier).

Accodring to the Maya documentations, there should be 3 ways to add extension-attributes:

  1. Using ‘addExtensios’ MEL command
  2. Using MNodeClass::addExtensionAttribute(<attr>)
  3. Using MDGModifier::addExtensionAttribute(<node-class>,<attr>)

I put the code that adds the extension-attribute in the plugin’s -initialization function, and a corresponding code for deleting it in the plugin’s uninitialize function.

I am able to use the MEL option with:
MGlobal::executeCommand(“addExtension -nt dagNode -sn S -ln L -dt T;”);
(where: ‘S’ and ‘L’ are the attr-name, and ‘T’ is my datat-type’s name)
The attribute even shows-up in the attribute-editor of all dag-nodes inthe ‘Extended’ section.
But then when I try to get the value of it later, it fails.

The code I’m using to get the data is taken from the blindComlexData example.
Within a MItSelectionList itereator, I do (satus-handling code excluded for clarity):

MObject node;
iter.getDependNode(node);

MFnDependencyNode fnNode;
fnNode.setObject(node);

plug = fnNode.findPlug(S, false);

MObject sData;
plug.getValue(sData);
MFnPluginData fnData(sData);

data = (MyMPx*)fnData.constData();

(Where: ‘S’ is the short-name of the attribute, and MyMPx is my custom-data class)

The last-line fails, when it tries to case the data back to my custom-class.

When using the other two options, I can’t even initialize the plugin if I use status-checking code - and there are absolutly no examples about how to do that anywhere (not that I could find, and I think I can search pretty well).

I’ve tried everythin I can think of, and then some guess-work… (a LOT actually…)

I first have to define/create an attribute, of-course, before I pass it along to any of the functions that would add it as an extension attribute.

I actually found out that it doesn’t matter what kind of attribute I created, using MFnTypedAttribute - even creating a built-in attribute-type, causes the same kind of failure:

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MFnStringData::kString);

BTW, if I add this right after: MFnData::Type t = fnAttr.attrType();
Then ‘t’ is ‘kInvalid’, which I find odd - can’t I even create a normal typed-attribute properly?

If I do this, though, then ‘t’ is ‘kString’:

MFnTypedAttribute fnAttr;
MString defaultString("");
MFnStringData defaultTextData;
MObject defaultTextAttr = defaultTextData.create(defaultString);
MObject attr = fnAttr.create(L, S, MFnStringData::kString, defaultTextAttr, &status);
MFnData::Type t = fnAttr.attrType();

Using MNodeClass, I’ve tried doing:

MTypeId mDagNodeTypeID(MFn::kDagNode);
const MNodeClass mnDagNodeClass(mDagNodeTypeID);
status = mnDagNodeClass.addExtensionAttribute(attr);
CHECK_MSTATUS_AND_RETURN_IT(status);

The status-check fails and returns immediately.

Using MDGModifier, I’ve tried doing:

MTypeId mDagNodeTypeID(MFn::kDagNode);
const MNodeClass mnDagNodeClass(mDagNodeTypeID);
MDGModifier mDgMod;
status = mDgMod.addExtensionAttribute(mnDagNodeClass, attr);
CHECK_MSTATUS_AND_RETURN_IT(status);

The status-check fails and returns immediately.

So it can’t even be the way I try to create my custom-typed attribute.
But just for completion-sake, here is what I’ve tried:

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MyMPx::id);
MFnData::Type t = fnAttr.attrType();

Doesn’t work…
‘t’ is ‘kInvalid’, and trying to add the attribute later as an extension-attribute (using either MNodeType or MDGModifier), fails the next status-check.

I then though, maybe it needs a default-value, so I first try:

MObject attr = fnAttr.create(L, S, MyMPx::id, MObject::kNullObj, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);
MFnData::Type t = fnAttr.attrType();

Status-check passes, but ‘t’ is still ‘kInavalid’, and again, can’t add it as an extension-attribute later.

Lastly then tried:

MFnPluginData fnData;
MObject defaultData = fnData.create(MyMPx::id);
MTypeId tPluginData(MFnData::kPlugin);
MObject attr = fnAttr.create(L, S, tPluginData, defaultData, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);
MFnData::Type t = fnAttr.attrType();

At this point, I am out of creative ideas…

Any help would be appreciated! :slight_smile:


#2

Ok, I figured it out:

I don’t know what about the MEL approach (I didn’t like it anyway).
But as for the 2 other approaches, the problem was the way I instantiated MNodeClass.
I thought I was giving it a NoteTypeID, but I was actually trying to instantiate is with an MFnTypeID which doesn’t work…
I found that out by trying to get it’s TypeName afer instanciating it, and the AttributeCound, and I got invalid results…
Until I tried to just pass it a NoteTypeName, like “transform” (all lower-case), and suddenly it started working.
Eventually, I used “dagNode” (with this exact casing), so I could add the extension-attribute to all DAG-nodes.
It also works with my custom MPxData-type, just as well as with the StringData.
I didn’t end-up having to wrap it in MFnPluginData for this to work - I just pass MyMPx::id to the attribute-creation function, and it works.
So, this is how it looks when it works:

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MyMPx::id); // or: MObject attr = fnAttr.create(L, S, MyMPx::id, MObject::kNullObj, &status);
MNodeClass mnDagNodeClass(“dagNode”);
status = mnDagNodeClass.addExtensionAttribute(attr);

Realistically, I actually did have to use MFnPluginData in order to pre-generate a default-value for my attribute:

MFnPluginData fnData;
MObject defaultValue = fnData.create(MyMPx::id, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MyMPx::id, defaultValue, &status);
MNodeClass mnDagNodeClass(“dagNode”);
status = mnDagNodeClass.addExtensionAttribute(attr);

I haven’t tried to use the MDGModifier approach, but I would guess it would work out just as well, with a proper MNodeClass instance…

I wish there was an easier way to find-out, when trying to instantiate MNodeClass, when it doesn’t actually work…
I also wish there was a list somewhere of node-names and type-ids…

Anyway, anyone reading this, who wants to write a plugin with this use-case, now you know how.


#3

Thanks for letting us know.