P4Connect.AssetBridge.cs #1

  • //
  • guest/
  • cswiedler/
  • p4connect/
  • dev/
  • shelves/
  • src/
  • P4Connect/
  • P4Connect/
  • P4Connect.AssetBridge.cs
  • View
  • Commits
  • Open Download .zip Download (8 KB)
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
{
	/// <summary>
	/// 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).
	/// </summary>
	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);
        //}

        /// <summary>
        /// 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.
        /// Only the files returned by this function will be further processed.
        /// Note: This is not an override because Unity calls it through Invoke()
        /// </summary>
        /// <param name="arPaths">Asset Paths from Unity</param>
        /// <returns>an array of asset paths for unity to continue processing</returns>
        public static string[] OnWillSaveAssets(string[] arPaths)
		{
            // I don't know why Unity calls this with empty lists???
            if (arPaths == null || !arPaths.Any())
            {
#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<string> filesToCheckout = new List<string>(10);
			List<string> filesToAdd = new List<string>(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;
		}

        /// <summary>
        /// This method is called by Unity when assets are created BY Unity itself
        /// Only enabled when using Unity PRO 
        /// </summary>
        /// <param name="path">Asset path of new asset</param>
        public static void OnWillCreateAsset(string path)
        {
#if DEBUG
            log.Debug("PRO: OnWillCreateAsset: " + path);
#endif
        }
        
        // Unity Pro only
        /// <summary>
        /// This method is called by Unity just before it deletes an asset
        /// Only enabled when using Unity PRO
        /// </summary>
        /// <param name="path">Asset path to the to-be-deleted Asset</param>
        /// <param name="options">enum RemoveAssetOptions</param>
        /// <returns>enum AssetDeleteResult</returns>
        public static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions options)
        {
#if DEBUG
            log.Debug("PRO: OnWillDeleteAsset: "+ path + " options: " + options.ToString());
#endif
            return AssetDeleteResult.DidNotDelete;
        }

        /// <summary>
        /// This method is called by Unity just before it moves an asset
        /// Only enabled when using Unity PRO
        /// </summary>
        /// <param name="oldpath">original asset path</param>
        /// <param name="newpath">new asset path</param>
        /// <returns>enum AssetMoveResult</returns>
        public static AssetMoveResult OnWillMoveAsset(string oldpath, string newpath)
        {
#if DEBUG
            log.Debug("PRO: OnWillMoveAsset:  from: "+ oldpath + " to: " + newpath);
#endif
            return AssetMoveResult.DidNotMove;
        }

		/// <summary>
		/// Called when the user double clicks an item to edit it
		/// We use it to check the file out if necessary
		/// </summary>
		/// <param name="aInstanceId">Object instance ID</param>
		/// <param name="aLine">Line number to go to</param>
		/// <returns>true if we opened asset, false to use external tool</returns>
		[UnityEditor.Callbacks.OnOpenAsset(0)]
		public static bool OpenFile(int aInstanceId, int aLine)
		{
			if (Config.ValidConfiguration)
			{
				var assetPath = AssetDatabase.GetAssetPath(aInstanceId);

			    if (Utils.IsDirectoryAsset(assetPath))
			        return false;

				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;
		}

		/// <summary>
		/// Called whenever the Visual Studio project files change
		/// </summary>
		/// <param name="aIncludeProjectFiles">true if  .csproj files are to be stored in Perforce</param>
		/// <param name="aIncludeSolutionFiles">true if .sln files are to be stored in Perforce</param>
		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<string> filesToTryAndCheckOut = new List<string>(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<string> filesToCheckOut = new List<string>(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();
		}

		/// <summary>
		/// Called whenever the project windows changes
		/// </summary>
		static void OnProjectWindowChanged()
		{
            log.Debug("OnProjectWindowChanged");
			CheckoutProjectFiles(Config.IncludeProjectFiles, Config.IncludeSolutionFiles);
		}
	}
}
# Change User Description Committed
#1 21852 cswiedler Branch //guest/cswiedler/p4connect
//guest/perforce_software/p4connect/dev/shelves/src/P4Connect/P4Connect/P4Connect.AssetBridge.cs
#1 17331 Norman Morse Dev branch for Shelves
//guest/perforce_software/p4connect/main/src/P4Connect/P4Connect/P4Connect.AssetBridge.cs
#3 16489 Norman Morse Another pass at async fstats.
Removed a UI update on exception
#2 16350 Norman Morse Minor Code Clean Up
Minor Documentation Clean Up
Changed Post Processor callback to ignore directories
Added option to use Server Typemap
#1 16209 Norman Morse Move entire source tree into "main" branch so workshop code will act correctly.
//guest/perforce_software/p4connect/src/P4Connect/P4Connect/P4Connect.AssetBridge.cs
#4 15244 Norman Morse Better Directory support in "add" "get latest" "refresh" and other commands.
Improved Project Root detection
Various Bug Fixes and Clean up
#3 15079 Norman Morse Rewrote AssetStatusCache to Cache AssetStatuses and FileMetaData
Fixed Edge conditions on Engine Operations
Change Debug output defaults.
Will now Checkout files which request to be "added" but which already exist in perforce.
Output P4Connect version to log on initialization.
#2 12512 Norman Morse Integrate from Dev branch, preparing for Beta3 release
#1 10940 Norman Morse Inital Workshop release of P4Connect.
Released under BSD-2 license