CodeLoader.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using Cysharp.Threading.Tasks;
  2. using HybridCLR;
  3. using Sirenix.Utilities;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Drawing;
  8. using System.IO;
  9. using System.Reflection;
  10. using UnityEngine;
  11. using YooAsset;
  12. namespace ET
  13. {
  14. public class CodeLoader: Singleton<CodeLoader>
  15. {
  16. public void Start()
  17. {
  18. AsyncLoadResAndCode().Forget();
  19. }
  20. private async UniTaskVoid AsyncLoadResAndCode()
  21. {
  22. YooAssets.EPlayMode playMode;
  23. if (Define.EnableCodes)
  24. {
  25. playMode = YooAssets.EPlayMode.EditorSimulateMode;
  26. }
  27. else
  28. {
  29. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  30. playMode = globalConfig.PlayMode;
  31. }
  32. Log.Info($"start mode: {playMode}");
  33. // 启动YooAsset引擎
  34. await YooAssetProxy.StartYooAssetEngine(playMode);
  35. // Shader Warm Up
  36. ShaderVariantCollection shaderVariantCollection =
  37. (await YooAssetProxy.LoadAssetAsync<ShaderVariantCollection>(
  38. YooAssetProxy.GetYooAssetFormatResPath("ProjectSShaderVariant",
  39. YooAssetProxy.YooAssetResType.Shader)))
  40. .GetAssetObject<ShaderVariantCollection>();
  41. Stopwatch stopwatch = Stopwatch.StartNew();
  42. shaderVariantCollection.WarmUp();
  43. stopwatch.Stop();
  44. Log.Info($"Shader Warm Up完成, 耗时: {stopwatch.ElapsedMilliseconds}ms,shaderCount: {shaderVariantCollection.shaderCount} variantCount: {shaderVariantCollection.variantCount}");
  45. //加载代码入口
  46. if (Define.EnableCodes)
  47. {
  48. LoadLocalCode();
  49. }
  50. else
  51. {
  52. await LoadMetadataForAOT();
  53. await LoadHotfixCode();
  54. }
  55. }
  56. // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
  57. private async UniTask LoadMetadataForAOT()
  58. {
  59. //AOT dll列表的配置也可以通过热更新下下来,这样增加了新的泛型就不怕了
  60. ConfigStringList hotUpdateAOTDlls =
  61. (await YooAssetProxy.LoadAssetAsync<ConfigStringList>("HotUpdateAOTDlls"))
  62. .GetAssetObject<ConfigStringList>();
  63. List<UniTask<RawFileOperation>> tasks = new List<UniTask<RawFileOperation>>();
  64. foreach (var aotDll in hotUpdateAOTDlls.List)
  65. {
  66. tasks.Add(YooAssetProxy.GetRawFileAsync(aotDll));
  67. }
  68. RawFileOperation[] rawFileOperations = await UniTask.WhenAll(tasks);
  69. foreach (var task in rawFileOperations)
  70. {
  71. var ret = RuntimeApi.LoadMetadataForAOTAssembly(task.GetRawBytes(), HomologousImageMode.SuperSet);
  72. if (ret != LoadImageErrorCode.OK)
  73. {
  74. Log.Error($"Error occurs when loadMetadataForAOT: {ret}");
  75. }
  76. }
  77. }
  78. //热更加载 model.dll & hotfix.dll
  79. private async UniTask LoadHotfixCode()
  80. {
  81. Dictionary<string, Type> typesInAssembly = new Dictionary<string, Type>();
  82. Assembly modelAss = null;
  83. #if ! UNITY_EDITOR
  84. var battleDlls = (await YooAssetProxy.LoadAssetAsync<ConfigStringList>("HotupdateBattleDlls")).GetAssetObject<ConfigStringList>();
  85. foreach (var dll in battleDlls.List)
  86. {
  87. Log.Info($"to load: {dll}");
  88. Assembly.Load((await YooAssetProxy.GetRawFileAsync(dll)).GetRawBytes());
  89. }
  90. #endif
  91. var hotDlls = (await YooAssetProxy.LoadAssetAsync<ConfigKeyValueMap>("HotupdateDlls")).GetAssetObject<ConfigKeyValueMap>();
  92. foreach(var kv in hotDlls.keyValueMaps)
  93. {
  94. Assembly ass;
  95. if(kv.Value.IsNullOrWhitespace())
  96. {
  97. Log.Info($"to load: {kv.Key}");
  98. ass = Assembly.Load((await YooAssetProxy.GetRawFileAsync(kv.Key)).GetRawBytes());
  99. }
  100. else
  101. {
  102. Log.Info($"to load: {kv.Key}");
  103. ass = Assembly.Load((await YooAssetProxy.GetRawFileAsync(kv.Key)).GetRawBytes(),
  104. (await YooAssetProxy.GetRawFileAsync(kv.Value)).GetRawBytes());
  105. }
  106. foreach (Type type in ass.GetTypes())
  107. {
  108. typesInAssembly[type.FullName] = type;
  109. }
  110. if(kv.Key.Equals("Model.dll"))
  111. {
  112. modelAss = ass;
  113. }
  114. }
  115. EventSystem.Instance.Add(typesInAssembly);
  116. if(modelAss == null)
  117. {
  118. Log.Error("Not Found 'Model.dll'! ");
  119. return;
  120. }
  121. Log.Info("to call Client.Entry.");
  122. IStaticMethod start = new MonoStaticMethod(modelAss, "ET.Entry", "Start");
  123. start.Run();
  124. }
  125. //不使用dll,打开了EnableCode,使用Editor编辑模式
  126. private void LoadLocalCode()
  127. {
  128. //GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  129. //if (globalConfig.CodeMode != CodeMode.ClientServer)
  130. //{
  131. // throw new Exception("ENABLE_CODES mode must use ClientServer code mode!");
  132. //}
  133. Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
  134. Dictionary<string, Type> types = AssemblyHelper.GetAssemblyTypes(assemblies);
  135. EventSystem.Instance.Add(types);
  136. bool bStart = false;
  137. foreach (Assembly ass in assemblies)
  138. {
  139. string name = ass.GetName().Name;
  140. if (name == "Unity.Model.Codes")
  141. {
  142. bStart = true;
  143. IStaticMethod start = new StaticMethod(ass, "ET.Entry", "Start");
  144. start.Run();
  145. break;
  146. }
  147. }
  148. if (!bStart)
  149. {
  150. throw new Exception("not found Assembly: 'Unity.Model.Codes'");
  151. }
  152. }
  153. //编译时会检查这个方法,需保留
  154. public void LoadHotfix()
  155. {
  156. //防裁剪
  157. var xx = ImageConversion.EnableLegacyPngGammaRuntimeLoadBehavior;
  158. Image x = Image.FromFile("");
  159. }
  160. }
  161. }