Trigger a callback after referencing a file?

Trigger a callback after referencing a file?

mikey.n
Enthusiast Enthusiast
3,766 Views
4 Replies
Message 1 of 5

Trigger a callback after referencing a file?

mikey.n
Enthusiast
Enthusiast

I want to run a certain callback after anytime a new file gets referenced. I want to do this in python.

According to the docs this should be possible: https://help.autodesk.com/view/MAYAUL/2018/ENU/?guid=__py_ref_class_open_maya_1_1_m_scene_message_ht...

 

But when I register callbacks for kAfterLoadReference or kAfterLoadReferenceAndRecordEdits, the function never gets triggered. I connected a debugger and set a breakpoint and the callback function never even gets entered.

kAfterImport works as expected. Am I missing something obvious here, or is something actually broken?

Example code below, it creates a simple scene with a cube in it, registers multiple test callbacks, then references in the cube, then imports the cube.

 

I'm in maya 2018.2

 

#create a new file called cube.ma, has a cube in it
TEST_SCENE_NAME = 'cube.ma'

cmds.file(new=1, f=1)
cmds.polyCube()
cmds.file(rn=TEST_SCENE_NAME)
cmds.file(s=1, f=1, type='mayaAscii')
cmds.file(new=1, f=1)

#register callbacks
import maya.api.OpenMaya as om2

def onReferenceLoad(clientData=None):
    print '#'*20
    print 'This is a callback'
    print '#'*20

id1 = om2.MSceneMessage.addReferenceCallback(om2.MSceneMessage.kAfterLoadReferenceAndRecordEdits, onReferenceLoad)
id2 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterLoadReferenceAndRecordEdits, onReferenceLoad)

id3 = om2.MSceneMessage.addReferenceCallback(om2.MSceneMessage.kAfterLoadReference, onReferenceLoad)
id4 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterLoadReference, onReferenceLoad)

id5 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterImportReference, onReferenceLoad)
id6 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterImport, onReferenceLoad)

#would expect this to trigger the callback method 5 times, doesn't trigger at all
print 'Referencing the test file'
cmds.file(TEST_SCENE_NAME, r=1, type='mayaAscii')

#correctly triggers the one callback registered
print 'Importing the test file'
cmds.file(TEST_SCENE_NAME, i=1)

#unregister callbacks
om2.MSceneMessage.removeCallbacks([id1,id2,id3,id4,id5,id6])

 

0 Likes
Accepted solutions (1)
3,767 Views
4 Replies
Replies (4)
Message 2 of 5

mikey.n
Enthusiast
Enthusiast

Just tested in Maya 2019.0, same problem. Will download and test in 2020.

EDIT: Behaviour is the same in Maya 2020. Am I making a mistake here?

0 Likes
Message 3 of 5

sergio-leon
Autodesk Support
Autodesk Support
Accepted solution

Hello Michael. 

 

I have been taking a look today at the behaviour. When creating a reference it only triggers the kAfterCreateReference scene message, even when the process internally - by default also loads the created reference. kAfterLoadReference will occur when a reference (that is already created)  is loaded. Below I created  sample code similar to the one you did, to illustrate it. Note that in one case a reference is created, and later a reference is also created but without the implicit loading of the file content.

 

In cases with nested references on files, right now we obtain one kAfterCreateReference message (for the Top level reference) and one kAfterLoadReference for every nested reference that is being loaded. The flag 'loadReferenceDepth' in the cmds.file command, will set the behavior when loading nested references. By default is set to 'all'.

 

I can think right now about three workarounds, that may apply depending on your purpose:

  • Workaround 1: it is to add a callback to kAfterLoadReference and also to kAfterCreateReference. But in this last case, check if possible, if the reference created have been also loaded.
  • Workaround 2: create a callback on kAfterFileRead. We will get it every time an external file is read, that is, when the reference is created and also when one reference is loaded.
  • Workaround 3: if you are not convinced about callbacks, you can take a look to scriptJobs. There is an event: readingFile that may be interesting to research.

Let me know please if the comments above helps.

 

Sample code:

 

 

from maya import cmds
TEST_SCENE_NAME = 'cube.ma'
 
cmds.file(new=1, f=1)
cmds.polyCube()
cmds.file(rn=TEST_SCENE_NAME)
cmds.file(s=1, f=1, type='mayaAscii')
cmds.file(new=1, f=1)
 
import maya.api.OpenMaya as om2
 
def printMessage(message):
    print message  
 
id1 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterCreateReference, printMessage, "Callback for kAfterCreateReference.")
id2 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterCreateReferenceAndRecordEdits, printMessage, "Callback for kAfterCreateReferenceAndRecordEdits.")
id3 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterLoadReference, printMessage, "Callback for kAfterLoadReference.")
id4 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterLoadReferenceAndRecordEdits, printMessage, "Callback for kAfterLoadReferenceAndRecordEdits.")
id5 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterImportReference, printMessage, "Callback for kAfterImportReference.")
id6 = om2.MSceneMessage.addCallback(om2.MSceneMessage.kAfterImport, printMessage, "Callback kAfterImport.")
 
#Workflow to trigger callbacks
print 'Creating a reference...'
cmds.file(TEST_SCENE_NAME, reference=1, type='mayaAscii')
reference_node = cmds.file( TEST_SCENE_NAME, query=True, referenceNode=True )
print 'Unload the reference...'
cmds.file(unloadReference=reference_node)
print 'Load the reference...'
cmds.file(loadReference=reference_node)
print 'Remove the reference...'
cmds.file(TEST_SCENE_NAME, removeReference=True )
print 'Referencing the test file without loading it...'
cmds.file(TEST_SCENE_NAME, reference=1, loadReferenceDepth='none', type='mayaAscii')
reference_node = cmds.file( TEST_SCENE_NAME, query=True, referenceNode=True )
print 'Load the reference...'
cmds.file(loadReference=reference_node)
print 'Importing the test file...'
cmds.file(TEST_SCENE_NAME, i=True)
 
#unregister callbacks

om2.MSceneMessage.removeCallbacks([id1,id2,id3,id4,id5,id6])

 

 

 

The output from it is:

Creating a reference...
Callback for kAfterCreateReference.
Callback for kAfterCreateReferenceAndRecordEdits.
Unload the reference...
Load the reference...
Callback for kAfterLoadReference.
Callback for kAfterLoadReferenceAndRecordEdits.
Remove the reference...
Referencing the test file without loading it...
Callback for kAfterCreateReference.
Callback for kAfterCreateReferenceAndRecordEdits.
Load the reference...
Callback for kAfterLoadReference.
Callback for kAfterLoadReferenceAndRecordEdits.
Importing the test file...
Callback kAfterImport.


 


Sergio Leon
Developer Technical Services
Autodesk Developer Network



Message 4 of 5

mikey.n
Enthusiast
Enthusiast

As you say, kCreateReference seems to be behave as we need. We will likely need to register the same callback twice for the nested refs, but with a bit of caching perf overhead should be minimal.
I tested and the data from the referenced file seems to have been loaded by the time the callback function is triggered.(A print cmds.ls(type='transform') check). I will need to test it again in a real use case but I'm hopeful.

 

Workaround 2 is also worth testing, but workaround 3 won't cut it in our case. The cmds docs say scriptJobs do not exist in the batch application, which we need them to.


The docs may benefit from being a bit clearer, as they seem to imply that the usage I had above was perfectly fine.

I think you've given us enough info to go on though, thank you so much!

0 Likes
Message 5 of 5

mikey.n
Enthusiast
Enthusiast

Short follow-up: With my testing I found that a kAfterCreateReference was triggered per reference node created, nested or not.
kAfterLoadReference was triggered only once for the nested reference though.

This is in 2018.2 though, so behaviour may have been changed in 2020, I haven't had time to test that.

0 Likes