ExportVisualStudio

From Unify Community Wiki
Jump to: navigation, search

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)

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Tools