247 lines
8.7 KiB
C#
247 lines
8.7 KiB
C#
#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 |