CodeLoader.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using Cysharp.Threading.Tasks;
  2. using HybridCLR;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Reflection;
  8. using UnityEngine;
  9. using YooAsset;
  10. namespace ET
  11. {
  12. public class CodeLoader: Singleton<CodeLoader>
  13. {
  14. public void Start()
  15. {
  16. if (Define.EnableCodes)
  17. {
  18. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  19. if (globalConfig.CodeMode != CodeMode.ClientServer)
  20. {
  21. throw new Exception("ENABLE_CODES mode must use ClientServer code mode!");
  22. }
  23. GameObject.Find("HotfixUI").SetActive(false);
  24. Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
  25. Dictionary<string, Type> types = AssemblyHelper.GetAssemblyTypes(assemblies);
  26. EventSystem.Instance.Add(types);
  27. bool bStart = false;
  28. foreach (Assembly ass in assemblies)
  29. {
  30. string name = ass.GetName().Name;
  31. if (name == "Unity.Model.Codes")
  32. {
  33. bStart = true;
  34. IStaticMethod start = new StaticMethod(ass, "ET.Entry", "Start");
  35. start.Run();
  36. break;
  37. }
  38. }
  39. if(!bStart)
  40. {
  41. throw new Exception("not found Assembly: 'Unity.Model.Codes'");
  42. }
  43. }
  44. else
  45. {
  46. LoadHotfix();
  47. }
  48. }
  49. //编译时会检查这个方法,需保留
  50. public void LoadHotfix()
  51. {
  52. AsyncLoadHotfix().Forget();
  53. }
  54. private async UniTaskVoid AsyncLoadHotfix()
  55. {
  56. GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig");
  57. Log.Info($"start mode: {globalConfig.PlayMode}");
  58. // 启动YooAsset引擎,并在初始化完毕后进行热更代码加载
  59. await YooAssetProxy.StartYooAssetEngine(globalConfig.PlayMode);
  60. // Shader Warm Up
  61. ShaderVariantCollection shaderVariantCollection =
  62. (await YooAssetProxy.LoadAssetAsync<ShaderVariantCollection>(
  63. YooAssetProxy.GetYooAssetFormatResPath("ProjectSShaderVariant",
  64. YooAssetProxy.YooAssetResType.Shader)))
  65. .GetAssetObject<ShaderVariantCollection>();
  66. Stopwatch stopwatch = Stopwatch.StartNew();
  67. shaderVariantCollection.WarmUp();
  68. stopwatch.Stop();
  69. Log.Info($"Shader Warm Up完成, 耗时: {stopwatch.ElapsedMilliseconds}ms,shaderCount: {shaderVariantCollection.shaderCount} variantCount: {shaderVariantCollection.variantCount}");
  70. //给mscorlib.dll等AOT补充元数据
  71. await LoadMetadataForAOT();
  72. await LoadHotfixCode();
  73. GameObject.Find("HotfixUI").SetActive(false);
  74. }
  75. // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
  76. private async UniTask LoadMetadataForAOT()
  77. {
  78. //AOT dll列表的配置也可以通过热更新下下来,这样增加了新的泛型就不怕了
  79. HotUpdateAssemblyManifest mainfest =
  80. (await YooAssetProxy.LoadAssetAsync<HotUpdateAssemblyManifest>("HotUpdateAssemblyManifest"))
  81. .GetAssetObject<HotUpdateAssemblyManifest>();
  82. var DLLNameList_ForABLoad = mainfest.AOTMetadataDlls;
  83. List<UniTask<RawFileOperation>> tasks = new List<UniTask<RawFileOperation>>();
  84. foreach (var aotDll in DLLNameList_ForABLoad)
  85. {
  86. tasks.Add(YooAssetProxy.GetRawFileAsync(aotDll));
  87. }
  88. RawFileOperation[] rawFileOperations = await UniTask.WhenAll(tasks);
  89. foreach (var task in rawFileOperations)
  90. {
  91. var ret = RuntimeApi.LoadMetadataForAOTAssembly(task.GetRawBytes(), HomologousImageMode.SuperSet);
  92. if (ret == LoadImageErrorCode.OK)
  93. {
  94. Log.Debug($"LoadMetadataForAOTAssembly({task.GetBundleName()}) ok.");
  95. }
  96. else
  97. {
  98. Log.Error($"LoadMetadataForAOTAssembly({task.GetBundleName()}) Error: {ret}");
  99. }
  100. }
  101. }
  102. //热更加载 model.dll & hotfix.dll
  103. private async UniTask LoadHotfixCode()
  104. {
  105. Log.Info("to load model.dll & hotfix.dll.");
  106. var rawfile_modeldll = await YooAssetProxy.GetRawFileAsync("Model.dll");
  107. var rawfile_modelpdb = await YooAssetProxy.GetRawFileAsync("Model.pdb");
  108. var modelAssembly = Assembly.Load(rawfile_modeldll.GetRawBytes(), rawfile_modelpdb.GetRawBytes());
  109. var rawfile_hotfixdll = await YooAssetProxy.GetRawFileAsync("Hotfix.dll");
  110. var rawfile_hotfixpdb = await YooAssetProxy.GetRawFileAsync("Hotfix.pdb");
  111. var hotfixAssembly = Assembly.Load(rawfile_hotfixdll.GetRawBytes(), rawfile_hotfixpdb.GetRawBytes());
  112. Dictionary<string, Type> types = AssemblyHelper.GetAssemblyTypes(typeof(Game).Assembly, typeof(Init).Assembly, modelAssembly, hotfixAssembly);
  113. EventSystem.Instance.Add(types);
  114. Log.Info("to call Client.Entry.");
  115. IStaticMethod start = new MonoStaticMethod(modelAssembly, "ET.Entry", "Start");
  116. start.Run();
  117. }
  118. }
  119. }