using XGame.Editor.Build; using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Compilation; using UnityEngine; namespace XGame.Editor.Compiler { //[InitializeOnLoad] public static class CompileScriptsHandle { private static CompileResult result; [UnityEditor.Callbacks.DidReloadScripts] static void OnDidReloadScripts() { //Debug.Log("CompileScriptsHandle OnDidReloadScripts."); EditorApplication.quitting -= OnQuit; EditorApplication.quitting += OnQuit; CompilationPipeline.compilationFinished -= OnCompilationFinished; CompilationPipeline.compilationFinished += OnCompilationFinished; CompilationPipeline.assemblyCompilationFinished -= OnAssemblyCompilationFinished; CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; //加载 初始化ICompileEvents if (HasEvents) { EditorApplication.update += OnUpdate; } //Debug.Log($"CompileScriptsHandle InitializeOnLoad. isCompiling: {EditorApplication.isCompiling}"); } //[InitializeOnLoadMethod] //static void OnInitializeOnLoadMethod() //{ // Debug.Log("CompileScriptsHandle OnInitializeOnLoadMethod."); //} /// /// 监听编辑器退出事件 /// private static void OnQuit() { //Debug.Log("EditorApplication OnQuit."); Clear(); } /// /// 监听Assembly编译事件 /// 编译失败时需要记录失败状态 /// /// /// private static void OnAssemblyCompilationFinished(string obj, CompilerMessage[] messages) { //Debug.Log($"OnAssemblyCompilationFinished. obj:{obj?.ToString() ?? "null"} msgCount:{messages?.Length ?? 0}"); if (messages != null && HasEvents) { foreach(var msg in messages) { if (msg.type == CompilerMessageType.Error) { result.isFailed = true; result.message = msg.message; if (result.isCopyAssemblyFailed == false && msg.message.Contains("Copying assembly from")) { //assembly拷贝失败 result.isCopyAssemblyFailed = true; } //打印错误信息 BuildLog.Error($"OnAssemblyCompilation error. msg:{msg.message} file:{msg.file} line:{msg.line} col:{msg.column}"); } } } } /// /// 监听编译结束回调事件 /// 编译失败时 Unity 不会执行InitializeOnLoad /// 需要主动执行回调事件 /// /// private static void OnCompilationFinished(object obj) { //Debug.Log($"OnCompilationFinished. obj:{obj?.ToString() ?? "null"}"); if (result.isFailed == false) return; //编译失败,主动执行回调 if (HasEvents) { EditorApplication.update += OnUpdate; } } private static void OnUpdate() { //Debug.Log($"CompileScriptsHandle OnUpdate. isCompiling: {EditorApplication.isCompiling} isFailed:{result.isFailed}"); EditorApplication.update -= OnUpdate; if (UnityEditorInternal.InternalEditorUtility.inBatchMode == false && result.isFailed && result.isCopyAssemblyFailed) { //非BatchMode下, 编译失败,并且是拷贝Assembly失败,重新编译 BuildLog.Log($"Compile Scripts Error: Assembly copy failed. Restart RequestScriptCompilation."); result = default; CompilationPipeline.RequestScriptCompilation(); return; } var events = ReadEvents(); if (events != null) { var tempResult = result; result = default; for (int i = 0; i < events.Length; i++) { if (tempResult.isFailed) { events[i].OnCompileFailed(tempResult); } else { events[i].OnCompileSuccess(); } } events = null; } } private static string OutputPath { get { return Path.GetFullPath($"{Application.dataPath}/../ExtAssets/Editor/CompileEvents.json").Replace("\\", "/"); } } /// /// 是否有监听事件 /// private static bool HasEvents => File.Exists(OutputPath); public static void RegistEvent(ICompileEvent compileEvent) { var filePath = OutputPath; var dir = Path.GetDirectoryName(filePath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var str = $""; try { var writer = File.Exists(filePath) ? new StreamWriter(filePath, true) : new StreamWriter(filePath); writer.WriteLine(str); writer.Flush(); writer.Close(); BuildLog.Log($"CompileScriptsHandle RegistEvent:{str}"); } catch (Exception ex) { BuildLog.Exception(ex); } } private static ICompileEvent[] ReadEvents() { var path = OutputPath; if (File.Exists(path)) { List lst = new List(); try { Regex regex = new Regex(@"", RegexOptions.Multiline); var lines = File.ReadAllLines(path); foreach (var line in lines) { var match = regex.Match(line); if (match.Success) { var typeName = match.Groups[1].Value; var eventValue = match.Groups[2].Value; BuildLog.Log($"CompileScriptsHandle ReadEvents type:{typeName} value:{eventValue}"); Type type = Type.GetType(typeName); var compileEvent = LitJson.JsonMapper.ToObject(eventValue, type) as ICompileEvent; lst.Add(compileEvent); } } lst.Sort((a, b) => { return a.Priority - b.Priority; }); } catch (Exception ex) { BuildLog.Exception(ex); } //删除文件 Clear(); return lst.ToArray(); } return null; } public static void Clear() { var path = OutputPath; if (File.Exists(path)) { File.Delete(path); } } } }