In this post, I will cover the design of a tool installer script for Maya.
Preface
I am going start a new series that details in some of the key implementations of Swift shelf. Xwift is a shelf that contains specialized scripts when I was producing my animated film. I want to write some blogs to document them, in case there’s anyone out there that needs some inspiration.
Everything is developed and tested using Maya 2022.
Swift is not (well, not yet) open-source and therefore I will not share the whole script in my post. However, after reading my posts I believe you can implement your own, given some time and effort.
Goal
We want a script that helps install scripts into Maya so maya will automatically load all the custom made tools when starting up.
Algorithm
The algorithm is simple and the script needs to do two things:
- Modify (or create) a file called
UserSetup.py
under a directory that Maya checks every time when starting up, and thisUserSetup.py
will load our tools. - Install (overwrite if necessary) all the scripts, plug-ins, and icons to appropriate directories that Maya loads when start.
Cross-platform Incompatiblities
Directory Difference
Interestingly, you are supposed to put scripts in different places with different OS. Which… further complicates the development. Therefore, I decided to develop two separate scripts that does the identical things but customized for Windows and macOS (I hate linux so it is out of the question). For example:
On Windows, scripts are placed under C:\Users\USER_NAME\Documents\maya\2022\scripts
, icons are placed under C:\Users\USER_NAME\Documents\maya\2022\prefs\icons
.
On macOS, scripts are placed under /Library/Preferences/Autodesk/Maya/2022/scripts/
, icons are placed under /Library/Preferences/Autodesk/Maya/2022/prefs/icons
.
Furthermore, if your system language is Simplified Chinese, the implementation of Maya in macOS, unlike Windows, can only go with system language, and for each language of Maya other than Windows Maya uses a different directory for custom tools. So even if you use other system language I think this problem will persist.
In this case if you want cross-language support, scripts are placed under /Library/Preferences/Autodesk/Maya/2022/zh_CN/scripts/
, icons are placed under /Library/Preferences/Autodesk/Maya/2022/zh_CN/prefs/icons
.
Slash and Backslash
Complicated enough? There’s more. You might already realized the directory in windows uses backslash, namely, \
. On macOS and presumably Linux, file paths are separated by slash, namely, /
.
If you recall, we are writing scripts in Python, and that’s when backslash becomes super troublesome, because backslash is supposed to be used for escape symbols.
Therefore in Python, \\
is what represents \
, while /
works as-is in Windows.
When manipulating file paths in Windows, this soon becomes extremely intolerable, so I wrote a little helper function:
Now everytime when you get a file path from python, pass that string through this function and this simple hack can save some lives.
Stupid? Absolutely. But does it work? Yes.
Preparation
Get and smartly assemble directories
Introduction
Now let’s get some important file locations sorted out. Like I mentioned above, these are places where Maya check for things.
Regardless of system versions, you can see a pattern of where most of the things are located. Take Windows as an example:
- Script and MEL:
C:\Users\USER_NAME\Documents\maya\2022\scripts
- Plug-in:
C:\Users\USER_NAME\Documents\maya\2022\plug-ins
- Icon:
C:\Users\USER_NAME\Documents\maya\2022\prefs\icons
Think of it this way:
- Script and MEL:
MAYA_APP_DIR\LATEST_MAYA_VERSION\scripts
- Plug-in:
MAYA_APP_DIR\LATEST_MAYA_VERSION\plug-ins
- Icon:
MAYA_APP_DIR\LATEST_MAYA_VERSION\prefs\icons
Oh! All I need is a function that can get MAYA_APP_DIR
and LATEST_MAYA_VERSION
, then I can assemble all the directories above!
How to get MAYA_APP_DIR from system
Well, turns out, using the os
package, there is a very handy line of code that will get you to the User folder of your computer.
That is, os.getenv("USERPROFILE")
will take you to C:\Users\USER_NAME\
.
Let’s get MAYA_APP_DIR using this tool.
How to get LATEST_MAYA_VERSION from system
Well, all we need, is navigate to the directory from above, get all the versions of Maya as numbers, and find the max. Yes, I know, older version of Maya like from a decade ago has version labeled as “maya20XX” and this method won’t work but it’s too old. I think most people nowadays at least uses Maya 2017 so should be fine.
Assemble everything
With the above implemented, everything else is easy. Using a simple {0}{1}.format(_, _)
trick will make your code look clean and neat.
Setting up userSetup.py
What is userSetup.py?
Maya will execute everything in this script when start up, when placed in the right place.
Where should I place it?
In windows, custom startup file is stored under C:\Users\USER_NAME\Documents\maya\scripts\userSetup.py
.
In macOS, custom startup file is stored under /Library/Preferences/Autodesk/Maya/scripts/userSetup.py
.
What should I write in it?
I am getting a bit ahead of myself here, but here’s what’s contained in my userSetup.py
.
Let me explain. When developing my shelf, I looked up Vasil Shotarov’s blog on how to make a Python shelf for maya, and I developed a modified version of his shelf.
The entire shelf is contained in a file called xwift_shelf.py
, and has a class named xwiftshelf
that can be called using xwiftshelf()
.
Therefore, this script’s logic is as follows:
from maya import cmds so I can execute Maya commands, then load the xwiftshelf()
in xwift_shelf.py
(Which will then load everything else), defer it a bit so this process doesn’t collide with other important Maya startup processes.
What should I do with it?
All there is left for you to write a function that moves the userSetup.py
to the Maya directory above or append it to the end of an already existed userSetup.py
.
Show me the code.
Here’s a fancy version I implemented that copies a pre-written userSetup.py
if such a file is not present, and ask the user to do it manually if such a file exist.
The reason why I chose to do it is because I don’t want it to append the same thing over and over again during development, because I need to re-install my scripts many, many times.
Getting the folder where the current script is located
This is a easy step yet important, because all other operations run in relative to this install script.
In my repository, I have my file organized like this (I omitted stuff that isn’t important):
xwift
icons
icon1.png, ...
plug-ins
plug-in1.mll, ...
scripts
script1.py
script2.mel, ...
install_script_macos.py
install_script_windows.py
No matter where you are in your computer, you can use the following line to get the location of the current install_script_OS.py
:
Assembling path of all the files of your custom toolbox
Now, let’s make the paths for all the paths of different things that our toolset need, using the file hierarchy above.
You will first need a little function to help you filter out the name of files that you want with a specific extension.
Then for each type of file, generate a list of file names with the given extension.
Installation
Step 1: Install userSetup
Simple. Just run the installUserSetup()
detailed above.
Step 2: Check if the folders are created
Normally, some of the folders, for example, plug-ins
, isn’t created.
When you try copy something into a non-existent folder, python will complain.
Therefore, you need a simple function to check if the folders exists. If not, create it.
Then, simply check if all the folders exist.
Step 3: Delete Maya Cache (New in 2022)
This step is not necessary, and is a new feature in 2022. However I find it a good habit.
Different from Maya 2020 and below, Maya 2022 will semi-compile every python script when launch. That is, before launching Maya:
|documents
|maya
|2022
|scripts
|your\_script.py
After you launch Maya:
|documents
|maya
|2022
|scripts
|your\_script.py
|\_\_pycache\_\_
|your\_script.pyc
And the way to do it is simple, simply recursively delete the folder using shutil.rmtree()
.
Step 4: Let’s make wrapper functions!
Obviously, it would be tedious to hard-code every step of copying. Instead, let’s make a little helper function that helps us do it.
Then, to install something, simply make wrapper functions using the helper function. Note I am using \\
to avoid the escaping symbol error.
Step 5: Do this to every single file!
Now that we harnessed the power to deliver any file to wherever we want, let’s do this to all files, thus completing the algorithm.
Conclusion
Whoa! That’s a lot of writing. I hope my words are understandable. I had given away 90% of all the code required to write such a script, and I hope it is a useful read. If you want to quickly say hi just shoot me a message using the contact portal.