using UnityEditor; using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace P4Connect { /// <summary> /// THIS CLASS IS NOT CURRENTLY USED. /// It was trying to detect file changes external to Unity. /// </summary> public class FileWatcher { static HashSet<string> _AllMetaFiles; static IEnumerator _FileEnumerator; const int _MaxFileCountPerIteration = 10; enum State { Iterating, WaitingForReload } static State _State; /// <summary> /// Static constructor /// </summary> public static void Initialize() { _AllMetaFiles = new HashSet<string>(); // 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; } /// <summary> /// Event handler called when the connection settings change /// </summary> static void OnConnectionSettingsChanged() { // Setup the root directories based on the updated path if (Config.PerforceEnabled) { // Restart enumeration PrimeFiles(); _FileEnumerator = WatchForMetaChanges().GetEnumerator(); } } /// <summary> /// Periodic Update method, scans through a few more files /// </summary> 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(); } } } /// <summary> /// Primes the list of files from all the .meta in the directory /// </summary> 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(); /// <summary> /// Coroutine that parses the current file list and fires events for new/deleted files /// </summary> 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<string> newAllMetaFiles = new HashSet<string>(); List<string> addedFiles = new List<string>(_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; } /// <summary> /// Triggered when a file appears in the directory structure /// </summary> /// <param name="aSender">IGNORED</param> /// <param name="aEventArgs">The name of the file</param> 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); } /// <summary> /// Triggered when a file disappears from the directory structure /// </summary> /// <param name="aSender">IGNORED</param> /// <param name="aEventArgs">The name of the file</param> 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); } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19640 | Liz Lam | "Forking branch Main of perforce-software-p4connect to liz_lam-p4connect." | ||
//guest/perforce_software/p4connect/main/src/P4Connect/P4Connect/P4Connect.FileWatcher.cs | |||||
#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.FileWatcher.cs | |||||
#1 | 10940 | Norman Morse |
Inital Workshop release of P4Connect. Released under BSD-2 license |