using UnityEditor; using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace P4Connect { /// /// THIS CLASS IS NOT CURRENTLY USED. /// It was trying to detect file changes external to Unity. /// public class FileWatcher { static HashSet _AllMetaFiles; static IEnumerator _FileEnumerator; const int _MaxFileCountPerIteration = 10; enum State { Iterating, WaitingForReload } static State _State; /// /// Static constructor /// public static void Initialize() { _AllMetaFiles = new HashSet(); // Prime the list of files PrimeFiles(); // Hook the connection settings event Config.PrefsChanged += OnConnectionSettingsChanged; // Prime the iterator _FileEnumerator = WatchForMetaChanges().GetEnumerator(); _State = State.Iterating; EditorApplication.update += Update; } /// /// Event handler called when the connection settings change /// static void OnConnectionSettingsChanged() { // Setup the root directories based on the updated path if (Config.PerforceEnabled) { // Restart enumeration PrimeFiles(); _FileEnumerator = WatchForMetaChanges().GetEnumerator(); } } /// /// Periodic Update method, scans through a few more files /// static void Update() { if (Config.PerforceEnabled) { switch (_State) { case State.Iterating: if (EditorApplication.isCompiling) { // Unity is compiling, finish checking files, we'll get reloaded eventually EditorApplication.LockReloadAssemblies(); while (_FileEnumerator.MoveNext()) ; // And scan one last time _FileEnumerator = WatchForMetaChanges().GetEnumerator(); while (_FileEnumerator.MoveNext()) ; _FileEnumerator = null; _State = State.WaitingForReload; EditorApplication.UnlockReloadAssemblies(); } else { if (!_FileEnumerator.MoveNext()) { _FileEnumerator = WatchForMetaChanges().GetEnumerator(); } } break; case State.WaitingForReload: break; default: throw new System.ArgumentException(); } } } /// /// Primes the list of files from all the .meta in the directory /// static void PrimeFiles() { _AllMetaFiles.Clear(); foreach (string file in System.IO.Directory.GetFiles(Main.DataPath, "*.meta", System.IO.SearchOption.AllDirectories)) { _AllMetaFiles.Add(file); } } static string[] GetFiles() { return System.IO.Directory.GetFiles(Main.DataPath, "*.meta", System.IO.SearchOption.AllDirectories); } delegate string[] AsyncGetFiles(); /// /// Coroutine that parses the current file list and fires events for new/deleted files /// static IEnumerable WatchForMetaChanges() { // Disable script recompiling EditorApplication.LockReloadAssemblies(); // Kick off a separate thread to do the scanning AsyncGetFiles getFiles = new AsyncGetFiles(GetFiles); IAsyncResult result = getFiles.BeginInvoke(null, null); // Yield as long as the operation has not completed while (!result.IsCompleted) yield return null; // Get the list of files back string[] currentFiles = getFiles.EndInvoke(result); int filesThisIteration = 0; HashSet newAllMetaFiles = new HashSet(); List addedFiles = new List(_MaxFileCountPerIteration); for (int i = 0; i < currentFiles.Length; ++i) { string file = currentFiles[i]; if (!_AllMetaFiles.Remove(file)) { // This is a new file addedFiles.Add(file); } // Add to the new hashset newAllMetaFiles.Add(file); if (++filesThisIteration >= _MaxFileCountPerIteration) { yield return null; filesThisIteration = 0; } } // Any remaining file in _AllMetaFiles has been deleted foreach (string file in _AllMetaFiles) { OnFileDeleted(file); } foreach (string file in addedFiles) { OnFileCreated(file); } // Swap the current list of files _AllMetaFiles = newAllMetaFiles; // Allow unity to reload assemblies EditorApplication.UnlockReloadAssemblies(); // And yield one last time so it can do just that. yield return null; } /// /// Triggered when a file appears in the directory structure /// /// IGNORED /// The name of the file static void OnFileCreated(string aFileName) { // Convert the path to a relative path string filePath = aFileName.Replace("\\", "/"); if (filePath.Contains(Main.RootPath)) filePath = aFileName.Substring(Main.RootPath.Length); // Delay the callback of the addition so the associated file has time to be created Engine.CreateAsset(filePath); } /// /// Triggered when a file disappears from the directory structure /// /// IGNORED /// The name of the file static void OnFileDeleted(string aFileName) { // Convert the path to a relative path string filePath = aFileName.Replace("\\", "/"); if (filePath.Contains(Main.RootPath)) filePath = aFileName.Substring(Main.RootPath.Length); // Delay the callback of the removal so the associated file has time to be deleted Engine.DeleteAsset(filePath); } } }