AssemblyTool.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 = { "ET.Hotfix", "ET.HotfixView", "ET.Model", "ET.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. {
  41. CodeLoader.Instance.Reload();
  42. }
  43. }
  44. /// <summary>
  45. /// 执行编译代码流程
  46. /// </summary>
  47. public static void DoCompile()
  48. {
  49. // 强制刷新一下,防止关闭auto refresh,编译出老代码
  50. AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
  51. RefreshCodeMode();
  52. RefreshBuildType();
  53. bool isCompileOk = CompileDlls();
  54. if (!isCompileOk)
  55. {
  56. return;
  57. }
  58. CopyHotUpdateDlls();
  59. BuildHelper.ReGenerateProjectFiles();
  60. Log.Info($"Compile Finish!");
  61. }
  62. /// <summary>
  63. /// 刷新代码模式
  64. /// </summary>
  65. static void RefreshCodeMode()
  66. {
  67. CodeMode codeMode = CodeMode.ClientServer;
  68. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  69. if (globalConfig)
  70. {
  71. codeMode = globalConfig.CodeMode;
  72. }
  73. switch (codeMode)
  74. {
  75. case CodeMode.Client:
  76. {
  77. EnableUnityClient();
  78. break;
  79. }
  80. case CodeMode.Server:
  81. {
  82. EnableUnityServer();
  83. break;
  84. }
  85. case CodeMode.ClientServer:
  86. {
  87. EnableUnityClientServer();
  88. break;
  89. }
  90. }
  91. AssetDatabase.Refresh();
  92. }
  93. /// <summary>
  94. /// 刷新构建类型
  95. /// </summary>
  96. static void RefreshBuildType()
  97. {
  98. BuildType buildType = BuildType.Release;
  99. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  100. if (globalConfig)
  101. {
  102. buildType = globalConfig.BuildType;
  103. }
  104. EditorUserBuildSettings.development = buildType == BuildType.Debug;
  105. }
  106. /// <summary>
  107. /// 编译成dll
  108. /// </summary>
  109. static bool CompileDlls()
  110. {
  111. // 运行时编译需要先设置为UnitySynchronizationContext, 编译完再还原为CurrentContext
  112. SynchronizationContext lastSynchronizationContext = Application.isPlaying ? SynchronizationContext.Current : null;
  113. SynchronizationContext.SetSynchronizationContext(unitySynchronizationContext);
  114. bool isCompileOk = false;
  115. try
  116. {
  117. Directory.CreateDirectory(Define.BuildOutputDir);
  118. BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
  119. BuildTargetGroup group = BuildPipeline.GetBuildTargetGroup(target);
  120. ScriptCompilationSettings scriptCompilationSettings = new()
  121. {
  122. group = group,
  123. target = target,
  124. extraScriptingDefines = new[] { "UNITY_COMPILE" },
  125. options = EditorUserBuildSettings.development ? ScriptCompilationOptions.DevelopmentBuild : ScriptCompilationOptions.None
  126. };
  127. ScriptCompilationResult result = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, Define.BuildOutputDir);
  128. isCompileOk = result.assemblies.Count > 0;
  129. EditorUtility.ClearProgressBar();
  130. }
  131. finally
  132. {
  133. if (lastSynchronizationContext != null)
  134. {
  135. SynchronizationContext.SetSynchronizationContext(lastSynchronizationContext);
  136. }
  137. }
  138. return isCompileOk;
  139. }
  140. /// <summary>
  141. /// 将dll文件复制到加载目录
  142. /// </summary>
  143. static void CopyHotUpdateDlls()
  144. {
  145. FileHelper.CleanDirectory(Define.CodeDir);
  146. foreach (string dllName in DllNames)
  147. {
  148. string sourceDll = $"{Define.BuildOutputDir}/{dllName}.dll";
  149. string sourcePdb = $"{Define.BuildOutputDir}/{dllName}.pdb";
  150. File.Copy(sourceDll, $"{Define.CodeDir}/{dllName}.dll.bytes", true);
  151. File.Copy(sourcePdb, $"{Define.CodeDir}/{dllName}.pdb.bytes", true);
  152. }
  153. AssetDatabase.Refresh();
  154. }
  155. /// <summary>
  156. /// 启用纯客户端模式
  157. /// </summary>
  158. static void EnableUnityClient()
  159. {
  160. DisableAsmdef("Assets/Scripts/Model/Generate/Client/Ignore.asmdef");
  161. EnableAsmdef("Assets/Scripts/Model/Generate/Server/Ignore.asmdef");
  162. EnableAsmdef("Assets/Scripts/Model/Generate/ClientServer/Ignore.asmdef");
  163. DisableAsmdef("Assets/Scripts/Model/Client/Ignore.asmdef");
  164. EnableAsmdef("Assets/Scripts/Model/Server/Ignore.asmdef");
  165. DisableAsmdef("Assets/Scripts/Hotfix/Client/Ignore.asmdef");
  166. EnableAsmdef("Assets/Scripts/Hotfix/Server/Ignore.asmdef");
  167. DisableAsmdef("Assets/Scripts/ModelView/Client/Ignore.asmdef");
  168. DisableAsmdef("Assets/Scripts/HotfixView/Client/Ignore.asmdef");
  169. }
  170. /// <summary>
  171. /// 启用纯服务端模式
  172. /// </summary>
  173. static void EnableUnityServer()
  174. {
  175. EnableAsmdef("Assets/Scripts/Model/Generate/Client/Ignore.asmdef");
  176. EnableAsmdef("Assets/Scripts/Model/Generate/Server/Ignore.asmdef");
  177. DisableAsmdef("Assets/Scripts/Model/Generate/ClientServer/Ignore.asmdef");
  178. DisableAsmdef("Assets/Scripts/Model/Client/Ignore.asmdef");
  179. DisableAsmdef("Assets/Scripts/Model/Server/Ignore.asmdef");
  180. DisableAsmdef("Assets/Scripts/Hotfix/Client/Ignore.asmdef");
  181. DisableAsmdef("Assets/Scripts/Hotfix/Server/Ignore.asmdef");
  182. EnableAsmdef("Assets/Scripts/HotfixView/Client/Ignore.asmdef");
  183. EnableAsmdef("Assets/Scripts/ModelView/Client/Ignore.asmdef");
  184. }
  185. /// <summary>
  186. /// 启用双端模式
  187. /// </summary>
  188. static void EnableUnityClientServer()
  189. {
  190. EnableAsmdef("Assets/Scripts/Model/Generate/Client/Ignore.asmdef");
  191. EnableAsmdef("Assets/Scripts/Model/Generate/Server/Ignore.asmdef");
  192. DisableAsmdef("Assets/Scripts/Model/Generate/ClientServer/Ignore.asmdef");
  193. DisableAsmdef("Assets/Scripts/Model/Client/Ignore.asmdef");
  194. DisableAsmdef("Assets/Scripts/Model/Server/Ignore.asmdef");
  195. DisableAsmdef("Assets/Scripts/Hotfix/Client/Ignore.asmdef");
  196. DisableAsmdef("Assets/Scripts/Hotfix/Server/Ignore.asmdef");
  197. DisableAsmdef("Assets/Scripts/HotfixView/Client/Ignore.asmdef");
  198. DisableAsmdef("Assets/Scripts/ModelView/Client/Ignore.asmdef");
  199. }
  200. /// <summary>
  201. /// 启用指定的程序集定义文件
  202. /// </summary>
  203. static void EnableAsmdef(string asmdefFile)
  204. {
  205. string asmdefDisableFile = $"{asmdefFile}.DISABLED";
  206. string srcFilePath = asmdefDisableFile.Replace("Assets/Scripts/", "Assets/Settings/IgnoreAsmdef/");
  207. if (!File.Exists(srcFilePath))
  208. {
  209. Debug.LogError($"忽略编译配置的原文件不存在, 请检查项目文件完整性:{srcFilePath}");
  210. return;
  211. }
  212. if (File.Exists(asmdefFile) && new FileInfo(srcFilePath).LastWriteTime == new FileInfo(asmdefFile).LastWriteTime)
  213. {
  214. return;
  215. }
  216. File.Copy(srcFilePath, asmdefFile, true);
  217. }
  218. /// <summary>
  219. /// 删除指定的程序集定义文件
  220. /// </summary>
  221. static void DisableAsmdef(string asmdefFile)
  222. {
  223. File.Delete(asmdefFile);
  224. File.Delete($"{asmdefFile}.meta");
  225. }
  226. }
  227. }