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

247 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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