Yeah I’d avoid touching the MEL files also on the grounds that technically this is violating copyright. No harm among friends but that it is the kind of thing that could add a month and several tens of thousands of dollars of lawyer time if for example your studio gets sold and you have to do a due-diligence sweep.
When I’ve run into this in the past I generally suggest just adding a start up script which overrwrites the original MEL in memory w/o touching the install itself. Something along these lines will let you grab the original mel :
def clone_mel_procedure(procedure : str) -> str:
"""
Grab the original text of mel proc as a string - you can re-eval to get the same functionailty
"""
s = maya.mel.eval(f"whatIs {procedure}")
if not "found in" in s:
raise RuntimeError (f"{procedure} is not an original Mel procedure")
local_copy = s.split("found in: ")[-1]
depth = 0
with open(local_copy, "rt") as melFile:
text = melFile.read()
header = re.search("global\W+proc\W+" + procedure + ".*\n", text)
counter = header.end()
for char in text[header.end():]:
depth += char == "{"
depth -= char == "}"
counter += 1
if depth == 0:
break
return text[header.start(): counter]
and you can use that to patch the command with a pre/post execute hook or to replace it altogether:
def patch_mel_procedure(procName : str, before_proc : str = None, after_proc : str = None, replace_proc: str = None):
"""
Patch a mel command adding callbacks which will fire before and/or after the original code.
"""
# reset the command to its original state
maya.mel.eval(f"source {procName}")
proc = extract_mel_definition(procName)
replacement_name = procName + "_orig"
pre_callback_name = procName + "_before"
post_callback_name = procName + "_after"
if before_proc and pre_callback_name not in before_proc:
raise ValueError(f"callback name should be: {pre_callback_name}")
if after_proc and post_callback_name not in after_proc:
raise ValueError(f"callback name should be: {post_callback_name}")
if replace_proc and f"global proc {procName}" not in replace_proc:
raise ValueError(f"callback name should be: {procName}")
# the original proc logic becomes the "_orig" function,
maya.mel.eval(proc.replace("proc " + procName, "proc " + replacement_name))
success = "entered interactively" in maya.mel.eval("whatIs " + replacement_name)
if not success:
raise RuntimeError (f"failed to redefine {procName}")
# synthesize a new procedure with same signature;
signature = re.search("(.*)\(.*\)", proc).group(0) # -> "global proc (string $a, string $b)"
arg_forward = re.search("\(.*\)", signature).group(0)
arg_forward = re.sub("(string \$)|(int \$)|(float \$)", "$", arg_forward)
arg_forward = re.sub("\[\]", "", arg_forward) # -> ($a, $b)
if not replace_proc:
# callback genertor
replace_proc = signature
replace_proc += "{\n"
replace_proc += '\t' + pre_callback_name + arg_forward + ";\n"
replace_proc += '\t' + replacement_name + arg_forward + ";\n"
replace_proc += '\t' + post_callback_name + arg_forward + ";\n"
replace_proc += "}\n"
local_signature = signature.replace("global proc", "proc")
pre_callback = before_proc or local_signature.replace(procName, pre_callback_name) + "{}\n"
post_callback = after_proc or local_signature.replace(procName, post_callback_name) + "{}\n"
for cb in (pre_callback, post_callback, replace_proc):
for line in cb.splitlines():
_logger.debug(line)
maya.mel.eval(pre_callback)
maya.mel.eval(post_callback)
maya.mel.eval(replace_proc)