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