using UnityEditor; using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using Perforce.P4; using System.Linq; using System.Reflection; using System.Text; using log4net; namespace P4Connect { /// /// This class hooks onto the Asset Save/Delete/Move process and makes sure that /// Perforce is updated accordingly. It uses the perforce connection class /// (which internally uses Config to retrieve the connection settings) /// to open a connection to the server and add the required changes (add/checkout/delete/move). /// public class AssetBridge : UnityEditor.AssetModificationProcessor { private static readonly ILog log = LogManager.GetLogger(typeof(AssetBridge)); // Static constructor public static void Initialize() { // Register for project changes EditorApplication.projectWindowChanged += OnProjectWindowChanged; } //// This method is called by Unity when assets are created BY Unity itself //// Note: This is not an override because Unity calls it through Invoke() //public static void OnWillCreateAsset(string arPath) //{ // Engine.CreateAsset(arPath); //} // This method is called by Unity when assets are about to be saved // We take this opportunity to either check out or add the assets // AND their associated .meta files. // Note: This is not an override because Unity calls it through Invoke() public static string[] OnWillSaveAssets(string[] arPaths) { // I don't know why Unity calls this with empty lists??? if (arPaths == null || arPaths.Count() == 0) { #if DEBUG log.Debug("OnWillSaveAssets: No Files"); #endif return arPaths; } #if DEBUG log.Debug("OnWillSaveAssets: " + Logger.StringArrayToString(arPaths)); #endif // Filter the files that are newly created from the ones that are modified List filesToCheckout = new List(10); List filesToAdd = new List(10); foreach (string file in arPaths) { string fullpath = Utils.AssetPathToFullPath(file); if (System.IO.File.Exists(fullpath)) { // The file already exists, check it out filesToCheckout.Add(file); } else { // This will be a new file filesToAdd.Add(file); } } if (filesToCheckout.Count() != 0) { #if DEBUG log.Debug("checkout: " + Logger.StringArrayToString(filesToCheckout.ToArray())); #endif Engine.CheckoutAssets(filesToCheckout.ToArray()); } if (filesToAdd.Count() != 0) { #if DEBUG log.Debug("add: " + Logger.StringArrayToString(filesToAdd.ToArray())); #endif Engine.CreateAssets(filesToAdd.ToArray()); } return arPaths; } // Unity Pro only public static void OnWillCreateAsset(string path) { #if DEBUG log.Debug("PRO: OnWillCreateAsset: " + path); #endif } // Unity Pro only public static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions options) { #if DEBUG log.Debug("PRO: OnWillDeleteAsset: "+ path + " options: " + options.ToString()); #endif return AssetDeleteResult.DidNotDelete; } // Unity Pro only public static AssetMoveResult OnWillMoveAsset(string oldpath, string newpath) { #if DEBUG log.Debug("PRO: OnWillMoveAsset: from: "+ oldpath + " to: " + newpath); #endif return AssetMoveResult.DidNotMove; } /// /// Called when the user double clicks an item to edit it /// We use it to check the file out if necessary /// [UnityEditor.Callbacks.OnOpenAsset(0)] public static bool OpenFile(int aInstanceID, int aLine) { if (Config.ValidConfiguration) { var assetPath = AssetDatabase.GetAssetPath(aInstanceID); bool checkout = false; switch (Queries.GetFileState(assetPath)) { case FileState.None: goto case FileState.InDepot; case FileState.InDepot: if (Config.AskBeforeCheckout) { string filename = System.IO.Path.GetFileName(assetPath); checkout = EditorUtility.DisplayDialog("P4Connect - Checkout " + filename, "Would you like to check out " + filename + "?", "Yes", "No"); } else { checkout = true; } break; default: // don't check out break; } if (checkout) { Engine.CheckoutAsset(assetPath); } } // In all cases, let the normal asset handler open the file return false; } /// /// Called whenever the project files change /// public static void CheckoutProjectFiles(bool aIncludeProjectFiles, bool aIncludeSolutionFiles) { log.Debug("CheckoutProjectFiles: " + aIncludeProjectFiles.ToString() + " " + aIncludeSolutionFiles.ToString()); // Build a list of project and solution files we may want to check out List filesToTryAndCheckOut = new List(10); if (aIncludeProjectFiles) { filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "Assembly-CSharp.csproj")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "Assembly-CSharp-Editor.csproj")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "Assembly-CSharp-vs.csproj")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, "Assembly-CSharp-Editor-vs.csproj")); } // Solution files if (aIncludeSolutionFiles) { filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, Main.ProjectName + ".sln")); filesToTryAndCheckOut.Add(System.IO.Path.Combine(Main.RootPath, Main.ProjectName + "-csharp.sln")); } // 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 if (filesToCheckOut.Any()) { Engine.CheckoutAssets(filesToCheckOut.ToArray()); } // Force the UnityVS files to be checked out as well UnityVSBridge.OnProjectWindowChanged(); } /// /// Called whenever the project windows changes /// static void OnProjectWindowChanged() { log.Debug("OnProjectWindowChanged"); CheckoutProjectFiles(Config.IncludeProjectFiles, Config.IncludeSolutionFiles); } } }