@@ -10,15 +10,34 @@ class Integrations
10
10
private const string MODULE_FILENAME = "unityoneclick" ;
11
11
private const string PACKAGE_NAME = "FbxExporters" ;
12
12
private const string VERSION_FILENAME = "README.txt" ;
13
- private const string VERSION_FIELD = "**Version** " ;
13
+ private const string VERSION_FIELD = "VERSION " ;
14
14
private const string VERSION_TAG = "{Version}" ;
15
15
private const string PROJECT_TAG = "{UnityProject}" ;
16
+ private const string INTEGRATION_TAG = "{UnityIntegrationsPath}" ;
16
17
17
- private const string FBX_EXPORT_SETTINGS_PATH = "FbxExporters /Integrations/Autodesk/maya/scripts/unityFbxExportSettings.mel" ;
18
+ private const string FBX_EXPORT_SETTINGS_PATH = "/Integrations/Autodesk/maya/scripts/unityFbxExportSettings.mel" ;
18
19
19
20
private const string MAYA_INSTRUCTION_FILENAME = "_safe_to_delete/_temp.txt" ;
20
21
21
- private const string MODULE_TEMPLATE_PATH = "FbxExporters/Integrations/Autodesk/maya/" + MODULE_FILENAME + ".txt" ;
22
+ private static string m_integrationFolderPath = null ;
23
+ public static string INTEGRATION_FOLDER_PATH
24
+ {
25
+ get {
26
+ if ( string . IsNullOrEmpty ( m_integrationFolderPath ) ) {
27
+ m_integrationFolderPath = Application . dataPath ;
28
+ }
29
+ return m_integrationFolderPath ;
30
+ }
31
+ set {
32
+ if ( ! string . IsNullOrEmpty ( value ) && System . IO . Directory . Exists ( value ) ) {
33
+ m_integrationFolderPath = value ;
34
+ } else {
35
+ Debug . LogError ( string . Format ( "Failed to set integration folder path, invalid directory \" {0}\" " , value ) ) ;
36
+ }
37
+ }
38
+ }
39
+
40
+ public const string MODULE_TEMPLATE_PATH = "Integrations/Autodesk/maya/" + MODULE_FILENAME + ".txt" ;
22
41
23
42
#if UNITY_EDITOR_OSX
24
43
private const string MAYA_MODULES_PATH = "Library/Preferences/Autodesk/Maya/modules" ;
@@ -28,12 +47,6 @@ class Integrations
28
47
private const string MAYA_MODULES_PATH = "maya/modules" ;
29
48
#endif
30
49
31
- public class MayaException : System . Exception {
32
- public MayaException ( ) { }
33
- public MayaException ( string message ) : base ( message ) { }
34
- public MayaException ( string message , System . Exception inner ) : base ( message , inner ) { }
35
- }
36
-
37
50
// Use string to define escaped quote
38
51
// Windows needs the backslash
39
52
#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX
@@ -70,7 +83,7 @@ public static string GetModulePath()
70
83
71
84
public static string GetModuleTemplatePath ( )
72
85
{
73
- return System . IO . Path . Combine ( Application . dataPath , MODULE_TEMPLATE_PATH ) ;
86
+ return System . IO . Path . Combine ( INTEGRATION_FOLDER_PATH , MODULE_TEMPLATE_PATH ) ;
74
87
}
75
88
76
89
public static string GetAppPath ( )
@@ -119,7 +132,7 @@ public static string GetFullMayaInstructionPath()
119
132
/// <returns>The export settings path.</returns>
120
133
public static string GetExportSettingsPath ( )
121
134
{
122
- return FBX_EXPORT_SETTINGS_PATH ;
135
+ return INTEGRATION_FOLDER_PATH + FBX_EXPORT_SETTINGS_PATH ;
123
136
}
124
137
125
138
public static string GetPackageVersion ( )
@@ -326,7 +339,8 @@ public static bool InstallMaya(bool verbose = false)
326
339
Dictionary < string , string > Tokens = new Dictionary < string , string > ( )
327
340
{
328
341
{ VERSION_TAG , GetPackageVersion ( ) } ,
329
- { PROJECT_TAG , GetProjectPath ( ) }
342
+ { PROJECT_TAG , GetProjectPath ( ) } ,
343
+ { INTEGRATION_TAG , INTEGRATION_FOLDER_PATH } ,
330
344
} ;
331
345
332
346
// parse template, replace "{UnityProject}" with project path
@@ -365,13 +379,35 @@ public static string GetMayaExe () {
365
379
return FbxExporters . EditorTools . ExportSettings . GetSelectedMayaPath ( ) ;
366
380
}
367
381
382
+ const string IntegrationZipPath = "FbxExporters/unityoneclick_for_maya.zip" ;
383
+
384
+ private static string DefaultIntegrationSavePath
385
+ {
386
+ get {
387
+ return Application . dataPath ;
388
+ }
389
+ }
390
+
391
+ private static string LastIntegrationSavePath = DefaultIntegrationSavePath ;
392
+
368
393
public static void InstallMayaIntegration ( )
369
394
{
370
395
var mayaExe = GetMayaExe ( ) ;
371
396
if ( string . IsNullOrEmpty ( mayaExe ) ) {
372
397
return ;
373
398
}
374
399
400
+ // decompress zip file if it exists, otherwise try using default location
401
+ if ( System . IO . File . Exists ( GetIntegrationZipFullPath ( ) ) ) {
402
+ var result = DecompressIntegrationZipFile ( ) ;
403
+ if ( ! result ) {
404
+ // could not find integration
405
+ return ;
406
+ }
407
+ } else {
408
+ Integrations . INTEGRATION_FOLDER_PATH = DefaultIntegrationSavePath ;
409
+ }
410
+
375
411
if ( ! Integrations . InstallMaya ( verbose : true ) ) {
376
412
return ;
377
413
}
@@ -388,5 +424,131 @@ public static void InstallMayaIntegration ()
388
424
}
389
425
UnityEditor . EditorUtility . DisplayDialog ( title , message , "Ok" ) ;
390
426
}
427
+
428
+ private static bool DecompressIntegrationZipFile ( )
429
+ {
430
+ // prompt user to enter location to unzip file
431
+ var unzipFolder = EditorUtility . OpenFolderPanel ( "Select Location to Save Maya Integration" , LastIntegrationSavePath , "" ) ;
432
+ if ( string . IsNullOrEmpty ( unzipFolder ) ) {
433
+ // user has cancelled, do nothing
434
+ return false ;
435
+ }
436
+
437
+ // check that this is a valid location to unzip the file
438
+ if ( ! DirectoryHasWritePermission ( unzipFolder ) ) {
439
+ // display dialog to try again or cancel
440
+ var result = UnityEditor . EditorUtility . DisplayDialog ( "No Write Permission" ,
441
+ string . Format ( "Directory \" {0}\" does not have write access" , unzipFolder ) ,
442
+ "Select another Directory" ,
443
+ "Cancel"
444
+ ) ;
445
+
446
+ if ( result ) {
447
+ InstallMayaIntegration ( ) ;
448
+ } else {
449
+ return false ;
450
+ }
451
+ }
452
+
453
+ LastIntegrationSavePath = unzipFolder ;
454
+
455
+ // if file already unzipped in this location, then prompt user
456
+ // if they would like to continue unzipping or use what is there
457
+ if ( FolderAlreadyUnzippedAtPath ( unzipFolder ) ) {
458
+ var result = UnityEditor . EditorUtility . DisplayDialogComplex ( "Integrations Exist at Path" ,
459
+ string . Format ( "Directory \" {0}\" already contains the decompressed integration" , unzipFolder ) ,
460
+ "Overwrite" ,
461
+ "Use Existing" ,
462
+ "Cancel"
463
+ ) ;
464
+
465
+ if ( result == 0 ) {
466
+ DecompressZip ( GetIntegrationZipFullPath ( ) , unzipFolder ) ;
467
+ } else if ( result == 2 ) {
468
+ return false ;
469
+ }
470
+ } else {
471
+ // unzip Integration folder
472
+ DecompressZip ( GetIntegrationZipFullPath ( ) , unzipFolder ) ;
473
+ }
474
+
475
+ Integrations . INTEGRATION_FOLDER_PATH = unzipFolder ;
476
+
477
+ return true ;
478
+ }
479
+
480
+ /// <summary>
481
+ /// Gets the integration zip full path as an absolute Unity-style path.
482
+ /// </summary>
483
+ /// <returns>The integration zip full path.</returns>
484
+ private static string GetIntegrationZipFullPath ( )
485
+ {
486
+ return Application . dataPath + "/" + IntegrationZipPath ;
487
+ }
488
+
489
+ /// <summary>
490
+ /// Determines if folder is already unzipped at the specified path
491
+ /// by checking if unityoneclick.txt exists at expected location.
492
+ /// </summary>
493
+ /// <returns><c>true</c> if folder is already unzipped at the specified path; otherwise, <c>false</c>.</returns>
494
+ /// <param name="path">Path.</param>
495
+ public static bool FolderAlreadyUnzippedAtPath ( string path )
496
+ {
497
+ return System . IO . File . Exists ( System . IO . Path . Combine ( path , Integrations . MODULE_TEMPLATE_PATH ) ) ;
498
+ }
499
+
500
+ /// <summary>
501
+ /// Make sure we can write to this directory.
502
+ /// Try creating a file in path directory, if it raises an error, then we can't
503
+ /// write here.
504
+ /// TODO: find a more reliable way to check this
505
+ /// </summary>
506
+ /// <returns><c>true</c>, if possible to write to path, <c>false</c> otherwise.</returns>
507
+ /// <param name="path">Path.</param>
508
+ public static bool DirectoryHasWritePermission ( string path )
509
+ {
510
+ try
511
+ {
512
+ using ( System . IO . FileStream fs = System . IO . File . Create (
513
+ System . IO . Path . Combine (
514
+ path ,
515
+ System . IO . Path . GetRandomFileName ( )
516
+ ) ,
517
+ 1 ,
518
+ System . IO . FileOptions . DeleteOnClose )
519
+ )
520
+ { }
521
+ return true ;
522
+ }
523
+ catch ( Exception )
524
+ {
525
+ return false ;
526
+ }
527
+ }
528
+
529
+ public static void DecompressZip ( string zipPath , string destPath ) {
530
+ System . Diagnostics . Process myProcess = new System . Diagnostics . Process ( ) ;
531
+ var ZIPAPP = "7z.exe" ;
532
+ #if UNITY_EDITOR_OSX
533
+ ZIPAPP = "7za" ;
534
+ #endif
535
+ myProcess . StartInfo . FileName = EditorApplication . applicationContentsPath + "/Tools/" + ZIPAPP ;
536
+ myProcess . StartInfo . WindowStyle = System . Diagnostics . ProcessWindowStyle . Hidden ;
537
+ myProcess . StartInfo . CreateNoWindow = true ;
538
+ myProcess . StartInfo . UseShellExecute = false ;
539
+
540
+ // Command line flags used:
541
+ // x : extract the zip contents so that they maintain the file hierarchy
542
+ // -o : specify where to extract contents
543
+ // -r : recurse subdirectories
544
+ // -y : auto yes to all questions (without this Unity freezes as the process waits for a response)
545
+ myProcess . StartInfo . Arguments = string . Format ( "x \" {0}\" -o\" {1}\" -r -y" , zipPath , destPath ) ;
546
+ myProcess . EnableRaisingEvents = true ;
547
+ myProcess . Start ( ) ;
548
+ myProcess . WaitForExit ( ) ;
549
+
550
+ // in case we unzip inside the Assets folder, make sure it updates
551
+ AssetDatabase . Refresh ( ) ;
552
+ }
391
553
}
392
554
}
0 commit comments