using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEditor.Compilation; using UnityEngine; using UnityAssembly = UnityEditor.Compilation.Assembly; namespace Mirror.Weaver { public static class CompilationFinishedHook { const string MirrorRuntimeAssemblyName = "Mirror"; const string MirrorWeaverAssemblyName = "Mirror.Weaver"; public static Action OnWeaverMessage; // delegate for subscription to Weaver debug messages public static Action OnWeaverWarning; // delegate for subscription to Weaver warning messages public static Action OnWeaverError; // delete for subscription to Weaver error messages public static bool WeaverEnabled { get; set; } // controls whether we weave any assemblies when CompilationPipeline delegates are invoked public static bool UnityLogEnabled = true; // controls weather Weaver errors are reported direct to the Unity console (tests enable this) public static bool WeaveFailed { get; private set; } // holds the result status of our latest Weave operation // debug message handler that also calls OnMessageMethod delegate static void HandleMessage(string msg) { if (UnityLogEnabled) Debug.Log(msg); if (OnWeaverMessage != null) OnWeaverMessage.Invoke(msg); } // warning message handler that also calls OnWarningMethod delegate static void HandleWarning(string msg) { if (UnityLogEnabled) Debug.LogWarning(msg); if (OnWeaverWarning != null) OnWeaverWarning.Invoke(msg); } // error message handler that also calls OnErrorMethod delegate static void HandleError(string msg) { if (UnityLogEnabled) Debug.LogError(msg); if (OnWeaverError != null) OnWeaverError.Invoke(msg); } [InitializeOnLoadMethod] static void OnInitializeOnLoad() { CompilationPipeline.assemblyCompilationFinished += OnCompilationFinished; } static string FindMirrorRuntime() { foreach (UnityAssembly assembly in CompilationPipeline.GetAssemblies()) { if (assembly.name == MirrorRuntimeAssemblyName) { return assembly.outputPath; } } return ""; } static bool CompilerMessagesContainError(CompilerMessage[] messages) { return messages.Any(msg => msg.type == CompilerMessageType.Error); } static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) { // Do nothing if there were compile errors on the target if (CompilerMessagesContainError(messages)) { Debug.Log("Weaver: stop because compile errors on target"); return; } // Should not run on the editor only assemblies if (assemblyPath.Contains("-Editor") || assemblyPath.Contains(".Editor")) { return; } // don't weave mirror files string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); if (assemblyName == MirrorRuntimeAssemblyName || assemblyName == MirrorWeaverAssemblyName) { return; } // find Mirror.dll string mirrorRuntimeDll = FindMirrorRuntime(); if (string.IsNullOrEmpty(mirrorRuntimeDll)) { Debug.LogError("Failed to find Mirror runtime assembly"); return; } if (!File.Exists(mirrorRuntimeDll)) { // this is normal, it happens with any assembly that is built before mirror // such as unity packages or your own assemblies // those don't need to be weaved // if any assembly depends on mirror, then it will be built after return; } // find UnityEngine.CoreModule.dll string unityEngineCoreModuleDLL = UnityEditorInternal.InternalEditorUtility.GetEngineCoreModuleAssemblyPath(); if (string.IsNullOrEmpty(unityEngineCoreModuleDLL)) { Debug.LogError("Failed to find UnityEngine assembly"); return; } // build directory list for later asm/symbol resolving using CompilationPipeline refs HashSet dependencyPaths = new HashSet(); dependencyPaths.Add(Path.GetDirectoryName(assemblyPath)); foreach (UnityAssembly unityAsm in CompilationPipeline.GetAssemblies()) { if (unityAsm.outputPath != assemblyPath) continue; foreach (string unityAsmRef in unityAsm.compiledAssemblyReferences) { dependencyPaths.Add(Path.GetDirectoryName(unityAsmRef)); } } // passing null in the outputDirectory param will do an in-place update of the assembly if (Program.Process(unityEngineCoreModuleDLL, mirrorRuntimeDll, null, new[] { assemblyPath }, dependencyPaths.ToArray(), HandleWarning, HandleError)) { WeaveFailed = false; //Debug.Log("Weaving succeeded for: " + assemblyPath); } else { WeaveFailed = true; if (UnityLogEnabled) Debug.LogError("Weaving failed for: " + assemblyPath); } } } }