You’ve got Threads in my Mel! (Timer Event Objects in Maya)

There’s been many times when I wanted to latch a command onto a  timer that runs independently of the main thread – still allowing control and interaction with maya while the timer is ticking.

The best example of this is an auto scene backup script.  Most, if not all, auto scene backup scripts out there latch onto some arbitrary events in the scriptJob command and execute the backup time check when these are triggered (selection change, tool change etc).

This typically does the job but can lead to some funny behavior depending on the events you’ve attached the backup to.

 


How could it be better?

In any other programming language that supports threads or even attaching timers to UI elements (ala maxScript) this would be very simple and is also simple enough problem inside a maya plugin – spawn a new thread, wait the given time then execute the command.

However I figured with Python’s implementation into Maya and it’s native ability for threading I should be able to achieve this without having to develop or distribute a compiled plugin.

 

It turns out it’s very simple.

 


Python:

 

#	timer.py	#

######################
#	imports
######################

import sys
import time
import threading
import maya.mel as mel
import maya.utils as utils
import maya.cmds as cmds
import string

######################
#	classes
######################

class TimerObj(threading.Thread):
	def __init__(self, runTime, command):
		self.runTime = runTime
		self.command = command
		threading.Thread.__init__(self)
	def run(self):
		time.sleep(self.runTime)
		utils.executeDeferred(mel.eval, prepMelCommand(self.command))

######################
#	functions
######################
def prepMelCommand(commandString):
	return cmds.encodeString(commandString).replace("\"",""")

def startTimerObj(runTime, command):
	newTimerObj = TimerObj(runTime, command)
	newTimerObj.start()

 

Really the important piece in this is the ‘utils.executeDeferred’ command which links the mel execution of the command back into the main thread.

If you don’t do this and lets say you just call:

mel.eval(prepMelCommand(self.command))

directly in the TimerObj thread you’ll get the following error:

# # C:Program FilesAutodeskMaya2008binpython25.zipthreading.py:540: RuntimeWarning: tp_compare didn't return -1 or -2 for exception
  del _active[_get_ident()]

Basically the thread is terminating badly because of the result generated in the ‘mel.eval’ command. Therefore if you want to call any Maya command outside the main thread then you need to utilize the ‘utils.executeDeferred’ or ‘utils.executeInMainThreadWithResult’ if you need the result.

  

 


Mel:

 To fully utilize this new command in a mel script you’d need to write something similar to this:

 

global proc startTimer(int $runTime, string $command)
{
	python("import timer;"
		+"timer.startTimerObj( " + $runTime + ", "" + encodeString($command) + "")");

}

startTimer(10, "print("Times Up!n");print("Hello World!n");");

 

 


Can this be used for other threading problems?

Of course this isn’t limited to simplistic timer objects and can be used for a whole range of threading goodness.  Threading is a tricky beast so tread carefully.

Some examples:

  • Realtime data streaming – why wait for the content to be fully read before you start to process it?
  • Idle syncing with servers or render farms without disturbing the user
  • Autoscript updating systems
  • Image hotloading
  • Background Photoshop / Maya communication layer
  • Version control automatic updating
  • Automatic Animation Rig distribution

 


Problems?

# Error: line 4: No module named timer
# Traceback (most recent call last):
#   File "<maya console>", line 1, in <module>
# ImportError: No module named tdimer # 

If you’re seeing an error like this or you’re having trouble getting the python part of this script working take a look at this quick tutorial on how to create and source a python script in mel.

 

5 thoughts on “You’ve got Threads in my Mel! (Timer Event Objects in Maya)”

  1. Hi!

    I know it’ll sound strange, im making my thesis in mel, bout rigging. And i’d love to see some thing refreshing automatically. The problem it’s that I dunno a thing bout python. Canyou help me by telling me better how to pull these ccode of yours to work in some sorta “step by step”.

    thank you very much!

  2. Hi,
    2,5 years late, well however, maybe yo still get this. I'm searching for a way to drive Maya timeline with an outside ( OSC ) signal. But whatever I try, even your approach, when set the time with an command, I can't even navigate the scene. Any Ideas, hints what I could try ?
    Cheers, ParticlePeter !

    1. Hey!
      I’ve been pretty much focused on Unity scripting the last couple of years. So I don’t really have any suggestions for you. Sorry.
      Rod.

Leave a Reply

Your email address will not be published. Required fields are marked *