Skip to content

Commit 3e424af

Browse files
authored
Merge pull request #134 from Unity-Technologies/UNI-25245-maya-in-non-default-path
Uni 25245 maya in non default path
2 parents c43a059 + 6b40c2a commit 3e424af

File tree

3 files changed

+300
-205
lines changed

3 files changed

+300
-205
lines changed

Assets/FbxExporters/Editor/FbxExportSettings.cs

Lines changed: 262 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using UnityEditorInternal;
44
using UnityEngine;
55
using UnityEditor;
6+
using System.Collections.Generic;
67

78
namespace FbxExporters.EditorTools {
89

@@ -98,8 +99,63 @@ public override void OnInspectorGUI() {
9899
GUILayout.EndHorizontal ();
99100

100101
EditorGUILayout.Space ();
101-
var installIntegrationContent = new GUIContent(
102-
"Install Maya Integration",
102+
103+
GUILayout.BeginHorizontal ();
104+
GUILayout.Label (new GUIContent (
105+
"Maya Application:",
106+
"Select the version of Maya where you would like to install the Unity integration."));
107+
108+
// dropdown to select Maya version to use
109+
var options = ExportSettings.GetMayaOptions();
110+
// make sure we never initially have browse selected
111+
if (exportSettings.selectedMayaApp == options.Length - 1) {
112+
exportSettings.selectedMayaApp = 0;
113+
}
114+
int oldValue = exportSettings.selectedMayaApp;
115+
exportSettings.selectedMayaApp = EditorGUILayout.Popup(exportSettings.selectedMayaApp, options);
116+
if (exportSettings.selectedMayaApp == options.Length - 1) {
117+
var ext = "exe";
118+
#if UNITY_EDITOR_OSX
119+
ext = "app";
120+
#endif
121+
string mayaPath = EditorUtility.OpenFilePanel ("Select Maya Application", ExportSettings.kDefaultAdskRoot, ext);
122+
123+
// check that the path is valid and references the maya executable
124+
if (!string.IsNullOrEmpty (mayaPath)) {
125+
if (!Path.GetFileNameWithoutExtension (mayaPath).ToLower ().Equals ("maya")) {
126+
// clicked on the wrong application, try to see if we can still find
127+
// maya in this directory.
128+
var mayaDir = new DirectoryInfo(Path.GetDirectoryName(mayaPath));
129+
#if UNITY_EDITOR_OSX
130+
var files = mayaDir.GetDirectories("*." + ext);
131+
#else
132+
var files = mayaDir.GetFiles ("*." + ext);
133+
#endif
134+
bool foundMaya = false;
135+
foreach (var file in files) {
136+
var filename = Path.GetFileNameWithoutExtension (file.Name).ToLower ();
137+
if (filename.Equals ("maya")) {
138+
mayaPath = file.FullName.Replace("\\","/");
139+
foundMaya = true;
140+
break;
141+
}
142+
}
143+
if (!foundMaya) {
144+
Debug.LogError (string.Format("Could not find Maya at: \"{0}\"", mayaDir.FullName));
145+
exportSettings.selectedMayaApp = oldValue;
146+
return;
147+
}
148+
}
149+
ExportSettings.AddMayaOption (mayaPath);
150+
Repaint ();
151+
} else {
152+
exportSettings.selectedMayaApp = oldValue;
153+
}
154+
}
155+
GUILayout.EndHorizontal ();
156+
157+
var installIntegrationContent = new GUIContent(
158+
"Install Unity Integration",
103159
"Install and configure the Unity integration for Maya so that you can import and export directly to this project.");
104160
if (GUILayout.Button (installIntegrationContent)) {
105161
FbxExporters.Editor.IntegrationsUI.InstallMayaIntegration ();
@@ -121,6 +177,20 @@ public class ExportSettings : ScriptableSingleton<ExportSettings>
121177
{
122178
public const string kDefaultSavePath = ".";
123179

180+
/// <summary>
181+
/// The path where all the different versions of Maya are installed
182+
/// by default. Depends on the platform.
183+
/// </summary>
184+
public const string kDefaultAdskRoot =
185+
#if UNITY_EDITOR_OSX
186+
"/Applications/Autodesk"
187+
#elif UNITY_EDITOR_LINUX
188+
"/usr/autodesk"
189+
#else // WINDOWS
190+
"C:/Program Files/Autodesk"
191+
#endif
192+
;
193+
124194
// Note: default values are set in LoadDefaults().
125195
public bool mayaCompatibleNames;
126196
public bool centerObjects;
@@ -132,6 +202,8 @@ public class ExportSettings : ScriptableSingleton<ExportSettings>
132202
[HideInInspector]
133203
public bool keepOriginalAfterConvert;
134204

205+
public int selectedMayaApp = 0;
206+
135207
[SerializeField]
136208
public UnityEngine.Object turntableScene;
137209

@@ -148,13 +220,201 @@ public class ExportSettings : ScriptableSingleton<ExportSettings>
148220
[SerializeField]
149221
string convertToModelSavePath;
150222

223+
// List of names in order that they appear in option list
224+
[SerializeField]
225+
private List<string> mayaOptionNames;
226+
// List of paths in order that they appear in the option list
227+
[SerializeField]
228+
private List<string> mayaOptionPaths;
229+
151230
protected override void LoadDefaults()
152231
{
153232
mayaCompatibleNames = true;
154233
centerObjects = true;
155234
keepOriginalAfterConvert = false;
156235
convertToModelSavePath = kDefaultSavePath;
157236
turntableScene = null;
237+
mayaOptionPaths = null;
238+
mayaOptionNames = null;
239+
}
240+
241+
/// <summary>
242+
/// Increments the name if there is a duplicate in MayaAppOptions dictionary.
243+
/// </summary>
244+
/// <returns>The unique name.</returns>
245+
/// <param name="name">Name.</param>
246+
private static string GetUniqueName(string name){
247+
if (!instance.mayaOptionNames.Contains(name)) {
248+
return name;
249+
}
250+
var format = "{1} ({0})";
251+
int index = 1;
252+
// try extracting the current index from the name and incrementing it
253+
var result = System.Text.RegularExpressions.Regex.Match(name, @"\((?<number>\d+?)\)$");
254+
if (result != null) {
255+
var number = result.Groups["number"].Value;
256+
int tempIndex;
257+
if (int.TryParse (number, out tempIndex)) {
258+
var indexOfNumber = name.LastIndexOf (number);
259+
format = name.Remove (indexOfNumber, number.Length).Insert (indexOfNumber, "{0}");
260+
index = tempIndex+1;
261+
}
262+
}
263+
264+
string uniqueName = null;
265+
do {
266+
uniqueName = string.Format (format, index, name);
267+
index++;
268+
} while (instance.mayaOptionNames.Contains(name));
269+
270+
return uniqueName;
271+
}
272+
273+
/// <summary>
274+
/// Find Maya installations at default install path.
275+
/// Add results to given dictionary.
276+
///
277+
/// If MAYA_LOCATION is set, add this to the list as well.
278+
/// </summary>
279+
private static void FindMayaInstalls() {
280+
instance.mayaOptionPaths = new List<string> ();
281+
instance.mayaOptionNames = new List<string> ();
282+
var mayaOptionName = instance.mayaOptionNames;
283+
var mayaOptionPath = instance.mayaOptionPaths;
284+
285+
// If the location is given by the environment, use it.
286+
var location = System.Environment.GetEnvironmentVariable ("MAYA_LOCATION");
287+
if (!string.IsNullOrEmpty(location)) {
288+
location = location.TrimEnd('/');
289+
mayaOptionPath.Add (GetMayaExePath (location.Replace ("\\", "/")));
290+
mayaOptionName.Add ("MAYA_LOCATION");
291+
}
292+
293+
// List that directory and find the right version:
294+
// either the newest version, or the exact version we wanted.
295+
var adskRoot = new System.IO.DirectoryInfo(kDefaultAdskRoot);
296+
foreach(var productDir in adskRoot.GetDirectories()) {
297+
var product = productDir.Name;
298+
299+
// Only accept those that start with 'maya' in either case.
300+
if (!product.StartsWith("maya", StringComparison.InvariantCultureIgnoreCase)) {
301+
continue;
302+
}
303+
// Reject MayaLT -- it doesn't have plugins.
304+
if (product.StartsWith("mayalt", StringComparison.InvariantCultureIgnoreCase)) {
305+
continue;
306+
}
307+
string version = product.Substring ("maya".Length);
308+
mayaOptionPath.Add (GetMayaExePath (productDir.FullName.Replace ("\\", "/")));
309+
mayaOptionName.Add (GetUniqueName("Maya " + version));
310+
}
311+
}
312+
313+
/// <summary>
314+
/// Gets the maya exe at Maya install location.
315+
/// </summary>
316+
/// <returns>The maya exe path.</returns>
317+
/// <param name="location">Location of Maya install.</param>
318+
private static string GetMayaExePath(string location)
319+
{
320+
#if UNITY_EDITOR_OSX
321+
// MAYA_LOCATION on mac is set by Autodesk to be the
322+
// Contents directory. But let's make it easier on people
323+
// and allow just having it be the app bundle or a
324+
// directory that holds the app bundle.
325+
if (location.EndsWith(".app/Contents")) {
326+
return location + "/MacOS/Maya";
327+
} else if (location.EndsWith(".app")) {
328+
return location + "/Contents/MacOS/Maya";
329+
} else {
330+
return location + "/Maya.app/Contents/MacOS/Maya";
331+
}
332+
#elif UNITY_EDITOR_LINUX
333+
return location + "/bin/maya";
334+
#else // WINDOWS
335+
return location + "/bin/maya.exe";
336+
#endif
337+
}
338+
339+
public static GUIContent[] GetMayaOptions(){
340+
if (instance.mayaOptionNames == null ||
341+
instance.mayaOptionNames.Count != instance.mayaOptionPaths.Count ||
342+
instance.mayaOptionNames.Count == 0) {
343+
FindMayaInstalls ();
344+
}
345+
346+
// remove options that no longer exist
347+
List<int> toDelete = new List<int>();
348+
for(int i = 0; i < instance.mayaOptionPaths.Count; i++) {
349+
var mayaPath = instance.mayaOptionPaths [i];
350+
if (!File.Exists (mayaPath)) {
351+
if (i == instance.selectedMayaApp) {
352+
instance.selectedMayaApp = 0;
353+
}
354+
instance.mayaOptionNames.RemoveAt (i);
355+
toDelete.Add (i);
356+
}
357+
}
358+
foreach (var index in toDelete) {
359+
instance.mayaOptionPaths.RemoveAt (index);
360+
}
361+
362+
GUIContent[] optionArray = new GUIContent[instance.mayaOptionPaths.Count+1];
363+
for(int i = 0; i < instance.mayaOptionPaths.Count; i++){
364+
optionArray [i] = new GUIContent(
365+
instance.mayaOptionNames[i],
366+
instance.mayaOptionPaths[i]
367+
);
368+
}
369+
optionArray [optionArray.Length - 1] = new GUIContent("Browse...");
370+
371+
return optionArray;
372+
}
373+
374+
public static void AddMayaOption(string newOption){
375+
// on OSX we get a path ending in .app, which is not quite the exe
376+
#if UNITY_EDITOR_OSX
377+
newOption = GetMayaExePath(newOption);
378+
#endif
379+
380+
var mayaOptionPaths = instance.mayaOptionPaths;
381+
if (mayaOptionPaths.Contains(newOption)) {
382+
instance.selectedMayaApp = mayaOptionPaths.IndexOf (newOption);
383+
return;
384+
}
385+
// get the version
386+
var version = AskMayaVersion(newOption);
387+
instance.mayaOptionNames.Add (GetUniqueName("Maya "+version));
388+
mayaOptionPaths.Add (newOption);
389+
instance.selectedMayaApp = mayaOptionPaths.Count - 1;
390+
}
391+
392+
/// <summary>
393+
/// Ask the version number by running maya.
394+
/// </summary>
395+
static string AskMayaVersion(string exePath) {
396+
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
397+
myProcess.StartInfo.FileName = exePath;
398+
myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
399+
myProcess.StartInfo.CreateNoWindow = true;
400+
myProcess.StartInfo.UseShellExecute = false;
401+
myProcess.StartInfo.RedirectStandardOutput = true;
402+
myProcess.StartInfo.Arguments = "-v";
403+
myProcess.EnableRaisingEvents = true;
404+
myProcess.Start();
405+
string resultString = myProcess.StandardOutput.ReadToEnd();
406+
myProcess.WaitForExit();
407+
408+
// Output is like: Maya 2018, Cut Number 201706261615
409+
// We want the stuff after 'Maya ' and before the comma.
410+
// TODO: less brittle! Consider also the mel command "about -version".
411+
var commaIndex = resultString.IndexOf(',');
412+
return resultString.Substring(0, commaIndex).Substring("Maya ".Length);
413+
}
414+
415+
public static string GetSelectedMayaPath()
416+
{
417+
return instance.mayaOptionPaths [instance.selectedMayaApp];
158418
}
159419

160420
public static string GetTurnTableSceneName(){

0 commit comments

Comments
 (0)