AssemblyTool.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. using System.IO;
  2. using System.Threading;
  3. using UnityEditor;
  4. using UnityEditor.Build.Player;
  5. using UnityEngine;
  6. namespace ET
  7. {
  8. public static class AssemblyTool
  9. {
  10. /// <summary>
  11. /// Unity线程的同步上下文
  12. /// </summary>
  13. static SynchronizationContext unitySynchronizationContext { get; set; }
  14. /// <summary>
  15. /// 程序集名字数组
  16. /// </summary>
  17. public static readonly string[] DllNames = { "Unity.Hotfix", "Unity.HotfixView", "Unity.Model", "Unity.ModelView" };
  18. [InitializeOnLoadMethod]
  19. static void Initialize()
  20. {
  21. unitySynchronizationContext = SynchronizationContext.Current;
  22. }
  23. /// <summary>
  24. /// 菜单和快捷键编译按钮
  25. /// </summary>
  26. [MenuItem("ET/Compile _F6", false, ETMenuItemPriority.Compile)]
  27. static void MenuItemOfCompile()
  28. {
  29. // 强制刷新一下,防止关闭auto refresh,文件修改时间不准确
  30. AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
  31. DoCompile();
  32. }
  33. /// <summary>
  34. /// 菜单和快捷键热重载按钮
  35. /// </summary>
  36. [MenuItem("ET/Reload _F7", false, ETMenuItemPriority.Compile)]
  37. static void MenuItemOfReload()
  38. {
  39. if (Application.isPlaying)
  40. CodeLoader.Instance?.Reload();
  41. }
  42. /// <summary>
  43. /// 执行编译代码流程
  44. /// </summary>
  45. public static void DoCompile()
  46. {
  47. // 强制刷新一下,防止关闭auto refresh,编译出老代码
  48. AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
  49. RefreshCodeMode();
  50. RefreshBuildType();
  51. bool isCompileOk = CompileDlls();
  52. if (!isCompileOk)
  53. return;
  54. CopyHotUpdateDlls();
  55. BuildHelper.ReGenerateProjectFiles();
  56. }
  57. /// <summary>
  58. /// 刷新代码模式
  59. /// </summary>
  60. static void RefreshCodeMode()
  61. {
  62. CodeMode codeMode = CodeMode.ClientServer;
  63. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  64. if (globalConfig)
  65. codeMode = globalConfig.CodeMode;
  66. switch (codeMode)
  67. {
  68. case CodeMode.Client:
  69. EnableUnityClient();
  70. break;
  71. case CodeMode.Server:
  72. EnableUnityServer();
  73. break;
  74. case CodeMode.ClientServer:
  75. EnableUnityClientServer();
  76. break;
  77. }
  78. AssetDatabase.Refresh();
  79. }
  80. /// <summary>
  81. /// 刷新构建类型
  82. /// </summary>
  83. static void RefreshBuildType()
  84. {
  85. BuildType buildType = BuildType.Release;
  86. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  87. if (globalConfig)
  88. buildType = globalConfig.BuildType;
  89. EditorUserBuildSettings.development = buildType == BuildType.Debug;
  90. }
  91. /// <summary>
  92. /// 编译成dll
  93. /// </summary>
  94. static bool CompileDlls()
  95. {
  96. // 运行时编译需要先设置为UnitySynchronizationContext, 编译完再还原为CurrentContext
  97. SynchronizationContext lastSynchronizationContext = Application.isPlaying ? SynchronizationContext.Current : null;
  98. SynchronizationContext.SetSynchronizationContext(unitySynchronizationContext);
  99. bool isCompileOk = false;
  100. try
  101. {
  102. Directory.CreateDirectory(Define.BuildOutputDir);
  103. BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
  104. BuildTargetGroup group = BuildPipeline.GetBuildTargetGroup(target);
  105. ScriptCompilationSettings scriptCompilationSettings = new()
  106. {
  107. group = group,
  108. target = target,
  109. extraScriptingDefines = new[] { "UNITY_COMPILE" },
  110. options = EditorUserBuildSettings.development ? ScriptCompilationOptions.DevelopmentBuild : ScriptCompilationOptions.None
  111. };
  112. ScriptCompilationResult result = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, Define.BuildOutputDir);
  113. isCompileOk = result.assemblies.Count > 0;
  114. EditorUtility.ClearProgressBar();
  115. }
  116. finally
  117. {
  118. if (lastSynchronizationContext != null)
  119. SynchronizationContext.SetSynchronizationContext(lastSynchronizationContext);
  120. }
  121. return isCompileOk;
  122. }
  123. /// <summary>
  124. /// 将dll文件复制到加载目录
  125. /// </summary>
  126. static void CopyHotUpdateDlls()
  127. {
  128. FileHelper.CleanDirectory(Define.CodeDir);
  129. foreach (string dllName in DllNames)
  130. {
  131. string sourceDll = $"{Define.BuildOutputDir}/{dllName}.dll";
  132. string sourcePdb = $"{Define.BuildOutputDir}/{dllName}.pdb";
  133. File.Copy(sourceDll, $"{Define.CodeDir}/{dllName}.dll.bytes", true);
  134. File.Copy(sourcePdb, $"{Define.CodeDir}/{dllName}.pdb.bytes", true);
  135. }
  136. AssetDatabase.Refresh();
  137. }
  138. /// <summary>
  139. /// 启用纯客户端模式
  140. /// </summary>
  141. static void EnableUnityClient()
  142. {
  143. DisableAsmdef("Assets/Scripts/Model/Generate/Client/Ignore.asmdef");
  144. EnableAsmdef("Assets/Scripts/Model/Generate/Server/Ignore.asmdef");
  145. EnableAsmdef("Assets/Scripts/Model/Generate/ClientServer/Ignore.asmdef");
  146. DisableAsmdef("Assets/Scripts/Model/Client/Ignore.asmdef");
  147. EnableAsmdef("Assets/Scripts/Model/Server/Ignore.asmdef");
  148. DisableAsmdef("Assets/Scripts/Hotfix/Client/Ignore.asmdef");
  149. EnableAsmdef("Assets/Scripts/Hotfix/Server/Ignore.asmdef");
  150. DisableAsmdef("Assets/Scripts/ModelView/Client/Ignore.asmdef");
  151. DisableAsmdef("Assets/Scripts/HotfixView/Client/Ignore.asmdef");
  152. }
  153. /// <summary>
  154. /// 启用纯服务端模式
  155. /// </summary>
  156. static void EnableUnityServer()
  157. {
  158. EnableAsmdef("Assets/Scripts/Model/Generate/Client/Ignore.asmdef");
  159. EnableAsmdef("Assets/Scripts/Model/Generate/Server/Ignore.asmdef");
  160. DisableAsmdef("Assets/Scripts/Model/Generate/ClientServer/Ignore.asmdef");
  161. DisableAsmdef("Assets/Scripts/Model/Client/Ignore.asmdef");
  162. DisableAsmdef("Assets/Scripts/Model/Server/Ignore.asmdef");
  163. DisableAsmdef("Assets/Scripts/Hotfix/Client/Ignore.asmdef");
  164. DisableAsmdef("Assets/Scripts/Hotfix/Server/Ignore.asmdef");
  165. EnableAsmdef("Assets/Scripts/HotfixView/Client/Ignore.asmdef");
  166. EnableAsmdef("Assets/Scripts/ModelView/Client/Ignore.asmdef");
  167. }
  168. /// <summary>
  169. /// 启用双端模式
  170. /// </summary>
  171. static void EnableUnityClientServer()
  172. {
  173. EnableAsmdef("Assets/Scripts/Model/Generate/Client/Ignore.asmdef");
  174. EnableAsmdef("Assets/Scripts/Model/Generate/Server/Ignore.asmdef");
  175. DisableAsmdef("Assets/Scripts/Model/Generate/ClientServer/Ignore.asmdef");
  176. DisableAsmdef("Assets/Scripts/Model/Client/Ignore.asmdef");
  177. DisableAsmdef("Assets/Scripts/Model/Server/Ignore.asmdef");
  178. DisableAsmdef("Assets/Scripts/Hotfix/Client/Ignore.asmdef");
  179. DisableAsmdef("Assets/Scripts/Hotfix/Server/Ignore.asmdef");
  180. DisableAsmdef("Assets/Scripts/HotfixView/Client/Ignore.asmdef");
  181. DisableAsmdef("Assets/Scripts/ModelView/Client/Ignore.asmdef");
  182. }
  183. /// <summary>
  184. /// 启用指定的程序集定义文件
  185. /// </summary>
  186. static void EnableAsmdef(string asmdefFile)
  187. {
  188. string asmdefDisableFile = $"{asmdefFile}.DISABLED";
  189. string srcFilePath = asmdefDisableFile.Replace("Assets/Scripts/", "Assets/Settings/IgnoreAsmdef/");
  190. if (!File.Exists(srcFilePath))
  191. {
  192. Debug.LogError($"忽略编译配置的原文件不存在, 请检查项目文件完整性:{srcFilePath}");
  193. return;
  194. }
  195. if (File.Exists(asmdefFile) && new FileInfo(srcFilePath).LastWriteTime == new FileInfo(asmdefFile).LastWriteTime)
  196. return;
  197. File.Copy(srcFilePath, asmdefFile, true);
  198. }
  199. /// <summary>
  200. /// 删除指定的程序集定义文件
  201. /// </summary>
  202. static void DisableAsmdef(string asmdefFile)
  203. {
  204. File.Delete(asmdefFile);
  205. File.Delete($"{asmdefFile}.meta");
  206. }
  207. }
  208. }