#if USE_HCLR using System.Collections.Generic; using System.Linq; using System.Reflection; using Cysharp.Threading.Tasks; using HybridCLR; using PhxhSDK.AOT.SimpleLoader; using UnityEngine; namespace PhxhSDK.AOT { public class HybridCLRHelper { const string META_DATA_DLL_PATH = "Assets/HotUpdateDlls/MetaDataDll/"; const string HOT_UPDATE_DLL_PATH = "Assets/HotUpdateDlls/HotUpdateDll/"; const string PHXH_DLL_NAME = "Phxh.dll"; const string FRAMEWORK_DLL_NAME = "FrameWork.dll"; const string GAMEPLAY_DLL_NAME = "GamePlay.dll"; private byte[] _dllBytes; private Dictionary _allHotUpdateAssemblies = new(); private readonly List _phxhDependencyDlls = new List() { }; private readonly List _frameWorkDependencyDlls = new List() { //不要随意改顺序! }; private readonly List _gamePlayDependencyDlls = new List() { //不要随意改顺序! "BehaviorDesigner.Runtime.dll", //"BestHTTP.dll", "DOTweenCSharp.dll", }; //所有使用了RuntimeInitializeOnLoadMethod attribute的程序集 private readonly List _hasRuntimeInitializeOnLoadMethodAssemblies = new List() { "BehaviorDesigner.Runtime", //"BestHTTP", "GamePlay", }; private List _aotAssemblyList = new List(); private ISimpleLoader _loader; public async UniTask LoadAssemblies() { await LoadPhxhDependencyAssemblies(); await LoadPhxhAssembies(); await LoadFrameworkDependencyAssemblies(); await LoadFrameWorkAssemblies(); await LoadMetadataForAOTAssemblies(); await LoadGamePlayDependencyAssemblies(); await LoadGamePlayAssemblies(); await ReloadAddressableCatalog(); _ExecuteRuntimeInitializeOnLoadMethodAttribute(); await UniTask.NextFrame(); } /// /// Addressable初始化时热更新代码所对应的ScriptableObject的类型会被识别为System.Object,需要在热更新dll加载完后重新加载一下Addressable的Catalog /// https://hybridclr.doc.code-philosophy.com/docs/help/commonerrors /// /// private async UniTask ReloadAddressableCatalog() { #if !USE_YOO await SimpleLoader_Addressables.ReloadAddressableCatalog(); #endif await UniTask.NextFrame(); } private void _TryHandleMethod(MethodInfo method, List runtimeMethods) { if (!method.IsStatic) return; var runtimeInitializedAttribute = typeof(RuntimeInitializeOnLoadMethodAttribute); var attri = method.GetCustomAttribute(runtimeInitializedAttribute); if (attri == null) return; var sequence = (int)((RuntimeInitializeOnLoadMethodAttribute)attri).loadType; var methodInfo = new MethodExecutionInfo(method, sequence); runtimeMethods.Add(methodInfo); } private void _ExecuteRuntimeInitializeOnLoadMethodAttribute() { List runtimeMethods = new(); foreach (var assemblyName in _hasRuntimeInitializeOnLoadMethodAssemblies) { var assembly = GetAssembly(assemblyName); if (assembly == null) { Debug.LogError($"找不到使用过RuntimeInitializeOnLoadMethod的assembly,name:{assemblyName}"); continue; } foreach (var type in assembly.GetTypes()) { var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (var method in methods) { _TryHandleMethod(method, runtimeMethods); } } } runtimeMethods.Sort((a, b) => b.sequnence.CompareTo(a.sequnence)); foreach (var methodInfo in runtimeMethods) { Debug.Log($"call method methodName:{methodInfo.method.Name} sequnence:{methodInfo.sequnence}"); methodInfo.method.Invoke(null, null); } Debug.Log("调用RuntimeInitializeOnLoadMethod结束!"); } private Assembly GetAssembly(string assemblyName) { assemblyName = assemblyName.Replace(".dll", ""); IEnumerable allAssemblies = _allHotUpdateAssemblies.Values; return allAssemblies.First(assembly => assembly.FullName.Contains(assemblyName)); } private async UniTask LoadSingleHotUpdateAssembly(string dllName) { var path = $"{HOT_UPDATE_DLL_PATH}{dllName}.bytes"; await ReadDllBytes(path); if (_dllBytes != null) { var assembly = Assembly.Load(_dllBytes); _allHotUpdateAssemblies.Add(assembly.FullName, assembly); Debug.Log($"Load Assembly success,assembly Name:{assembly.FullName}"); // foreach (var type in GetAssembly(dllName).GetTypes()) // { // Debug.Log($"type:{type} in assembly:{GAMEPLAY_DLL_NAME}"); // } } await UniTask.NextFrame(); } //加载GamePlay程序集 private async UniTask LoadGamePlayAssemblies() { await LoadSingleHotUpdateAssembly(GAMEPLAY_DLL_NAME); Debug.Log("加载GamePlay程序集结束!"); } //加载GamePlay依赖的第三方程序集 private async UniTask LoadGamePlayDependencyAssemblies() { foreach (var dllName in _gamePlayDependencyDlls) { await LoadSingleHotUpdateAssembly(dllName); } Debug.Log("加载GamePlay依赖程序集结束!"); } //加载Framework程序集 private async UniTask LoadFrameWorkAssemblies() { await LoadSingleHotUpdateAssembly(FRAMEWORK_DLL_NAME); Debug.Log("加载Framework程序集结束!"); } //加载FrameWork依赖的第三方热更序集 private async UniTask LoadFrameworkDependencyAssemblies() { foreach (var dllName in _frameWorkDependencyDlls) { await LoadSingleHotUpdateAssembly(dllName); } Debug.Log("加载Framework依赖程序集结束!"); } private async UniTask LoadPhxhAssembies() { await LoadSingleHotUpdateAssembly(PHXH_DLL_NAME); Debug.Log("加载Phxh程序集结束!"); } private async UniTask LoadPhxhDependencyAssemblies() { foreach (var dllName in _phxhDependencyDlls) { await LoadSingleHotUpdateAssembly(dllName); } Debug.Log("加载Phxh依赖程序集结束!"); } //补充元数据 private async UniTask LoadMetadataForAOTAssemblies() { var aotAssemblies = _aotAssemblyList; if (aotAssemblies == null) { Debug.LogError($"LoadMetadataForAOTAssemblies failed, PatchedAOTAssemblyList is null!"); return; } foreach (var aotDllName in aotAssemblies) { var path = $"{META_DATA_DLL_PATH}{aotDllName}.bytes"; await ReadDllBytes(path); if (_dllBytes != null) { var err = RuntimeApi.LoadMetadataForAOTAssembly(_dllBytes, HomologousImageMode.SuperSet); Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. ret:{err}"); } } Debug.Log("补充元数据结束!"); } private async UniTask ReadDllBytes(string path) { _dllBytes = await _loader.LoadDllBytes(path); if (_dllBytes == null) { Debug.LogError($"cant load dll,path:{path}"); return; } await _loader.UnloadDll(path); } public void RegistLoader(ISimpleLoader loader) { _loader = loader; } public void SetDllList(IReadOnlyList dllList) { _aotAssemblyList.AddRange(dllList); } } } #endif