Forest_Client/Forest/Assets/PhxhSDK/AOT/HybridCLR/HybridCLRHelper.cs

247 lines
8.7 KiB
C#
Raw Normal View History

2024-06-12 15:01:54 +08:00
#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<string, Assembly> _allHotUpdateAssemblies = new();
private readonly List<string> _phxhDependencyDlls = new List<string>()
{
};
private readonly List<string> _frameWorkDependencyDlls = new List<string>()
{
//不要随意改顺序!
};
private readonly List<string> _gamePlayDependencyDlls = new List<string>()
{
//不要随意改顺序!
"BehaviorDesigner.Runtime.dll",
//"BestHTTP.dll",
"DOTweenCSharp.dll",
};
//所有使用了RuntimeInitializeOnLoadMethod attribute的程序集
private readonly List<string> _hasRuntimeInitializeOnLoadMethodAssemblies = new List<string>()
{
"BehaviorDesigner.Runtime",
//"BestHTTP",
"GamePlay",
};
private List<string> _aotAssemblyList = new List<string>();
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();
}
/// <summary>
/// Addressable初始化时热更新代码所对应的ScriptableObject的类型会被识别为System.Object需要在热更新dll加载完后重新加载一下Addressable的Catalog
/// https://hybridclr.doc.code-philosophy.com/docs/help/commonerrors
/// </summary>
/// <returns></returns>
private async UniTask ReloadAddressableCatalog()
{
#if !USE_YOO
await SimpleLoader_Addressables.ReloadAddressableCatalog();
#endif
await UniTask.NextFrame();
}
private void _TryHandleMethod(MethodInfo method, List<MethodExecutionInfo> 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<MethodExecutionInfo> 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<Assembly> 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<string> dllList)
{
_aotAssemblyList.AddRange(dllList);
}
}
}
#endif