remap reference paths on load

1,701 views
Skip to first unread message

Pierre A

unread,
Dec 16, 2010, 11:50:46 AM12/16/10
to python_inside_maya
Hi list,

I'm facing an issue regarding references which are deleted on load
when their path does not correspond to an existing file.

The user have a browse option to remap to an existing file, I'm
looking for a way to reproduce the behavior in a python script. I've
found no help in Echo All nor missingReferenceDialog.mel...

Otherwise, perhaps these workflows could work:
- parse the maya file ( if it's in ascii ), find the lines
corresponding to the creation of the references and test for the file
path. They should be like:
file -r -ns "NS" -dr 1 -rfn "REF_NAME" "PATH";
and
file -rdi 1 -ns "NS" -rfn "REF_NAME" "PATH";
But I don't know if it's safe...

- add a call back ( MSceneMessage.Message.kBeforeCreateReferenceCheck
or MSceneMessage.Message.kBeforeCreateReference ), but I don't know
which enum to use nor the callback associated ( addCallback,
addCheckCallback, addCheckFileCallback ) and the data accessible in
the callback.

Of course I need to have access to the name of the reference node,
associated to the file path. Best would be to be able to instantiate
it as a PyNode (or get its attrs with maya.cmds)

Thanks!

Christian Åkesson

unread,
Dec 16, 2010, 10:08:59 PM12/16/10
to python_in...@googlegroups.com, python_inside_maya
I am doing the ASCII parsing with a template file setup and it works great...

/Christian
- Sent from my iPhone -

> --
> http://groups.google.com/group/python_inside_maya

Jesse Capper

unread,
Dec 17, 2010, 4:08:17 PM12/17/10
to python_inside_maya

Pierre A

unread,
Dec 30, 2010, 9:12:58 AM12/30/10
to python_in...@googlegroups.com
Thanks for the link, actually I had already bumped into that one.

So let's recap the issue: if the file path does not lead to an existing file, the reference is not created.
This behavior is the same with buildLoadSettings set to True in the cmds.file function. And when there is no reference node in the scene, you've lost all your data. Too late.

Regarding the callbacks, only MSceneMessage.addCheckFileCallback, and MSceneMessage.addCheckCallback can be used, with the kBeforeCreateReferenceCheck enum. These callbacks will be triggered before reference creation.

If you parse a .ma file, there are at least three lines regarding reference creation:
1/ file -rdi 1 -ns "REF_NS" -dr 1 -rfn "REF_NAME" "/path/to/file.ma";
2/ file -r -ns "REF_NS" -dr 1 -rfn "REF_NAME" "/path/to/file.ma";
3/ createNode reference -n "REF_NAME";

The first line does not trigger the remap path popup ("abort..." - "skip" - "browse..." buttons). The second one does.
addCheckFileCallback and addCheckCallback are called just before 2/ is executed.

If you want to monitor the reference node creation, this step is executed after the path check. It's the line 3/. You can have callbacks thanks to MDGMessage.addNodeAddedCallback, but it's useless for me.

Among MSceneMessage.addCheckFileCallback and MSceneMessage.addCheckCallback, only addCheckFileCallback is relevant here because you can modify the MFileObject passed as argument of the callback (by reference).

Note: Don't forget to set retCode to True with OpenMaya.MScriptUtil.setBool(retCode, True). The signature of setBool is bool& but it seems to accept a bool*

In my particular case, I need the reference node name (rfn) to be able to remap the bad path to an existing one. Unfortunately, I have not found a way to get this piece of info in a straightforward manner.
I have tried to use the MCommandMessage.addCommandCallback in order to see which 2/ "file -r -ns .... " is executed, but the callback is called after the addCheckFileCallback.
Of course, the 1/ "file -rdi 1 -ns ... " are executed before addCheckFileCallback, and I could assume that 2/ commands will be called in the same order than 1/.
Another hack would be to directly parse the .ma file and build a list/dict for the list of 2/ command lines.
Then, by incrementing an index for each addCheckFileCallback call, I could match the reference name with the corresponding path.

The first solution proposed by Christian is clearly simpler, providing that the renaming process is not harmful. Unfortunately I can not overwrite the maya files.

I think I'll go with a .ma parsing for 2/ lines & building list of reference node name.

Michał Frątczak

unread,
Dec 7, 2018, 9:50:14 AM12/7/18
to Python Programming for Autodesk Maya
So, has anybody found a nice way to remap path to a referenced file based on referenceNode attributes?
It seems referenceNode is not accessible inside kBeforeCreateReferenceCheck callback

Robert White

unread,
Dec 7, 2018, 7:34:45 PM12/7/18
to Python Programming for Autodesk Maya
I've done this at a past job, and sadly don't have the code in front of me anymore.
But from what I remember you get a MFile object from the callback, and can edit the paths in that file object, and they will be passed into the created reference node after the callback is finished.

Michał Frątczak

unread,
Dec 17, 2018, 11:40:24 AM12/17/18
to Python Programming for Autodesk Maya
Thanks Robert !
I attach a simple callback to modify paths in case anyone finds it usefull.
However what I need to get is to have acces to reference node itself, as it has metadata needed for propoer path update. Anyone ? :)

import os
import string

import maya.OpenMaya as om
import maya.cmds as mc

__all__
= ['mfFixPathsOnSave_Register']


def addFirstSlash(i_str):
   
if len(i_str) and i_str[0] == '/' and i_str[1] != '/':
       
return '/' + i_str
   
return i_str

def PrependWithEnvVar(i_path, envVarList):
   
for ev in envVarList:
       
if ev not in os.environ:
           
continue
        v
= os.environ[ev]
       
if i_path.find(v) == 0:
           
return i_path.replace(v, '${%s}' % ev)
   
return i_path

def mfFixPaths():
    loop
= [('file', 'ftn', True), ('mfMTexture', 'texture', True),
           
('readCachedDeform', 'cacheFile', True), ('readCachedDeform', 'cacheFileExpanded', False),
           
('pgYetiMaya', 'cacheFileName', False), ('pgYetiMaya', 'outputCacheFileName', False)
           
]
   
for _t, _a, _envUpd in loop:
        nodes
= mc.ls(type=_t)
       
for f in nodes:
            _p
= mc.getAttr(f + '.' + _a)
            _fixed
= addFirstSlash(_p)
           
if _envUpd:
                _fixed
= PrependWithEnvVar(_fixed, ['PRROOT', 'PRDATA'])
            mc
.setAttr(f + '.' + _a, _fixed, type='string')

def mf_MSceneMessage_AfterOpen_CB(*args, **kwargs):
   
try:
        mfFixPaths
()
   
except:
        mc
.warning("mf_MSceneMessage_AfterOpen_CB() failed on mfFixPaths")

def mf_MSceneMessage_BeforeLoadReferenceCheck_CB(retCode, fileObject, clientData):
   
try:
        _path
= fileObject.rawFullName()
        _path_fixed
= addFirstSlash(_path)
        _path_fixed
= PrependWithEnvVar(_path_fixed, ['PRROOT', 'PRDATA'])
        fileObject
.setRawFullName( _path_fixed )
   
except:
        mc
.warning("mf_MSceneMessage_BeforeLoadReferenceCheck_CB() failed.")
    om
.MScriptUtil.setBool( retCode, True )


def mfFixPathsOnSave_Register():
   
print "Regisering MSceneMessage.kAfterOpen --> mf_MSceneMessage_AfterOpen_CB"
    om
.MSceneMessage.addCallback(om.MSceneMessage.kAfterOpen,
                                   
lambda *args, **kwargs:
                                        mf_MSceneMessage_AfterOpen_CB
(args, kwargs))

   
print "Regisering MSceneMessage.kBeforeLoadReferenceCheck --> mf_MSceneMessage_BeforeLoadReferenceCheck_CB"
    om
.MSceneMessage.addCheckFileCallback(om.MSceneMessage.kBeforeLoadReferenceCheck,
                                           
lambda retCode, fileObject, clientData:
                                                mf_MSceneMessage_BeforeLoadReferenceCheck_CB
(retCode, fileObject, clientData))

Enter code here...


Reply all
Reply to author
Forward
0 new messages