using UnityEditor; using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using Perforce.P4; using System.Linq; using System.Reflection; using System.Text; using System.Xml.Linq; using SyntaxTree.VisualStudio.Unity.Bridge; namespace P4Connect { // Hook into Unitys Project File Generation. [InitializeOnLoad] public class VSTUFileHook { // necessary for XLinq to sae the xml project file in utf8 class Utf8StringWriter : StringWriter { public override Encoding Encoding { get { return Encoding.UTF8; } } } static void ProjectFileHook() { ProjectFilesGenerator.ProjectFileGeneration += (string name, string content) => { var document = XDocument.Parse(content); document.Root.Add(new XComment("PRJ FIX ME")); var str = new Utf8StringWriter(); document.Save(str); return str.ToString(); }; } static void SolutionFileHook() { ProjectFilesGenerator.SolutionFileGeneration += (string name, string content) => { var document = XDocument.Parse(content); document.Root.Add(new XComment("SLN FIX ME")); var str = new Utf8StringWriter(); document.Save(str); return str.ToString(); }; } } /// /// This class hooks up to and handles UnityVS modifying the project files /// VSTU has changed a lot, this stuff may be useless by now.... /// public class UnityVSBridge { // A bunch of strings used to find the project file generation event through reflection public const string UnityVSAssemblyName = "SyntaxTree.VisualStudio.Unity.Bridge"; public const string UnityVSProjectFileGeneratorTypename = "SyntaxTree.VisualStudio.Unity.Bridge.ProjectFilesGenerator"; public const string UnityVSProjectFileGenerationEventName = "ProjectFileGeneration"; public const string UnityVSProjectFileGenerationEventHandlerType = "SyntaxTree.VisualStudio.Unity.Bridge.FileGenerationHandler"; /// /// Static constructor /// public static void Initialize() { // And hook us up to UnityVS if (Config.UnityVsSupport) SetupUnityVSHook(); // Hook the connection settings event Config.PrefsChanged += OnConnectionSettingsChanged; // Register for project changes EditorApplication.projectWindowChanged += OnProjectWindowChanged; } /// /// Event handler called when the connection settings change /// static void OnConnectionSettingsChanged() { // Setup the root directories based on the updated path if (Config.UnityVsSupport) SetupUnityVSHook(); } /// /// Hook up to UnityVS ProjectFile event through reflection /// static void SetupUnityVSHook() { // First, find the UnityVS assembly Assembly unityVSAssembly = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; unityVSAssembly == null && i < assemblies.Length; ++i) { if (assemblies[i].FullName.Contains(UnityVSAssemblyName)) unityVSAssembly = assemblies[i]; } if (unityVSAssembly != null) { // Now that we have the assembly, find the project file generator class Type projectFileGeneratorType = unityVSAssembly.GetType(UnityVSProjectFileGeneratorTypename); if (projectFileGeneratorType != null) { // Then the project file generation event itself FieldInfo projectGeneration = projectFileGeneratorType.GetField(UnityVSProjectFileGenerationEventName); if (projectGeneration != null) { // Make a bridge delegate to our function Func currentDelegate = OnUnityVSProjectFilesChange; Type handlerType = unityVSAssembly.GetType(UnityVSProjectFileGenerationEventHandlerType); Delegate unityVSBridgeDelegate = Delegate.CreateDelegate(handlerType, currentDelegate.Target, currentDelegate.Method); if (unityVSBridgeDelegate != null) { // Register with the event handler projectGeneration.SetValue(null, unityVSBridgeDelegate); } else { Debug.LogError("P4Connect - Could not create conversion delegate to UnityVS ProjectFileGenerator"); } } else { Debug.LogError("P4Connect - Could not find ProjectFileGeneration.ProjectFileGeneration() in UnityVS namespace"); } } else { Debug.LogError("P4Connect - Could not find ProjectFileGeneration class in UnityVS namespace"); } } else { Debug.LogError("P4Connect - UnityVS Assembly doesn't appear to be loaded"); } } /// /// Called when unityVS re-creates project files /// /// The project being modified /// The content of the project file /// modified content if desired, we don't, we just use this method as an event static string OnUnityVSProjectFilesChange(string name, string content) { if (Config.UnityVsSupport) { string[] files = new string[2]; // First file is the solution file, which we derive from the project name files[0] = "UnityVS." + Main.ProjectName + ".sln"; // Second file is the project file itself files[1] = name; Engine.CheckoutAssets(files); } // We don't touch the content return content; } // Called whenever the project files change public static void OnProjectWindowChanged() { // The following files don't exist unless you have UnityVS if (Config.UnityVsSupport) { // Build a list of project and solution files we may want to check out List filesToTryAndCheckOut = new List(10); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "UnityVS." + Main.ProjectName + ".CSharp.csproj")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "UnityVS." + Main.ProjectName + ".CSharp.Editor.csproj")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "UnityVS." + Main.ProjectName + ".CSharp.Plugins.csproj")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "UnityVS." + Main.ProjectName + ".sln")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "UnityVS." + Main.ProjectName + ".sln.DotSettings")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "UnityVS." + Main.ProjectName + ".UnityScript.Plugins.unityproj")); // These files may not exist (the -vs ones only exist if you have Visual Studio set up) // so don't try to add them and get an error if they don't exist List filesToCheckOut = new List(filesToTryAndCheckOut.Where(file => System.IO.File.Exists(file))); // Now pass those off to the Add method // The using statement will make sure the connection is Disposed (i.e. closed) Engine.CheckoutAssets(filesToCheckOut.ToArray()); } } } }