2009
08.18

Timers have all sorts of uses, and unfortunately up until 8.5 Maya had no good way of checking a timer, and running a background event.

Previously you could check system time at certain events with a scriptJob, like selectionChanged, but it tends to slow Maya down right when the user was trying to interact.. so in a production environment that wasn’t a viable solution (usually scriptJobs aren’t, as nifty as they are).

Now, with the flexibility of python in Maya, and python’s ability to create threads, it’s quite simple to create a basic Timer class.

Note: I updated it to use threading.Event().wait() instead of a time.sleep() loop, and now I directly subclass threading.Thread.

[python]
”’
Usage:
def timerTest():
print ‘Hello World!’

#create and start a timer
timer = Timer(30, timerTest, repeat=True)
timer.start()

#To stop the timer
timer.stop()
”’

import threading

try:
from maya.utils import executeInMainThreadWithResult
except:
executeInMainThreadWithResult = None

class Timer(threading.Thread):
def __init__(self, interval, function, args=[], kwargs={}, repeat=True):
self.interval = interval
self.function = function
self.repeat = repeat
self.args = args
self.kwargs = kwargs
self.event = threading.Event()
threading.Thread.__init__(self)

def run(self):
def _mainLoop():
self.event.wait(self.interval)
if not self.event.isSet():
if executeInMainThreadWithResult:
executeInMainThreadWithResult(self.function, *self.args, **self.kwargs)
else:
self.function(*self.args, **self.kwargs)

if self.repeat:
while not self.event.isSet():
_mainLoop()
else:
_mainLoop()
self.stop()

def start(self):
self.event.clear()
threading.Thread.start(self)

def stop(self):
self.event.set()
threading.Thread.__init__(self)[/python]

”’
Usage:
def timerTest():
print ‘Hello World!’
#create and start a timer
timer = Timer(30, timerTest, repeat=True)
timer.start()
#To stop the timer
timer.stop()
”’
import threading
try:
from maya.utils import executeInMainThreadWithResult
except:
executeInMainThreadWithResult = None
class Timer(threading.Thread):
def __init__(self, interval, function, args=[], kwargs={}, repeat=True):
self.interval = interval
self.function = function
self.repeat = repeat
self.args = args
self.kwargs = kwargs
self.event = threading.Event()
threading.Thread.__init__(self)
def run(self):
def _mainLoop():
self.event.wait(self.interval)
if not self.event.isSet():
if executeInMainThreadWithResult:
executeInMainThreadWithResult(self.function, *self.args, **self.kwargs)
else:
self.function(*self.args, **self.kwargs)
if self.repeat:
while not self.event.isSet():
_mainLoop()
else:
_mainLoop()
self.stop()
def start(self):
self.event.clear()
threading.Thread.start(self)
def stop(self):
self.event.set()
threading.Thread.__init__(self)
2009
08.15

SQL logging from Maya

I was inspired by a post on tech-artists by Adam Pletcher over at Volition, he talked about using SQL to track usage stats for tools, and startup time for 3dsmax.

Getting the data:

I started with a simple database,  just tracking the tool name, the username, and the date/time. But there is room to expand that information later (I want to track arguments, and time taken per tool).

There’s a problem right away: accessing a remote database on every function call (that I want to track) is SLOW, to work around this I dump the data to a local temp file (I used csv), and use a timer in a separate thread to upload every N seconds (on my machine I do every 10 seconds, for the artist’s I’m still tweaking, but somewhere around 2-5 minutes seems to work well). The actual database access usually takes .1 to .5 of a second, so it’s not terrible. I also have it set to run with utils.executeDeferred(), so it goes unnoticed for me, even on my 10 second interval.

Sooo… I have a bunch of cool data in a table, now what?

CHARTS! :)

It even has alpha! :)

It even has alpha! :)

I used pycha and pycairo to create charts from the database, had to track down some missing dll’s to get it working, but not too bad. So far the most useful chart is function usage by user (given a  function, % that each person uses it), it helps me to spot tools that aren’t being used by certain users, which will allow me to train them on the new tool. This is good because if they never use it, they probably don’t know it exists.. :)

Where to go from here:

Break functions down by how long they take to execute, it should show me where most of our processor time is going as far as tools are concerned, so once I turn on function timing, that’s an immediate goal.

2009
08.11

A cool feature of Maya’s python is that it runs as an interactive session, and that lets you do this neat trick from any imported module

you can add objects to the __main__ namespace (The script editor’s interactive prompt), this is also where python will search when you use the MEL command python();

from some python file:

[python]
#import the interactive main module
import __main__

def someCommand():
”’This is a pretty basic function…”’
print ’someCommand called!’

#now assign it to an attribute in __main__
__main__.someCommand = someCommand
[/python]

[code]
python("someCommand()");
// someCommand called!
[/code]

This can also be used as a way to create global variables across multiple modules, as it is always present so long as Maya is open (although any attributes you define may not be, so check first :) )

2009
08.11

I have everything set up the way I want it now :) I’m running wordpress and a home server with Apache + subversion + Trac. So I can keep track of all my personal projects and files on the go. As a bonus, anyone who visits can yell at me for slacking on my personal work! :)