using UnityEditor; using UnityEditor.Compilation; using System.Diagnostics; using Debug = UnityEngine.Debug; using UnityEngine; using System.Reflection; /// /// ____DESC: 手动reload domain 工具 /// public class ScriptCompileReloadTools { /* 说明 * 关于域重载 https://docs.unity.cn/cn/2021.3/Manual/DomainReloading.html * EditorApplication.LockReloadAssemblies()和 EditorApplication.UnlockReloadAssemblies() 最好成对 * 如果不小心LockReloadAssemblies3次 但是只UnlockReloadAssemblies了一次 那么还是不会重载 必须也要但是只UnlockReloadAssemblies3次 */ const string menuEnableManualReload = "Tools/Script/开启手动Reload Domain"; const string menuDisenableManualReload ="Tools/Script/关闭手动Reload Domain"; const string menuRealodDomain ="Tools/Script/Unlock Reload %t"; const string kManualReloadDomain = "ManualReloadDomain"; const string kFirstEnterUnity = "FirstEnterUnity"; //是否首次进入unity const string kReloadDomainTimer = "ReloadDomainTimer";//计时 /**************************************************/ //编译时间 static Stopwatch compileSW = new Stopwatch(); //是否手动reload static bool IsManualReload => PlayerPrefs.GetInt(kManualReloadDomain, -1) == 1; //缓存数据 域重载之后数据会变成false 如果不是false 那么就要重载 static bool tempData = false; //https://github.com/INeatFreak/unity-background-recompiler 来自这个库 反射获取是否锁住 static MethodInfo CanReloadAssembliesMethod; static bool IsLocked { get { if (CanReloadAssembliesMethod == null) { // source: https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/EditorApplication.bindings.cs#L154 CanReloadAssembliesMethod = typeof(EditorApplication).GetMethod("CanReloadAssemblies", BindingFlags.NonPublic | BindingFlags.Static); if (CanReloadAssembliesMethod == null) Debug.LogError("Can't find CanReloadAssemblies method. It might have been renamed or removed."); } return !(bool)CanReloadAssembliesMethod.Invoke(null, null); } } /**************************************************/ [InitializeOnLoadMethod] static void InitCompile() { //**************不需要这个可以注释******************************** CompilationPipeline.compilationStarted -= OnCompilationStarted; CompilationPipeline.compilationStarted += OnCompilationStarted; CompilationPipeline.compilationFinished -= OnCompilationFinished; CompilationPipeline.compilationFinished += OnCompilationFinished; //************************************************************** //域重载事件监听 AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload; AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload; AssemblyReloadEvents.afterAssemblyReload -= OnAfterAssemblyReload; AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload; EditorApplication.playModeStateChanged -= EditorApplication_playModeStateChanged; EditorApplication.playModeStateChanged += EditorApplication_playModeStateChanged; // 首次启动的时候 并不会马上设置 //if (PlayerPrefs.HasKey(kManualReloadDomain)) //{ // Menu.SetChecked(menuEnableManualReload, IsManualReload ? true : false); // Menu.SetChecked(menuDisenableManualReload, IsManualReload ? false : true); //} FirstCheckAsync(); } //首次打开检测 async static void FirstCheckAsync() { await System.Threading.Tasks.Task.Delay(100); //判断是否首次打开 //https://docs.unity.cn/cn/2021.3/ScriptReference/SessionState.html if (SessionState.GetBool(kFirstEnterUnity, true)) { SessionState.SetBool(kFirstEnterUnity, false); Menu.SetChecked(menuEnableManualReload, IsManualReload ? true : false); Menu.SetChecked(menuDisenableManualReload, IsManualReload ? false : true); if (IsManualReload) { UnlockReloadDomain(); LockRealodDomain(); } Debug.Log($"当前ReloadDomain状态,是否手动: {IsManualReload}"); } } //运行模式改变 private static void EditorApplication_playModeStateChanged(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredEditMode: break; case PlayModeStateChange.ExitingEditMode: if (tempData) { UnlockReloadDomain(); EditorUtility.RequestScriptReload(); } break; case PlayModeStateChange.EnteredPlayMode: tempData = true; break; case PlayModeStateChange.ExitingPlayMode: break; } } //当开始编译脚本 private static void OnCompilationStarted(object obj) { if (IsManualReload) { compileSW.Start(); Debug.Log("Begin Compile"); } } //结束编译 private static void OnCompilationFinished(object obj) { if (IsManualReload) { compileSW.Stop(); Debug.Log($"End Compile 耗时:{compileSW.ElapsedMilliseconds} ms"); compileSW.Reset(); } } //开始reload domain private static void OnBeforeAssemblyReload() { if (IsManualReload) { Debug.Log("Begin Reload Domain ......"); //记录时间 SessionState.SetInt(kReloadDomainTimer, (int)(EditorApplication.timeSinceStartup * 1000)); } } //结束reload domain private static void OnAfterAssemblyReload() { if (IsManualReload) { var timeMS = (int)(EditorApplication.timeSinceStartup * 1000) - SessionState.GetInt(kReloadDomainTimer, 0); Debug.Log($"End Reload Domain 耗时:{timeMS} ms"); LockRealodDomain(); } } static void LockRealodDomain() { //如果没有锁住 锁住 if (!IsLocked) { EditorApplication.LockReloadAssemblies(); } } static void UnlockReloadDomain() { //如果锁住了 打开 if (IsLocked) { EditorApplication.UnlockReloadAssemblies(); } } [MenuItem(menuEnableManualReload)] static void EnableManualReloadDomain() { Debug.Log("开启手动 Reload Domain"); Menu.SetChecked(menuEnableManualReload, true); Menu.SetChecked(menuDisenableManualReload, false); PlayerPrefs.SetInt(kManualReloadDomain, 1); //编辑器设置 projectsetting->editor->enterPlayModeSetting EditorSettings.enterPlayModeOptionsEnabled = true; EditorSettings.enterPlayModeOptions = EnterPlayModeOptions.DisableDomainReload; LockRealodDomain(); } [MenuItem(menuDisenableManualReload)] static void DisenableManualReloadDomain() { Debug.Log("关闭手动 Reload Domain"); Menu.SetChecked(menuEnableManualReload, false); Menu.SetChecked(menuDisenableManualReload, true); PlayerPrefs.SetInt(kManualReloadDomain, 0); UnlockReloadDomain(); EditorSettings.enterPlayModeOptionsEnabled = false; } //手动刷新 [MenuItem(menuRealodDomain)] static void ManualReload() { if (IsManualReload) { UnlockReloadDomain(); EditorUtility.RequestScriptReload(); } } }