ExportVisualStudio
From Unify Community Wiki
Author: Lasse Järvensivu a.k.a. Statement
Contents |
What it does
- Creates Visual Studio projects (2005, 2008, 2010 CTP) to allow Unity3D coders to benefit from intellisense.
- Automatic documentation download for missing documentation (all you need to do is extract the contents).
- Launches Visual Studio project for you.
- Includes .cs .js .boo .shader files out of the box and easy to mod!
Installation
Add this script file into a folder called "Editor", and allow for unity to compile it.
Usage
- 1) In Unity, select from the the menu "File/New Visual Studio Project/" the version of Visual Studio C# project you want to create. Please note that 2005 and 2008 versions are untested at the time of writing.
- 2) In case Xml documentation is missing, this script will attempt to download it. To successfully install the documentation you need to extract the Xml files into the opened directory.
- 3) If all went well, the script will offer to open the project for you.
C# - ExportVisualStudio.cs
// ExportVisualStudio.cs // Created by Lasse Järvensivu (no email please, but I might be on IRC as 'Statement'). // Feel free to modify code, make money from it, or claim it is yours. // I don't care. 'I hold no ownership to this document'. I hope you enjoy. // What it does: // * Creates Visual Studio projects (2005, 2008, 2010 CTP) to allow Unity3D coders to benefit from intellisense. // * Automatic documentation download for intellisense inline documentation (all you need to do is extract the contents). // * Launches Visual Studio project for you. // Installaton: // 1) Add this script file into a folder called "Editor", and allow for unity to compile it. // Usage: // 1) In Unity, select from the the menu "File/New Visual Studio Project/" the version of // Visual Studio C# project you want to create (Note that 2005 and 2008 versions are untested). // 2) In case Xml documentation is missing, this script will attempt to download it. To successfully // install the documentation you need to extract the Xml files into the opened directory. // 3) If all went well, the script will offer to open the project for you. // Troubleshooting: // If you want to silence the nagging compability warning, simply remove the first two lines of code in // ExportVisualStudio.GenerateVisualC2005 and ExportVisualStudio.GenerateVisualC2008. // // If downloading the documentation locks up unity, remove the call to DocumentationHelper.CheckAndDownload // in ExportVisualStudio.GenerateVisualC2005, ExportVisualStudio.GenerateVisualC2008 and // ExportVisualStudio.GenerateVisualC2010. // // Finally, don't be afraid to change the code to suit your needs. Start in ExportVisualStudio functions // and then work your way around the calls to figure out how the code works. It is not complex, it just // contains a lot of xml generation. using System; using System.IO; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Xml; using UnityEditor; using UnityEngine; using AssemblyReferences = System.Collections.Generic.List<VisualStudioProject.AssemblyReference>; using FileInfos = System.Collections.Generic.List<System.IO.FileInfo>; public sealed class ExportVisualStudio { /// <summary> /// Creates projectname.csproj and attempts to conform to Visual C# 2005 specificatons. /// </summary> [MenuItem("File/New Visual Studio Project/Visual C# 2005")] public static void GenerateVisualC2005() { if (!EditorUtility.DisplayDialog("Compability warning.", "*Version 2005 of Visual C# project has not been tested.\nIt might produce an invalid project file and possibly overwrite a valid one.\nAre you sure you want to continue?", "Yes", "No")) return; DocumentationHelper.CheckAndDownload(); string toolsVersion = "2.0"; string targetFrameworkVersion = "v2.0"; string productVersion = VisualStudioProject.VS2005ProjectVersion; GenerateProject(toolsVersion, targetFrameworkVersion, productVersion, true); } /// <summary> /// Creates projectname.csproj and attempts to conform to Visual C# 2008 specificatons. /// </summary> [MenuItem("File/New Visual Studio Project/Visual C# 2008")] public static void GenerateVisualC2008() { if (!EditorUtility.DisplayDialog("Compability warning.", "*Version 2008 of Visual C# project has not been tested.\nIt might produce an invalid project file and possibly overwrite a valid one.\nAre you sure you want to continue?", "Yes", "No")) return; DocumentationHelper.CheckAndDownload(); string toolsVersion = "3.5"; string targetFrameworkVersion = "v3.5"; string productVersion = VisualStudioProject.VS2008ProjectVersion; GenerateProject(toolsVersion, targetFrameworkVersion, productVersion); } /// <summary> /// Creates projectname.csproj and attempts to conform to Visual C# 2010 CTP Beta specificatons. /// </summary> [MenuItem("File/New Visual Studio Project/Visual C# 2010 (CTP)")] public static void GenerateVisualC2010() { DocumentationHelper.CheckAndDownload(); string toolsVersion = "4.0"; string targetFrameworkVersion = "v3.5"; string productVersion = VisualStudioProject.VS2010ProjectVersion; GenerateProject(toolsVersion, targetFrameworkVersion, productVersion); } /// <summary> /// Creates projectname.csproj. /// </summary> /// <param name="toolsVersion">The toolset version</param> /// <param name="targetFrameworkVersion">The intended target framework version of .net</param> /// <param name="productVersion">The version of visual studio to support</param> private static void GenerateProject(string toolsVersion, string targetFrameworkVersion, string productVersion) { GenerateProject(toolsVersion, targetFrameworkVersion, productVersion, false); } /// <summary> /// Creates projectname.csproj. /// </summary> /// <param name="toolsVersion">The toolset version</param> /// <param name="targetFrameworkVersion">The intended target framework version of .net</param> /// <param name="productVersion">The version of visual studio to support</param> /// <param name="exportFor2005">If true, Import directive is omitted from the build. Useful when exporting for 2005.</param> private static void GenerateProject(string toolsVersion, string targetFrameworkVersion, string productVersion, bool exportFor2005) { VisualStudioProject project = new VisualStudioProject(); DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), "Assets")); project.AssemblyName = VisualStudioProject.GetProjectName(); project.Compiled.AddRange(directoryInfo.GetFiles("*.cs", SearchOption.AllDirectories)); project.Contents.AddRange(directoryInfo.GetFiles("*.shader", SearchOption.AllDirectories)); project.Contents.AddRange(directoryInfo.GetFiles("*.js", SearchOption.AllDirectories)); project.Contents.AddRange(directoryInfo.GetFiles("*.boo", SearchOption.AllDirectories)); project.ProductVersion = productVersion; project.ToolsVersion = toolsVersion; project.TargetFrameworkVersion = targetFrameworkVersion; project.ProjectGuid = VisualStudioProject.GetProjectGuid(); project.References = VisualStudioProject.GetCommonReferences(); project.RootNamespace = VisualStudioProject.GetProjectName(); project.SkipImport = exportFor2005; project.Build(); project.Save(); if (EditorUtility.DisplayDialog("Generation complete.", "Would you like to open the project?", "Yes", "No")) { string path = Path.Combine(Directory.GetCurrentDirectory(), VisualStudioProject.GetProjectName() + ".csproj"); FileInfo info = new FileInfo(path); System.Diagnostics.Process.Start(info.FullName); } } } internal static class DocumentationHelper { /// <summary> /// Checks for documentation files and attempts to download these if not found. /// </summary> internal static void CheckAndDownload() { FileInfo unityEngineDll = new FileInfo(VisualStudioProject.GetAssemblyPath(typeof(UnityEngine.Object))); FileInfo unityEditorDll = new FileInfo(VisualStudioProject.GetAssemblyPath(typeof(UnityEditor.Editor))); FileInfo unityEngineXml = new FileInfo(Path.Combine(unityEngineDll.Directory.ToString(), "UnityEngine.xml")); FileInfo unityEditorXml = new FileInfo(Path.Combine(unityEditorDll.Directory.ToString(), "UnityEditor.xml")); if ((!unityEngineXml.Exists || !unityEditorXml.Exists)) { string title = "Documentation missing."; string message = "Unity3D documentation not found.\nWould you attempt to download this now?\n(Documentation provided by unifycommuinty.com)"; bool download = EditorUtility.DisplayDialog(title, message, "Download", "Skip"); if (download) { DownloadDocumentationTo(unityEngineXml.Directory.FullName); } } } /// <summary> /// Downloads documentation to folder. /// </summary> /// <param name="destination">The folder where to place documentation zip to.</param> private static void DownloadDocumentationTo(string destination) { string url = @"http://www.unifycommunity.com/wiki/images/d/d2/Visual_Studio_docs_2.5.zip"; string file = Path.Combine(destination, "Visual_Studio_docs_2.5.zip"); try { WWW www = new WWW(url); while (!www.isDone) { EditorUtility.DisplayProgressBar("Downloading documentation...", "Downloading documentation for Visual Studio...", www.progress); } EditorUtility.DisplayProgressBar("Downloading documentation...", "Saving file...", 0.5f); File.WriteAllBytes(file, www.bytes); EditorUtility.ClearProgressBar(); System.Diagnostics.Process.Start(destination); bool open = EditorUtility.DisplayDialog("Documentation downloaded.", "Would you like to open the zipped archive?", "Yes", "No"); if (open) { System.Diagnostics.Process.Start(file); } } catch (Exception e) { Debug.LogWarning(string.Format("File download error ({0})", e.Message)); } } } /// <summary> /// Handles building a visual studio project. /// </summary> internal sealed class VisualStudioProject { public const string VS2005ProjectVersion = "8.0.50727"; public const string VS2008ProjectVersion = "9.0.21022"; public const string VS2010ProjectVersion = "10.0.20506"; // This is from the public beta build. /// <summary> /// See GetProjectGuid() /// </summary> public System.Guid ProjectGuid = System.Guid.Empty; /// <summary> /// The version of Visual Studio this project is targetted for /// </summary> public string ProductVersion = VS2010ProjectVersion; /// <summary> /// The projects root namespace (used when creating new files through visual studio) /// </summary> public string RootNamespace = string.Empty; /// <summary> /// The projects assembly name. Commonly the project name. See GetProjectName() /// </summary> public string AssemblyName = string.Empty; /// <summary> /// Some sort of version identifier for the tools in visual studio. /// </summary> public string ToolsVersion = "4.0"; /// <summary> /// The target .net framework version. /// </summary> public string TargetFrameworkVersion = "v3.5"; /// <summary> /// Relative path to the project where debug files are emitted during build events. /// </summary> public string DebugOutput = "Visual Studio/Debug/"; /// <summary> /// Relative path to the project where release files are emitted during build events. /// </summary> public string ReleaseOutput = "Visual Studio/Release/"; /// <summary> /// Mainly used for Visual Studio 2005 support. /// </summary> public bool SkipImport = false; /// <summary> /// List of references in the project /// </summary> public AssemblyReferences References = new AssemblyReferences(); /// <summary> /// All content that is not to compiled and included in the project /// </summary> public FileInfos Compiled = new FileInfos(); /// <summary> /// All content that is not to be compiled, but included in the project /// </summary> public FileInfos Contents = new FileInfos(); /// <summary> /// Is set on Build() and contains the XmlDocument which makes up this project. /// </summary> public XmlDocument GeneratedDocument; /// <summary> /// References to Assemblies /// </summary> internal sealed class AssemblyReference { public string Name; public string HintPath; public AssemblyReference(string name) : this(name, string.Empty) { } public AssemblyReference(string name, string hintPath) { Name = name; HintPath = hintPath; } } /// <summary> /// Builds the project as defined through the member settings. /// Access GeneratedDocument if you need to process contents easily through Xml. /// </summary> public void Build() { GeneratedDocument = new XmlDocument(); XmlDeclaration declaration = GeneratedDocument.CreateXmlDeclaration("1.0", "utf-8", null); GeneratedDocument.AppendChild(declaration); BuildProject(GeneratedDocument); } /// <summary> /// Saves the project to yourprojectname.csproj. /// </summary> public void Save() { if (GeneratedDocument != null) GeneratedDocument.Save(Path.Combine(Directory.GetCurrentDirectory(), GetProjectName() + ".csproj")); else Debug.LogError("Must build document before Save"); } #region Helper functions /// <summary> /// Returns a list of assembly references commonly accessed, such as System.Core, System.Xml and the assemblies exposed by Unity3D. /// </summary> /// <returns>A list of common assembly references.</returns> public static AssemblyReferences GetCommonReferences() { AssemblyReferences references = new AssemblyReferences(); AssemblyReference system = new AssemblyReference("System"); references.Add(system); AssemblyReference systemCore = new AssemblyReference("System.Core"); references.Add(systemCore); AssemblyReference systemXml = new AssemblyReference("System.XML"); references.Add(systemXml); AssemblyReference unityEngine = new AssemblyReference("UnityEngine", GetAssemblyPath(typeof(UnityEngine.Object))); references.Add(unityEngine); AssemblyReference unityEditor = new AssemblyReference("UnityEditor", GetAssemblyPath(typeof(UnityEditor.Editor))); references.Add(unityEditor); return references; } /// <summary> /// Returns the path where the assembly which holds type exists. /// </summary> /// <param name="type">The type to discover its associated assemblys path.</param> /// <returns>The associated assemblys path.</returns> public static string GetAssemblyPath(Type type) { return Assembly.GetAssembly(type).Location; } /// <summary> /// Creates a deterministic Guid based on a string. /// </summary> /// <param name="input">The string used as input to generate a Guid.</param> /// <returns>The generated Guid based on input.</returns> public static System.Guid StringGuid(string input) { MD5 md5 = MD5.Create(); Encoding encoding = Encoding.Default; byte[] bytes = encoding.GetBytes(input); byte[] hash = md5.ComputeHash(bytes); System.Guid guid = new System.Guid(hash); return guid; } /// <summary> /// Returns the project name based on the current directorys name (in lack of any API function). /// </summary> /// <returns>The current project name.</returns> public static string GetProjectName() { DirectoryInfo directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory()); string projectName = directoryInfo.Name; return projectName; } /// <summary> /// Creates a deterministic guid based on the MD5 hash of the current project name. /// </summary> /// <returns>A guid for this project name.</returns> public static System.Guid GetProjectGuid() { return StringGuid(GetProjectName()); } #endregion #region Helper functions to build the project in steps private void BuildProject(XmlDocument document) { XmlElement project = document.CreateElement("Project"); project.SetAttribute("ToolsVersion", ToolsVersion); project.SetAttribute("DefaultTargets", "Build"); project.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); BuildProperties(project, document); BuildConfigurationDebug(project, document); BuildConfigurationRelease(project, document); BuildReferences(project, document); BuildFiles(project, document); // Visual Studio 2005 security fix. if (!SkipImport) { BuildImport(project, document); } document.AppendChild(project); } private void BuildProperties(XmlElement project, XmlDocument document) { XmlElement propertyGroup = document.CreateElement("PropertyGroup"); XmlElement configuration = document.CreateElement("Configuration"); configuration.SetAttribute("Condition", " '$(Configuration)' == '' "); configuration.InnerText = "Debug"; propertyGroup.AppendChild(configuration); XmlElement platform = document.CreateElement("Platform"); platform.SetAttribute("Condition", " '$(Platform)' == '' "); platform.InnerText = "AnyCPU"; propertyGroup.AppendChild(platform); XmlElement productVersion = document.CreateElement("ProductVersion"); productVersion.InnerText = ProductVersion; propertyGroup.AppendChild(productVersion); XmlElement schemaVersion = document.CreateElement("SchemaVersion"); schemaVersion.InnerText = "2.0"; propertyGroup.AppendChild(schemaVersion); XmlElement projectGuid = document.CreateElement("ProjectGuid"); projectGuid.InnerText = ProjectGuid.ToString(); propertyGroup.AppendChild(projectGuid); XmlElement outputType = document.CreateElement("OutputType"); outputType.InnerText = "Library"; propertyGroup.AppendChild(outputType); XmlElement appDesignerFolder = document.CreateElement("AppDesignerFolder"); appDesignerFolder.InnerText = "Properties"; propertyGroup.AppendChild(appDesignerFolder); XmlElement rootNamespace = document.CreateElement("RootNamespace"); rootNamespace.InnerText = RootNamespace; propertyGroup.AppendChild(rootNamespace); XmlElement assemblyName = document.CreateElement("AssemblyName"); assemblyName.InnerText = AssemblyName; propertyGroup.AppendChild(assemblyName); XmlElement targetFrameworkVersion = document.CreateElement("TargetFrameworkVersion"); targetFrameworkVersion.InnerText = TargetFrameworkVersion; propertyGroup.AppendChild(targetFrameworkVersion); project.AppendChild(propertyGroup); } private void BuildConfigurationDebug(XmlElement project, XmlDocument document) { XmlElement propertyGroup = document.CreateElement("PropertyGroup"); propertyGroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "); XmlElement debugSymbols = document.CreateElement("DebugSymbols"); debugSymbols.InnerText = "true"; propertyGroup.AppendChild(debugSymbols); XmlElement debugType = document.CreateElement("DebugType"); debugType.InnerText = "full"; propertyGroup.AppendChild(debugType); XmlElement optimize = document.CreateElement("Optimize"); optimize.InnerText = "false"; propertyGroup.AppendChild(optimize); XmlElement outputPath = document.CreateElement("OutputPath"); outputPath.InnerText = DebugOutput; propertyGroup.AppendChild(outputPath); XmlElement defineConstants = document.CreateElement("DefineConstants"); defineConstants.InnerText = "DEBUG;TRACE"; propertyGroup.AppendChild(defineConstants); XmlElement errorReport = document.CreateElement("ErrorReport"); errorReport.InnerText = "prompt"; propertyGroup.AppendChild(errorReport); XmlElement warningLevel = document.CreateElement("WarningLevel"); warningLevel.InnerText = "4"; propertyGroup.AppendChild(warningLevel); project.AppendChild(propertyGroup); } private void BuildConfigurationRelease(XmlElement project, XmlDocument document) { XmlElement propertyGroup = document.CreateElement("PropertyGroup"); propertyGroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "); XmlElement debugType = document.CreateElement("DebugType"); debugType.InnerText = "pdbonly"; propertyGroup.AppendChild(debugType); XmlElement optimize = document.CreateElement("Optimize"); optimize.InnerText = "true"; propertyGroup.AppendChild(optimize); XmlElement outputPath = document.CreateElement("OutputPath"); outputPath.InnerText = ReleaseOutput; propertyGroup.AppendChild(outputPath); XmlElement defineConstants = document.CreateElement("DefineConstants"); defineConstants.InnerText = "TRACE"; propertyGroup.AppendChild(defineConstants); XmlElement errorReport = document.CreateElement("ErrorReport"); errorReport.InnerText = "prompt"; propertyGroup.AppendChild(errorReport); XmlElement warningLevel = document.CreateElement("WarningLevel"); warningLevel.InnerText = "4"; propertyGroup.AppendChild(warningLevel); project.AppendChild(propertyGroup); } private void BuildReferences(XmlElement project, XmlDocument document) { XmlElement itemGroup = document.CreateElement("ItemGroup"); foreach (AssemblyReference assemblyReference in References) { XmlElement reference = document.CreateElement("Reference"); reference.SetAttribute("Include", assemblyReference.Name); if (!string.IsNullOrEmpty(assemblyReference.HintPath)) { XmlElement hintPath = document.CreateElement("HintPath"); hintPath.InnerText = assemblyReference.HintPath; reference.AppendChild(hintPath); } itemGroup.AppendChild(reference); } project.AppendChild(itemGroup); } private void BuildFiles(XmlElement project, XmlDocument document) { XmlElement itemGroup = document.CreateElement("ItemGroup"); foreach (FileInfo fileInfo in Compiled) { // For each compiled file XmlElement compile = document.CreateElement("Compile"); compile.SetAttribute("Include", fileInfo.FullName); itemGroup.AppendChild(compile); } foreach (FileInfo fileInfo in Contents) { // For each .shader/.js/.boo XmlElement none = document.CreateElement("None"); none.SetAttribute("Include", fileInfo.FullName); itemGroup.AppendChild(none); } project.AppendChild(itemGroup); } private void BuildImport(XmlElement project, XmlDocument document) { XmlElement import = document.CreateElement("Import"); import.SetAttribute("Project", @"$(MSBuildToolsPath)/Microsoft.CSharp.targets"); project.AppendChild(import); } #endregion }
--Statement 06:50, 24 October 2009 (PDT)