123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894 |
- using UnityEngine;
- using System;
- using System.Collections.Generic;
- using System.Security.Permissions;
- namespace UnityEditor.Formats.Fbx.Exporter
- {
- internal abstract class DCCIntegration
- {
- public abstract string DccDisplayName { get; }
- public abstract string IntegrationZipPath { get; }
- private static string s_integrationFolderPath = null;
- public static string IntegrationFolderPath
- {
- get{
- if (string.IsNullOrEmpty (s_integrationFolderPath)) {
- s_integrationFolderPath = Application.dataPath;
- }
- return s_integrationFolderPath;
- }
- set{
- if (!string.IsNullOrEmpty (value) && System.IO.Directory.Exists (value)) {
- s_integrationFolderPath = value;
- } else {
- Debug.LogError (string.Format("Failed to set integration folder path, invalid directory \"{0}\"", value));
- }
- }
- }
- public void SetIntegrationFolderPath(string path){
- IntegrationFolderPath = path;
- }
- /// <summary>
- /// Gets the integration zip full path as an absolute Unity-style path.
- /// </summary>
- /// <returns>The integration zip full path.</returns>
- public string IntegrationZipFullPath
- {
- get
- {
- return System.IO.Path.GetFullPath("Packages/com.unity.formats.fbx/Editor/Integrations~").Replace("\\", "/") + "/" + IntegrationZipPath;
- }
- }
- /// <summary>
- /// Gets the project path.
- /// </summary>
- /// <returns>The project path.</returns>
- public static string ProjectPath
- {
- get
- {
- return System.IO.Directory.GetParent(Application.dataPath).FullName.Replace("\\", "/");
- }
- }
- /// <summary>
- /// Installs the integration using the provided executable.
- /// </summary>
- /// <returns>The integration.</returns>
- /// <param name="exe">Exe.</param>
- [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- public abstract int InstallIntegration(string exe);
- /// <summary>
- /// Determines if folder is already unzipped at the specified path.
- /// </summary>
- /// <returns><c>true</c> if folder is already unzipped at the specified path; otherwise, <c>false</c>.</returns>
- /// <param name="path">Path.</param>
- public abstract bool FolderAlreadyUnzippedAtPath (string path);
- /// <summary>
- /// Launches application at given path
- /// </summary>
- /// <param name="AppPath"></param>
- [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- public static void LaunchDCCApplication(string AppPath)
- {
- System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
- myProcess.StartInfo.FileName = AppPath;
- myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
- myProcess.StartInfo.CreateNoWindow = false;
- myProcess.StartInfo.UseShellExecute = false;
- myProcess.EnableRaisingEvents = false;
- myProcess.Start();
- }
- }
- internal class MayaIntegration : DCCIntegration
- {
- public override string DccDisplayName { get { return "Maya"; } }
- public override string IntegrationZipPath { get { return "UnityFbxForMaya.7z"; } }
- private string FBX_EXPORT_SETTINGS_PATH { get { return "/Integrations/Autodesk/maya/scripts/unityFbxExportSettings.mel"; } }
- private string FBX_IMPORT_SETTINGS_PATH { get { return "/Integrations/Autodesk/maya/scripts/unityFbxImportSettings.mel"; } }
- private string MODULE_TEMPLATE_PATH { get { return "Integrations/Autodesk/maya/" + MODULE_FILENAME + ".txt"; } }
- private string MODULE_FILENAME { get { return "UnityFbxForMaya"; } }
- private const string PACKAGE_NAME = "com.unity.formats.fbx";
- private const string VERSION_FIELD = "VERSION";
- private const string VERSION_TAG = "{Version}";
- private const string PROJECT_TAG = "{UnityProject}";
- private const string INTEGRATION_TAG = "{UnityIntegrationsPath}";
- private const string MAYA_USER_STARTUP_SCRIPT = "userSetup.mel";
- private const string UI_SETUP_FUNCTION = "unitySetupUI";
- private string USER_STARTUP_CALL { get { return string.Format ("if(`exists {0}`){{ {0}; }}", UI_SETUP_FUNCTION); } }
- private static string MAYA_DOCUMENTS_PATH {
- get {
- switch (Application.platform) {
- case RuntimePlatform.WindowsEditor:
- return "maya";
- case RuntimePlatform.OSXEditor:
- return "Library/Preferences/Autodesk/Maya";
- default:
- throw new NotImplementedException ();
- }
- }
- }
- private static string MAYA_MODULES_PATH {
- get {
- return System.IO.Path.Combine(UserFolder, MAYA_DOCUMENTS_PATH + "/modules");
- }
- }
- private static string MAYA_SCRIPTS_PATH {
- get {
- return System.IO.Path.Combine(UserFolder, MAYA_DOCUMENTS_PATH + "/scripts");
- }
- }
- // Use string to define escaped quote
- // Windows needs the backslash
- protected static string EscapedQuote {
- get {
- switch (Application.platform) {
- case RuntimePlatform.WindowsEditor:
- return "\\\"";
- case RuntimePlatform.OSXEditor:
- return "\"";
- default:
- throw new NotSupportedException ();
- }
- }
- }
- protected string MayaConfigCommand { get {
- return string.Format("unityConfigure {0}{1}{0} {0}{2}{0} {0}{3}{0} {4} {5};",
- EscapedQuote, ProjectPath, ExportSettingsPath, ImportSettingsPath, (IsHeadlessInstall()), (HideSendToUnityMenu));
- }}
- private string MAYA_CLOSE_COMMAND { get {
- return string.Format("scriptJob -idleEvent quit;");
- }}
- protected static string UserFolder
- {
- get
- {
- switch (Application.platform)
- {
- case RuntimePlatform.WindowsEditor:
- return System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
- case RuntimePlatform.OSXEditor:
- return System.Environment.GetEnvironmentVariable("HOME");
- default:
- throw new NotSupportedException();
- }
- }
- }
- public static int IsHeadlessInstall ()
- {
- return 0;
- }
- public static int HideSendToUnityMenu
- {
- get{
- return ExportSettings.instance.HideSendToUnityMenuProperty?1:0;
- }
- }
- public string ModuleTemplatePath
- {
- get
- {
- return System.IO.Path.Combine(IntegrationFolderPath, MODULE_TEMPLATE_PATH);
- }
- }
- public static string PackagePath
- {
- get
- {
- return System.IO.Path.Combine(Application.dataPath, PACKAGE_NAME);
- }
- }
- /// <summary>
- /// Gets the path to the export settings file.
- /// Returns a relative path with forward slashes as path separators.
- /// </summary>
- /// <returns>The export settings path.</returns>
- public string ExportSettingsPath
- {
- get
- {
- return IntegrationFolderPath + FBX_EXPORT_SETTINGS_PATH;
- }
- }
- /// <summary>
- /// Gets the path to the import settings file.
- /// Returns a relative path with forward slashes as path separators.
- /// </summary>
- /// <returns>The import settings path.</returns>
- public string ImportSettingsPath{
- get
- {
- return IntegrationFolderPath + FBX_IMPORT_SETTINGS_PATH;
- }
- }
- /// <summary>
- /// Gets the user startup script path.
- /// Returns a relative path with forward slashes as path separators.
- /// </summary>
- /// <returns>The user startup script path.</returns>
- private static string GetUserStartupScriptPath(){
- return MAYA_SCRIPTS_PATH + "/" + MAYA_USER_STARTUP_SCRIPT;
- }
- public static string PackageVersion
- {
- get
- {
- return ModelExporter.GetVersionFromReadme();
- }
- }
- private static List<string> ParseTemplateFile(string FileName, Dictionary<string,string> Tokens )
- {
- List<string> lines = new List<string>();
- try
- {
- // Pass the file path and file name to the StreamReader constructor
- System.IO.StreamReader sr = new System.IO.StreamReader(FileName);
- // Read the first line of text
- string line = sr.ReadLine();
- // Continue to read until you reach end of file
- while (line != null)
- {
- foreach(KeyValuePair<string, string> entry in Tokens)
- {
- line = line.Replace(entry.Key, entry.Value);
- }
- lines.Add(line);
- //Read the next line
- line = sr.ReadLine();
- }
- //close the file
- sr.Close();
- }
- catch(Exception e)
- {
- Debug.LogError(string.Format("Exception reading module file template ({0})", e.Message));
- }
- return lines;
- }
- private static void WriteFile(string FileName, List<string> Lines )
- {
- try
- {
- //Pass the filepath and filename to the StreamWriter Constructor
- System.IO.StreamWriter sw = new System.IO.StreamWriter(FileName);
- foreach (string line in Lines)
- {
- //Write a line of text
- sw.WriteLine(line);
- }
- //Close the file
- sw.Close();
- }
- catch(Exception e)
- {
- Debug.LogException(e);
- Debug.LogError(string.Format("Exception while writing module file ({0})", e.Message));
- }
- }
- /// <summary>
- /// Creates the missing directories in path.
- /// </summary>
- /// <returns><c>true</c>, if directory was created, <c>false</c> otherwise.</returns>
- /// <param name="path">Path to create.</param>
- protected static bool CreateDirectory(string path){
- try
- {
- System.IO.Directory.CreateDirectory(path);
- }
- catch (Exception xcp)
- {
- Debug.LogException(xcp);
- return false;
- }
- if (!System.IO.Directory.Exists(path)) {
- return false;
- }
- return true;
- }
- [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- public int ConfigureMaya(string mayaPath)
- {
- int ExitCode = 0;
- try {
- if (!System.IO.File.Exists(mayaPath))
- {
- Debug.LogError (string.Format ("No maya installation found at {0}", mayaPath));
- return -1;
- }
- System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
- myProcess.StartInfo.FileName = mayaPath;
- myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
- myProcess.StartInfo.CreateNoWindow = true;
- myProcess.StartInfo.UseShellExecute = false;
- if (!ExportSettings.instance.LaunchAfterInstallation)
- {
- myProcess.StartInfo.RedirectStandardError = true;
- }
- string commandString;
- switch (Application.platform) {
- case RuntimePlatform.WindowsEditor:
- commandString = "-command \"{0}\"";
- break;
- case RuntimePlatform.OSXEditor:
- commandString = @"-command '{0}'";
- break;
- default:
- throw new NotImplementedException ();
- }
- if (ExportSettings.instance.LaunchAfterInstallation)
- {
- myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
- myProcess.StartInfo.CreateNoWindow = false;
- myProcess.StartInfo.Arguments = string.Format(commandString, MayaConfigCommand);
- }
- else
- {
- myProcess.StartInfo.Arguments = string.Format(commandString, MayaConfigCommand + MAYA_CLOSE_COMMAND);
- }
- myProcess.EnableRaisingEvents = true;
- myProcess.Start();
- if (!ExportSettings.instance.LaunchAfterInstallation)
- {
- string stderr = myProcess.StandardError.ReadToEnd();
- myProcess.WaitForExit();
- ExitCode = myProcess.ExitCode;
- Debug.Log(string.Format("Ran maya: [{0}]\nWith args [{1}]\nResult {2}",
- mayaPath, myProcess.StartInfo.Arguments, ExitCode));
- // see if we got any error messages
- if(ExitCode != 0){
- if(!string.IsNullOrEmpty(stderr)){
- Debug.LogError(string.Format("Maya installation error (exit code: {0}): {1}", ExitCode, stderr));
- }
- }
- }
- else
- {
- ExitCode = 0;
- }
- }
- catch (Exception e)
- {
- UnityEngine.Debug.LogError(string.Format ("Exception failed to start Maya ({0})", e.Message));
- ExitCode = -1;
- }
- return ExitCode;
- }
- public bool InstallMaya(bool verbose = false)
- {
- // What's happening here is that we copy the module template to
- // the module path, basically:
- // - copy the template to the user Maya module path
- // - search-and-replace its tags
- // - done.
- // But it's complicated because we can't trust any files actually exist.
- string moduleTemplatePath = ModuleTemplatePath;
- if (!System.IO.File.Exists(moduleTemplatePath))
- {
- Debug.LogError(string.Format("Missing Maya module file at: \"{0}\"", moduleTemplatePath));
- return false;
- }
- // Create the {USER} modules folder and empty it so it's ready to set up.
- string modulePath = MAYA_MODULES_PATH;
- string moduleFilePath = System.IO.Path.Combine(modulePath, MODULE_FILENAME + ".mod");
- bool installed = false;
- if (!System.IO.Directory.Exists(modulePath))
- {
- if (verbose) { Debug.Log(string.Format("Creating Maya Modules Folder {0}", modulePath)); }
- if (!CreateDirectory (modulePath)) {
- Debug.LogError(string.Format("Failed to create Maya Modules Folder {0}", modulePath));
- return false;
- }
- installed = false;
- }
- else
- {
- // detect if UnityFbxForMaya.mod is installed
- installed = System.IO.File.Exists(moduleFilePath);
- if (installed)
- {
- // (Uni-31606): remove this when we support parsing existing .mod files
- try
- {
- if (verbose) { Debug.Log(string.Format("Deleting module file {0}", moduleFilePath)); }
- System.IO.File.Delete(moduleFilePath);
- installed = false;
- }
- catch (Exception xcp)
- {
- Debug.LogException(xcp);
- Debug.LogWarning(string.Format ("Failed to delete plugin module file {0}", moduleFilePath));
- }
- }
- }
- // if not installed
- if (!installed)
- {
- Dictionary<string,string> Tokens = new Dictionary<string,string>()
- {
- {VERSION_TAG, PackageVersion },
- {PROJECT_TAG, ProjectPath },
- {INTEGRATION_TAG, IntegrationFolderPath },
- };
- // parse template, replace "{UnityProject}" with project path
- List<string> lines = ParseTemplateFile(moduleTemplatePath, Tokens);
- if (verbose) Debug.Log(string.Format("Copying plugin module file to {0}", moduleFilePath));
- // write out .mod file
- WriteFile(moduleFilePath, lines);
- }
- else
- {
- throw new NotImplementedException();
- // (Uni-31606) Parse maya mod file during installation and find location
- }
- return SetupUserStartupScript (verbose);
- }
- private bool SetupUserStartupScript(bool verbose = false){
- // setup user startup script
- string mayaStartupScript = GetUserStartupScriptPath ();
- string fileContents = string.Format("\n{0}", USER_STARTUP_CALL);
- // make sure scripts directory exists
- if (!System.IO.Directory.Exists(MAYA_SCRIPTS_PATH))
- {
- if (verbose) { Debug.Log(string.Format("Creating Maya Scripts Folder {0}", MAYA_SCRIPTS_PATH)); }
- if (!CreateDirectory (MAYA_SCRIPTS_PATH)) {
- Debug.LogError(string.Format("Failed to create Maya Scripts Folder {0}", MAYA_SCRIPTS_PATH));
- return false;
- }
- }
- else if (System.IO.File.Exists (mayaStartupScript)) {
- // script exists, check that the UI setup is being called
- try{
- using (System.IO.StreamReader sr = new System.IO.StreamReader (mayaStartupScript)) {
- while (sr.Peek () >= 0) {
- string line = sr.ReadLine ();
- if (line.Trim().Contains (UI_SETUP_FUNCTION)) {
- // startup call already in the file, nothing to do
- return true;
- }
- }
- }
- }
- catch(Exception e){
- Debug.LogException(e);
- Debug.LogError(string.Format("Exception while reading user startup file ({0})", e.Message));
- return false;
- }
- }
- // append text to file
- try{
- System.IO.File.AppendAllText (mayaStartupScript, fileContents);
- }
- catch(Exception e)
- {
- Debug.LogException(e);
- Debug.LogError(string.Format("Exception while writing to user startup file ({0})", e.Message));
- return false;
- }
- return true;
- }
- [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- public override int InstallIntegration (string exe)
- {
- if (!InstallMaya(verbose: true)) {
- return -1;
- }
- return ConfigureMaya (exe);
- }
- /// <summary>
- /// Determines if folder is already unzipped at the specified path
- /// by checking if UnityFbxForMaya.mod exists at expected location.
- /// </summary>
- /// <returns><c>true</c> if folder is already unzipped at the specified path; otherwise, <c>false</c>.</returns>
- /// <param name="path">Path.</param>
- public override bool FolderAlreadyUnzippedAtPath(string path)
- {
- if (string.IsNullOrEmpty (path)) {
- return false;
- }
- return System.IO.File.Exists (System.IO.Path.Combine (path, MODULE_TEMPLATE_PATH));
- }
- }
- internal class MayaLTIntegration : MayaIntegration
- {
- public override string DccDisplayName { get { return "Maya LT"; } }
- }
- internal class MaxIntegration : DCCIntegration
- {
- public override string DccDisplayName { get { return "3Ds Max"; } }
- private const string MaxScriptsPath = "Integrations/Autodesk/max/scripts/";
- private const string PluginName = "UnityFbxForMaxPlugin.ms";
- public const string PluginPath = MaxScriptsPath + PluginName;
- private const string ConfigureMaxScript = MaxScriptsPath + "configureUnityFbxForMax.ms";
- private const string ExportSettingsFile = MaxScriptsPath + "unityFbxExportSettings.ms";
- private const string ImportSettingsFile = MaxScriptsPath + "unityFbxImportSettings.ms";
- private const string PluginSourceTag = "UnityPluginScript_Source";
- private const string PluginNameTag = "UnityPluginScript_Name";
- private const string ProjectTag = "UnityProject";
- private const string ExportSettingsTag = "UnityFbxExportSettings";
- private const string ImportSettingsTag = "UnityFbxImportSettings";
- public override string IntegrationZipPath { get { return "UnityFbxForMax.7z"; } }
- /// <summary>
- /// Gets the absolute Unity path for relative path in Integrations folder.
- /// </summary>
- /// <returns>The absolute path.</returns>
- /// <param name="relPath">Relative path.</param>
- public static string GetAbsPath(string relPath){
- return MayaIntegration.IntegrationFolderPath + "/" + relPath;
- }
- private static string GetInstallScript(){
- Dictionary<string,string> Tokens = new Dictionary<string,string>()
- {
- {PluginSourceTag, GetAbsPath(PluginPath) },
- {PluginNameTag, PluginName },
- {ProjectTag, ProjectPath },
- {ExportSettingsTag, GetAbsPath(ExportSettingsFile) },
- {ImportSettingsTag, GetAbsPath(ImportSettingsFile) }
- };
- var installScript = "";
- // setup the variables to be used in the configure max script
- foreach (var t in Tokens) {
- installScript += string.Format (@"global {0} = @\""{1}\"";", t.Key, t.Value);
- }
- installScript += string.Format(@"filein \""{0}\""", GetAbsPath(ConfigureMaxScript));
- return installScript;
- }
- [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- public static int InstallMaxPlugin(string maxExe){
- if (Application.platform != RuntimePlatform.WindowsEditor) {
- Debug.LogError ("The 3DsMax Unity plugin is Windows only, please try installing a Maya plugin instead");
- return -1;
- }
- var installScript = GetInstallScript ();
- int ExitCode = 0;
- try {
- if (!System.IO.File.Exists(maxExe))
- {
- Debug.LogError (string.Format ("No 3DsMax installation found at {0}", maxExe));
- return -1;
- }
- System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
- myProcess.StartInfo.FileName = maxExe;
- myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
- myProcess.StartInfo.CreateNoWindow = true;
- myProcess.StartInfo.UseShellExecute = false;
- myProcess.StartInfo.RedirectStandardOutput = true;
- myProcess.StartInfo.Arguments = string.Format("-q -silent -mxs \"{0}\"", installScript);
- myProcess.EnableRaisingEvents = true;
- myProcess.Start();
- string stderr = myProcess.StandardOutput.ReadToEnd();
- myProcess.WaitForExit();
- ExitCode = myProcess.ExitCode;
- if (ExportSettings.instance.LaunchAfterInstallation)
- {
- LaunchDCCApplication(maxExe);
- }
- // TODO (UNI-29910): figure out what exactly causes this exit code + how to resolve
- if (ExitCode == -1073740791){
- Debug.Log(string.Format("Detected 3ds max exitcode {0} -- safe to ignore", ExitCode));
- ExitCode = 0;
- }
- // print any errors
- if(ExitCode != 0){
- if(!string.IsNullOrEmpty(stderr)){
- Debug.LogError(string.Format("3ds Max installation error (exit code: {0}): {1}", ExitCode, stderr));
- }
- }
- Debug.Log(string.Format("Ran max: [{0}]\nWith args [{1}]\nResult {2}",
- maxExe, myProcess.StartInfo.Arguments, ExitCode));
- }
- catch (Exception e)
- {
- UnityEngine.Debug.LogError(string.Format ("Exception failed to start Max ({0})", e.Message));
- ExitCode = -1;
- }
- return ExitCode;
- }
- [SecurityPermission(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
- public override int InstallIntegration(string exe){
- return MaxIntegration.InstallMaxPlugin (exe);
- }
- /// <summary>
- /// Determines if folder is already unzipped at the specified path
- /// by checking if plugin exists at expected location.
- /// </summary>
- /// <returns><c>true</c> if folder is already unzipped at the specified path; otherwise, <c>false</c>.</returns>
- /// <param name="path">Path.</param>
- public override bool FolderAlreadyUnzippedAtPath(string path)
- {
- if (string.IsNullOrEmpty (path)) {
- return false;
- }
- return System.IO.File.Exists (System.IO.Path.Combine (path, MaxIntegration.PluginPath));
- }
- }
- static class IntegrationsUI
- {
- /// <summary>
- /// The path of the DCC executable.
- /// </summary>
- public static string GetDCCExe () {
- return ExportSettings.SelectedDCCPath;
- }
- /// <summary>
- /// Gets the name of the selected DCC.
- /// </summary>
- /// <returns>The DCC name.</returns>
- public static string GetDCCName() {
- return ExportSettings.SelectedDCCName;
- }
- /// <summary>
- /// Opens a dialog showing whether the installation succeeded.
- /// </summary>
- /// <param name="dcc">Dcc name.</param>
- private static void ShowSuccessDialog(string dcc, int exitCode){
- string title, message, customMessage;
- if (exitCode != 0) {
- title = string.Format("Failed to install {0} Integration.", dcc);
- message = string.Format("Failed to configure {0}, please check logs (exitcode={1}).", dcc, exitCode);
- } else {
- if (ExportSettings.instance.LaunchAfterInstallation)
- {
- customMessage = "Installing Unity menu in {0}, application will open once installation is complete";
- }
- else
- {
- customMessage = "Enjoy the new Unity menu in {0}.";
- }
- title = string.Format("Completing installation of {0} Integration.", dcc);
- message = string.Format(customMessage, dcc);
- }
- UnityEditor.EditorUtility.DisplayDialog (title, message, "Ok");
- }
- public static void InstallDCCIntegration ()
- {
- var dccExe = GetDCCExe ();
- if (string.IsNullOrEmpty (dccExe)) {
- return;
- }
- string dccType = System.IO.Path.GetFileNameWithoutExtension (dccExe).ToLower();
- DCCIntegration dccIntegration;
- if (dccType.Equals ("maya")) {
- // could be Maya or Maya LT
- if (GetDCCName ().ToLower ().Contains ("lt")) {
- dccIntegration = new MayaLTIntegration ();
- } else {
- dccIntegration = new MayaIntegration ();
- }
- } else if (dccType.Equals ("3dsmax")) {
- dccIntegration = new MaxIntegration ();
- } else {
- throw new System.NotImplementedException ();
- }
- if (!GetIntegrationFolder (dccIntegration)) {
- // failed to get integration folder
- return;
- }
- int exitCode = dccIntegration.InstallIntegration (dccExe);
- ShowSuccessDialog (dccIntegration.DccDisplayName, exitCode);
- }
- private static bool GetIntegrationFolder(DCCIntegration dcc){
- // decompress zip file if it exists, otherwise try using default location
- var zipPath = dcc.IntegrationZipFullPath;
- if (System.IO.File.Exists (zipPath)) {
- return DecompressIntegrationZipFile (zipPath, dcc);
- }
- dcc.SetIntegrationFolderPath (ExportSettings.IntegrationSavePath);
- return true;
- }
- private static bool DecompressIntegrationZipFile(string zipPath, DCCIntegration dcc)
- {
- // prompt user to enter location to unzip file
- var unzipFolder = EditorUtility.OpenFolderPanel(string.Format("Select Location to Save {0} Integration", dcc.DccDisplayName), ExportSettings.IntegrationSavePath, "");
- if (string.IsNullOrEmpty(unzipFolder))
- {
- // user has cancelled, do nothing
- return false;
- }
- ExportSettings.IntegrationSavePath = unzipFolder;
- // check that this is a valid location to unzip the file
- if (!DirectoryHasWritePermission (unzipFolder)) {
- // display dialog to try again or cancel
- var result = UnityEditor.EditorUtility.DisplayDialog ("No Write Permission",
- string.Format("Directory \"{0}\" does not have write access", unzipFolder),
- "Select another Directory",
- "Cancel"
- );
- if (result) {
- InstallDCCIntegration ();
- } else {
- return false;
- }
- }
- // if file already unzipped in this location, then prompt user
- // if they would like to continue unzipping or use what is there
- if (dcc.FolderAlreadyUnzippedAtPath (unzipFolder)) {
- var result = UnityEditor.EditorUtility.DisplayDialogComplex ("Integrations Exist at Path",
- string.Format ("Directory \"{0}\" already contains the decompressed integration", unzipFolder),
- "Overwrite",
- "Use Existing",
- "Cancel"
- );
- if (result == 0) {
- DecompressZip (zipPath, unzipFolder);
- } else if (result == 2) {
- return false;
- }
- } else {
- // unzip Integration folder
- DecompressZip (zipPath, unzipFolder);
- }
- dcc.SetIntegrationFolderPath(unzipFolder);
- return true;
- }
- /// <summary>
- /// Make sure we can write to this directory.
- /// Try creating a file in path directory, if it raises an error, then we can't
- /// write here.
- /// TODO: find a more reliable way to check this
- /// </summary>
- /// <returns><c>true</c>, if possible to write to path, <c>false</c> otherwise.</returns>
- /// <param name="path">Path.</param>
- public static bool DirectoryHasWritePermission(string path)
- {
- try
- {
- using (System.IO.FileStream fs = System.IO.File.Create(
- System.IO.Path.Combine(
- path,
- System.IO.Path.GetRandomFileName()
- ),
- 1,
- System.IO.FileOptions.DeleteOnClose)
- )
- { }
- return true;
- }
- catch(Exception)
- {
- return false;
- }
- }
- public static void DecompressZip(string zipPath, string destPath){
- System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
- var ZIPAPP = "7z.exe";
- if (Application.platform == RuntimePlatform.OSXEditor) {
- ZIPAPP = "7za";
- }
- myProcess.StartInfo.FileName = EditorApplication.applicationContentsPath + "/Tools/" + ZIPAPP;
- myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
- myProcess.StartInfo.CreateNoWindow = true;
- myProcess.StartInfo.UseShellExecute = false;
- // Command line flags used:
- // x : extract the zip contents so that they maintain the file hierarchy
- // -o : specify where to extract contents
- // -r : recurse subdirectories
- // -y : auto yes to all questions (without this Unity freezes as the process waits for a response)
- myProcess.StartInfo.Arguments = string.Format("x \"{0}\" -o\"{1}\" -r -y", zipPath, destPath);
- myProcess.EnableRaisingEvents = true;
- myProcess.Start();
- myProcess.WaitForExit();
- // in case we unzip inside the Assets folder, make sure it updates
- AssetDatabase.Refresh ();
- }
- }
- }
|