4
4
using UnityEngine ;
5
5
using UnityEditor ;
6
6
using System . Collections . Generic ;
7
+ using System . Linq ;
7
8
8
9
namespace FbxExporters . EditorTools {
9
10
@@ -288,39 +289,135 @@ private static string DefaultIntegrationSavePath {
288
289
}
289
290
}
290
291
291
- /// <summary>
292
- /// The paths where all the different versions of Maya are installed
293
- /// by default. Depends on the platform.
294
- /// </summary>
295
- public static string [ ] DCCVendorLocations {
296
- get {
297
- var environmentVariable = Environment . GetEnvironmentVariable ( "UNITY_3DAPP_VENDOR_LOCATIONS" ) ;
298
- if ( environmentVariable != null )
292
+ private static string GetMayaLocationFromEnvironmentVariable ( string env )
293
+ {
294
+ string result = null ;
295
+
296
+ if ( string . IsNullOrEmpty ( env ) )
297
+ return null ;
298
+
299
+ string location = Environment . GetEnvironmentVariable ( env ) ;
300
+
301
+ if ( string . IsNullOrEmpty ( location ) )
302
+ return null ;
303
+
304
+ //Remove any extra slashes on the end
305
+ //Maya would accept a single slash in either direction, so we should be able to
306
+ location = location . Replace ( "\\ " , "/" ) ;
307
+ location = location . TrimEnd ( '/' ) ;
308
+
309
+ if ( ! Directory . Exists ( location ) )
310
+ return null ;
311
+
312
+ if ( Application . platform == RuntimePlatform . WindowsEditor )
313
+ {
314
+ //If we are on Windows, we need only go up one location to get to the "Autodesk" folder.
315
+ result = Directory . GetParent ( location ) . ToString ( ) ;
316
+ }
317
+ else if ( Application . platform == RuntimePlatform . OSXEditor )
318
+ {
319
+ //We can assume our path is: /Applications/Autodesk/maya2017/Maya.app/Contents
320
+ //So we need to go up three folders.
321
+
322
+ var appFolder = Directory . GetParent ( location ) ;
323
+ if ( appFolder != null )
299
324
{
300
- string [ ] locations = environmentVariable . Split ( ';' ) ;
301
- List < string > locationsList = new List < string > ( ) ;
302
- for ( int i = 0 ; i < locations . Length ; i ++ )
325
+ var versionFolder = Directory . GetParent ( appFolder . ToString ( ) ) ;
326
+ if ( versionFolder != null )
303
327
{
304
- if ( Directory . Exists ( locations [ i ] ) )
328
+ var autoDeskFolder = Directory . GetParent ( versionFolder . ToString ( ) ) ;
329
+ if ( autoDeskFolder != null )
305
330
{
306
- locationsList . Add ( locations [ i ] ) ;
331
+ result = autoDeskFolder . ToString ( ) ;
307
332
}
308
333
}
309
- if ( locationsList . Count > 0 )
334
+ }
335
+ }
336
+ return result ;
337
+ }
338
+
339
+ /// <summary>
340
+ /// Returns a set of valid vendor folder paths with no trailing '/'
341
+ /// </summary>
342
+ private static HashSet < string > GetCustomVendorLocations ( )
343
+ {
344
+ HashSet < string > result = new HashSet < string > ( ) ;
345
+
346
+ var environmentVariable = Environment . GetEnvironmentVariable ( "UNITY_FBX_3DAPP_VENDOR_LOCATIONS" ) ;
347
+
348
+ if ( ! string . IsNullOrEmpty ( environmentVariable ) )
349
+ {
350
+ string [ ] locations = environmentVariable . Split ( ';' ) ;
351
+ foreach ( var location in locations )
352
+ {
353
+ if ( Directory . Exists ( location ) )
354
+ {
355
+ result . Add ( location ) ;
356
+ }
357
+ }
358
+ }
359
+
360
+
361
+ return result ;
362
+ }
363
+
364
+ private static HashSet < string > GetDefaultVendorLocations ( )
365
+ {
366
+ if ( Application . platform == RuntimePlatform . WindowsEditor )
367
+ {
368
+ HashSet < string > windowsDefaults = new HashSet < string > ( ) { "C:/Program Files/Autodesk" , "D:/Program Files/Autodesk" } ;
369
+ HashSet < string > existingDirectories = new HashSet < string > ( ) ;
370
+ foreach ( string path in windowsDefaults )
371
+ {
372
+ if ( Directory . Exists ( path ) )
310
373
{
311
- return locationsList . ToArray ( ) ;
374
+ existingDirectories . Add ( path ) ;
312
375
}
313
376
}
377
+ return existingDirectories ;
314
378
315
- switch ( Application . platform )
379
+ }
380
+ else if ( Application . platform == RuntimePlatform . OSXEditor )
381
+ {
382
+ HashSet < string > MacOSDefaults = new HashSet < string > ( ) { "/Applications/Autodesk" } ;
383
+ HashSet < string > existingDirectories = new HashSet < string > ( ) ;
384
+ foreach ( string path in MacOSDefaults )
316
385
{
317
- case RuntimePlatform . WindowsEditor :
318
- return new string [ ] { "C:/Program Files/Autodesk" , "D:/Program Files/Autodesk" } ;
319
- case RuntimePlatform . OSXEditor :
320
- return new string [ ] { "/Applications/Autodesk" } ;
321
- default :
322
- throw new NotImplementedException ( ) ;
386
+ if ( Directory . Exists ( path ) )
387
+ {
388
+ existingDirectories . Add ( path ) ;
389
+ }
323
390
}
391
+ return existingDirectories ;
392
+ }
393
+
394
+ throw new NotImplementedException ( ) ;
395
+ }
396
+
397
+ /// <summary>
398
+ /// Retrieve available vendor locations.
399
+ /// If there is valid alternative vendor locations, do not use defaults
400
+ /// always use MAYA_LOCATION when available
401
+ /// </summary>
402
+ public static string [ ] DCCVendorLocations
403
+ {
404
+ get
405
+ {
406
+ HashSet < string > result = GetCustomVendorLocations ( ) ;
407
+
408
+ if ( result == null || result . Count < 1 )
409
+ {
410
+ result = GetDefaultVendorLocations ( ) ;
411
+ }
412
+
413
+ var additionalLocation = GetMayaLocationFromEnvironmentVariable ( "MAYA_LOCATION" ) ;
414
+
415
+ if ( ! string . IsNullOrEmpty ( additionalLocation ) )
416
+ {
417
+ result . Add ( additionalLocation ) ;
418
+ }
419
+
420
+ return result . ToArray < string > ( ) ;
324
421
}
325
422
}
326
423
@@ -420,13 +517,19 @@ public void ClearDCCOptionNames()
420
517
dccOptionNames . Clear ( ) ;
421
518
}
422
519
520
+ public void ClearDCCOptions ( )
521
+ {
522
+ SetDCCOptionNames ( null ) ;
523
+ SetDCCOptionPaths ( null ) ;
524
+ }
525
+
423
526
/// <summary>
424
527
///
425
528
/// Find the latest program available and make that the default choice.
426
529
/// Will always take any Maya version over any 3ds Max version.
427
530
///
428
531
/// Returns the index of the most recent program in the list of dccOptionNames
429
- ///
532
+ /// Returns -1 on error.
430
533
/// </summary>
431
534
public int GetPreferredDCCApp ( )
432
535
{
@@ -435,33 +538,36 @@ public int GetPreferredDCCApp()
435
538
return - 1 ;
436
539
}
437
540
438
- int newestDCCVersionIndex = - 1 ;
541
+ int result = - 1 ;
439
542
int newestDCCVersionNumber = - 1 ;
440
543
441
544
for ( int i = 0 ; i < dccOptionNames . Count ; i ++ )
442
545
{
443
546
int versionToCheck = FindDCCVersion ( dccOptionNames [ i ] ) ;
444
547
if ( versionToCheck == - 1 )
445
548
{
549
+ if ( dccOptionNames [ i ] == "MAYA_LOCATION" )
550
+ return i ;
551
+
446
552
continue ;
447
553
}
448
554
if ( versionToCheck > newestDCCVersionNumber )
449
555
{
450
- newestDCCVersionIndex = i ;
556
+ result = i ;
451
557
newestDCCVersionNumber = versionToCheck ;
452
558
}
453
559
else if ( versionToCheck == newestDCCVersionNumber )
454
560
{
455
- int selection = ChoosePreferredDCCApp ( newestDCCVersionIndex , i ) ;
561
+ int selection = ChoosePreferredDCCApp ( result , i ) ;
456
562
if ( selection == i )
457
563
{
458
- newestDCCVersionIndex = i ;
564
+ result = i ;
459
565
newestDCCVersionNumber = FindDCCVersion ( dccOptionNames [ i ] ) ;
460
566
}
461
567
}
462
568
}
463
- Debug . Assert ( newestDCCVersionIndex >= - 1 && newestDCCVersionIndex < dccOptionNames . Count ) ;
464
- return newestDCCVersionIndex ;
569
+
570
+ return result ;
465
571
}
466
572
/// <summary>
467
573
/// Takes the index of two program names from dccOptionNames and chooses our preferred one based on the preference list
@@ -498,20 +604,23 @@ private int ChoosePreferredDCCApp(int optionA, int optionB)
498
604
/// <returns> the year/version OR -1 if the year could not be parsed </returns>
499
605
private static int FindDCCVersion ( string AppName )
500
606
{
501
- if ( AppName == null )
607
+ if ( string . IsNullOrEmpty ( AppName ) )
502
608
{
503
609
return - 1 ;
504
610
}
505
-
506
- int version ;
611
+ AppName = AppName . Trim ( ) ;
612
+ if ( string . IsNullOrEmpty ( AppName ) )
613
+ return - 1 ;
614
+
507
615
string [ ] piecesArray = AppName . Split ( ' ' ) ;
508
- if ( piecesArray . Length == 0 )
616
+ if ( piecesArray . Length < 2 )
509
617
{
510
618
return - 1 ;
511
619
}
512
620
//Get the number, which is always the last chunk separated by a space.
513
621
string number = piecesArray [ piecesArray . Length - 1 ] ;
514
622
623
+ int version ;
515
624
if ( int . TryParse ( number , out version ) )
516
625
{
517
626
return version ;
@@ -535,9 +644,10 @@ private static int FindDCCVersion(string AppName)
535
644
/// If MAYA_LOCATION is set, add this to the list as well.
536
645
/// </summary>
537
646
private static void FindDCCInstalls ( ) {
538
- var dccOptionName = instance . dccOptionNames ;
539
- var dccOptionPath = instance . dccOptionPaths ;
647
+ var dccOptionNames = instance . dccOptionNames ;
648
+ var dccOptionPaths = instance . dccOptionPaths ;
540
649
650
+ // find dcc installation from vendor locations
541
651
for ( int i = 0 ; i < DCCVendorLocations . Length ; i ++ )
542
652
{
543
653
if ( ! Directory . Exists ( DCCVendorLocations [ i ] ) )
@@ -555,8 +665,8 @@ private static void FindDCCInstalls() {
555
665
// Only accept those that start with 'maya' in either case.
556
666
if ( product . StartsWith ( "maya" , StringComparison . InvariantCultureIgnoreCase ) ) {
557
667
string version = product . Substring ( "maya" . Length ) ;
558
- dccOptionPath . Add ( GetMayaExePath ( productDir . FullName . Replace ( "\\ " , "/" ) ) ) ;
559
- dccOptionName . Add ( GetUniqueDCCOptionName ( kMayaOptionName + version ) ) ;
668
+ dccOptionPaths . Add ( GetMayaExePathFromLocation ( productDir . FullName . Replace ( "\\ " , "/" ) ) ) ;
669
+ dccOptionNames . Add ( GetUniqueDCCOptionName ( kMayaOptionName + version ) ) ;
560
670
continue ;
561
671
}
562
672
@@ -572,11 +682,21 @@ private static void FindDCCInstalls() {
572
682
continue ;
573
683
}
574
684
575
- dccOptionPath . Add ( exePath ) ;
576
- dccOptionName . Add ( maxOptionName ) ;
685
+ dccOptionPaths . Add ( exePath ) ;
686
+ dccOptionNames . Add ( maxOptionName ) ;
577
687
}
578
688
}
579
689
}
690
+
691
+ // add extra locations defined by special environment variables
692
+ string location = GetMayaLocationFromEnvironmentVariable ( "MAYA_LOCATION" ) ;
693
+
694
+ if ( ! string . IsNullOrEmpty ( location ) )
695
+ {
696
+ dccOptionPaths . Add ( GetMayaExePathFromLocation ( location ) ) ;
697
+ dccOptionNames . Add ( "MAYA_LOCATION" ) ;
698
+ }
699
+
580
700
instance . selectedDCCApp = instance . GetPreferredDCCApp ( ) ;
581
701
}
582
702
@@ -604,7 +724,7 @@ public static string GetFirstValidVendorLocation()
604
724
/// </summary>
605
725
/// <returns>The maya exe path.</returns>
606
726
/// <param name="location">Location of Maya install.</param>
607
- private static string GetMayaExePath ( string location )
727
+ private static string GetMayaExePathFromLocation ( string location )
608
728
{
609
729
switch ( Application . platform ) {
610
730
case RuntimePlatform . WindowsEditor :
@@ -684,7 +804,7 @@ public enum DCCType { Maya, Max };
684
804
public static void AddDCCOption ( string newOption , DCCType dcc ) {
685
805
if ( Application . platform == RuntimePlatform . OSXEditor && dcc == DCCType . Maya ) {
686
806
// on OSX we get a path ending in .app, which is not quite the exe
687
- newOption = GetMayaExePath ( newOption ) ;
807
+ newOption = GetMayaExePathFromLocation ( newOption ) ;
688
808
}
689
809
690
810
var dccOptionPaths = instance . dccOptionPaths ;
@@ -697,6 +817,14 @@ public static void AddDCCOption(string newOption, DCCType dcc){
697
817
switch ( dcc ) {
698
818
case DCCType . Maya :
699
819
var version = AskMayaVersion ( newOption ) ;
820
+ if ( version == null )
821
+ {
822
+ Debug . LogError ( "This version of Maya could not be launched properly" ) ;
823
+ UnityEditor . EditorUtility . DisplayDialog ( "Error Loading 3D Application" ,
824
+ "Failed to add Maya option, could not get version number from maya.exe" ,
825
+ "Ok" ) ;
826
+ return ;
827
+ }
700
828
optionName = GetUniqueDCCOptionName ( "Maya " + version ) ;
701
829
break ;
702
830
case DCCType . Max :
@@ -739,8 +867,25 @@ static string AskMayaVersion(string exePath) {
739
867
// Output is like: Maya 2018, Cut Number 201706261615
740
868
// We want the stuff after 'Maya ' and before the comma.
741
869
// (Uni-31601) less brittle! Consider also the mel command "about -version".
870
+ if ( string . IsNullOrEmpty ( resultString ) )
871
+ {
872
+ return null ;
873
+ }
874
+
875
+ resultString = resultString . Trim ( ) ;
742
876
var commaIndex = resultString . IndexOf ( ',' ) ;
743
- return resultString . Substring ( 0 , commaIndex ) . Substring ( "Maya " . Length ) ;
877
+
878
+ if ( commaIndex != - 1 )
879
+ {
880
+ const int versionStart = 5 ; // length of "Maya "
881
+ return resultString . Length > versionStart ? resultString . Substring ( 0 , commaIndex ) . Substring ( versionStart ) : null ;
882
+ }
883
+ else
884
+ {
885
+ //This probably means we tried to launch Maya to check the version but it was some sort of broken maya.
886
+ //We'll just return null and throw an error for it.
887
+ return null ;
888
+ }
744
889
}
745
890
746
891
/// <summary>
0 commit comments