259 lines
10 KiB
C#
259 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using Cysharp.Threading.Tasks;
|
||
using HybridCLR;
|
||
using UnityEngine;
|
||
using YooAsset;
|
||
|
||
namespace Stary.Evo
|
||
{
|
||
public class HotFixState : AbstractFSMIStateAsync
|
||
{
|
||
public string[] PatchedAOTAssemblyList = new string[]
|
||
{
|
||
"System.Core.dll",
|
||
"UnityEngine.CoreModule.dll",
|
||
"mscorlib.dll",
|
||
"DOTween.dll",
|
||
"InformationSave.RunTime.dll",
|
||
"UIFarme.RunTime.dll",
|
||
"UniTask.dll",
|
||
"YooAsset.dll",
|
||
"com.stary.evo.runtime.dll"
|
||
|
||
};
|
||
public HotFixState(IFsmSystemAsync system) : base(system)
|
||
{
|
||
}
|
||
|
||
public override async UniTask OnEnterAsync<T>(T param)
|
||
{
|
||
DomainConfig domainConfig = param as DomainConfig;
|
||
Debug.Log("UnityEvo:热更脚本...");
|
||
var package = YooAssets.GetPackage(AppConfig.PackageDomainName);
|
||
// Editor环境下,HotUpdate.dll.bytes已经被自动加载,不需要加载,重复加载反而会出问题。
|
||
|
||
|
||
// 添加类型存在性检查
|
||
string fullClassName = $"{domainConfig.@namespace}.{domainConfig.className}";
|
||
|
||
#if EDITOR_SIMULATEMODE
|
||
// Editor下无需加载,直接查找获得HotUpdate程序集
|
||
Assembly hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies()
|
||
.First(a => a.GetName().Name == $"HotUpdate_{AppConfig.PackageDomainName}");
|
||
#else
|
||
string hotUpdateAssemblyName = $"HotUpdate_{AppConfig.PackageDomainName}";
|
||
|
||
|
||
Type assemblyType = IsAssetLoaded(fullClassName);
|
||
if (assemblyType!=null)
|
||
{
|
||
Debug.Log($"UnityEvo:热更程序集:{hotUpdateAssemblyName} 已经加载过了");
|
||
FsmSystem.SetCurState(nameof(LoadResState), domainConfig, assemblyType);
|
||
return;
|
||
}
|
||
|
||
|
||
//判断DLL是否下载成功
|
||
foreach (var aot in PatchedAOTAssemblyList)
|
||
{
|
||
var aotName = $"Android_{aot}";
|
||
var handle = package.LoadAssetAsync<TextAsset>(aotName);
|
||
await handle;
|
||
if (handle.Status == EOperationStatus.Succeed)
|
||
{
|
||
var assetObj = handle.AssetObject as TextAsset;
|
||
_sAssetDatas.Add(assetObj);
|
||
Debug.Log($"UnityEvo:dll:{aotName} ,下载成功");
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"UnityEvo:dll:{aotName} ,下载失败");
|
||
}
|
||
}
|
||
|
||
//先补元数据
|
||
LoadMetadataForAOTAssemblies();
|
||
|
||
// 加载热更dll
|
||
var hotfixDll = package.LoadAssetAsync<TextAsset>($"Android_HotUpdate_{AppConfig.PackageDomainName}.dll");
|
||
await hotfixDll;
|
||
var hotfixPdb = package.LoadAssetAsync<TextAsset>($"Android_HotUpdate_{AppConfig.PackageDomainName}.pdb");
|
||
await hotfixPdb;
|
||
Assembly hotUpdateAss = null;
|
||
if (hotfixDll.Status == EOperationStatus.Succeed)
|
||
{
|
||
var hotfixDllAsset = hotfixDll.AssetObject as TextAsset;
|
||
if (hotfixPdb.Status == EOperationStatus.Succeed)
|
||
{
|
||
Debug.Log($"UnityEvo:dll:加载成功!!");
|
||
var hotfixPdbAsset = hotfixPdb.AssetObject as TextAsset;
|
||
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes, hotfixPdbAsset.bytes);
|
||
Debug.Log($"UnityEvo:dll: Assembly.Load加载成功!!");
|
||
}
|
||
else
|
||
{
|
||
if (hotfixDllAsset != null)
|
||
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError($"UnityEvo:Android_HotUpdate_{AppConfig.PackageDomainName}.dll加载失败!!!!!");
|
||
}
|
||
|
||
|
||
#endif
|
||
Debug.Log($"UnityEvo:dll: Assembly.Load加载后是否为空:{hotUpdateAss == null}");
|
||
if (hotUpdateAss != null)
|
||
{
|
||
|
||
Type type = hotUpdateAss.GetType(fullClassName);
|
||
|
||
if (type == null)
|
||
{
|
||
Debug.LogError($"UnityEvo:热更类不存在!程序集: {hotUpdateAss.FullName}\n" +
|
||
$"期望类名: {fullClassName}\n" +
|
||
$"可用类型列表:{string.Join("\n", hotUpdateAss.GetTypes().Select(t => t.FullName))}");
|
||
return;
|
||
}
|
||
|
||
// 添加方法存在性检查
|
||
Debug.Log($"UnityEvo:dll:开始MethodInfo检查!!");
|
||
MethodInfo onEnterMethod = type.GetMethod("OnEnter");
|
||
MethodInfo onEnterAsyncMethod = type.GetMethod("OnEnterAsync");
|
||
if (onEnterMethod == null || onEnterAsyncMethod == null)
|
||
{
|
||
Debug.LogError($"UnityEvo:热更类进入方法缺失!\n" +
|
||
$"存在方法:{string.Join(", ", type.GetMethods().Select(m => m.Name))}");
|
||
return;
|
||
}
|
||
Debug.Log($"UnityEvo:dll:OnEnter检查成功!!");
|
||
MethodInfo onExitMethod = type.GetMethod("OnExit");
|
||
MethodInfo onExitAsyncMethod = type.GetMethod("OnExitAsync");
|
||
if (onExitMethod == null || onExitAsyncMethod == null)
|
||
{
|
||
Debug.LogError($"UnityEvo:热更类退出方法缺失!\n" +
|
||
$"存在方法:{string.Join(", ", type.GetMethods().Select(m => m.Name))}");
|
||
return;
|
||
}
|
||
Debug.Log($"UnityEvo:dll:OnExit检查成功!!");
|
||
// AppConfig.SetDefaultHotfixType(type);
|
||
FsmSystem.SetCurState(nameof(LoadResState), domainConfig, type);
|
||
// // 创建热更类实例
|
||
// DomainBase hotfixInstance = AppConfig.HOTFIXBASE.AddComponent(type) as DomainBase;
|
||
//
|
||
// if (hotfixInstance == null)
|
||
// {
|
||
// Debug.LogError($"热更类{fullClassName}实例创建失败!必须继承MonoBehaviour");
|
||
// return;
|
||
// }
|
||
//
|
||
//
|
||
// // 原有调用逻辑修改为使用实例
|
||
// onEnterMethod.Invoke(hotfixInstance, new object[] { "" }); // 第一个参数改为实例对象
|
||
// onEnterAsyncMethod.Invoke(hotfixInstance, new object[] { "" });
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError($"UnityEvo:热更类不存在!程序集: hotUpdateAss 不存在\n" +
|
||
$"期望类名: {fullClassName}\n" +
|
||
$"可用类型列表:{string.Join("\n", hotUpdateAss.GetTypes().Select(t => t.FullName))}");
|
||
}
|
||
}
|
||
|
||
public override UniTask OnEnterAsync()
|
||
{
|
||
return UniTask.CompletedTask;
|
||
}
|
||
|
||
public override UniTask OnEnterAsync<T1, T2>(T1 param1, T2 param2)
|
||
{
|
||
return UniTask.CompletedTask;
|
||
}
|
||
|
||
#region 补充元数据
|
||
|
||
// //补充元数据dll的列表
|
||
// //通过RuntimeApi.LoadMetadataForAOTAssembly()函数来补充AOT泛型的原始元数据
|
||
// private List<string> AOTMetaAssemblyFiles { get; } =new()
|
||
// {
|
||
// "Android_mscorlib.dll", "Android_System.dll", "Android_System.Core.dll",
|
||
// };
|
||
|
||
private readonly List<TextAsset> _sAssetDatas = new List<TextAsset>();
|
||
|
||
|
||
// public byte[] ReadBytesFromStreamingAssets(string dllName)
|
||
// {
|
||
// if (_sAssetDatas.ContainsKey(dllName))
|
||
// {
|
||
// return _sAssetDatas[dllName].bytes;
|
||
// }
|
||
//
|
||
// return Array.Empty<byte>();
|
||
// }
|
||
|
||
|
||
/// <summary>
|
||
/// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
|
||
/// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
|
||
/// </summary>
|
||
private void LoadMetadataForAOTAssemblies()
|
||
{
|
||
HomologousImageMode mode = HomologousImageMode.SuperSet;
|
||
// foreach (var aotDllName in AOTGenericReferences.PatchedAOTAssemblyList)
|
||
foreach (var aotDll in _sAssetDatas)
|
||
{
|
||
// var aotName = $"Android_{aotDllName}";
|
||
//
|
||
// byte[] dllBytes = ReadBytesFromStreamingAssets(aotName);
|
||
if (aotDll != null)
|
||
{
|
||
byte[] dllBytes = aotDll.bytes;
|
||
// 添加元数据加载校验
|
||
if (dllBytes == null || dllBytes.Length == 0)
|
||
{
|
||
Debug.LogError($"AOT元数据加载失败:{aotDll.name}");
|
||
continue;
|
||
}
|
||
|
||
LoadImageErrorCode err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
|
||
|
||
Debug.Log($"UnityEvo:【补元】{aotDll.name} 加载结果: {err} 字节数: {dllBytes.Length}");
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
private Type IsAssetLoaded(string assemblyName)
|
||
{
|
||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||
foreach (var assembly in assemblies)
|
||
{
|
||
Type assemblyType = assembly.GetType(assemblyName);
|
||
if (assemblyType!=null)
|
||
{
|
||
|
||
Debug.Log("type:" + assemblyType);
|
||
return assemblyType;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public override void OnUpdate()
|
||
{
|
||
base.OnUpdate();
|
||
}
|
||
|
||
public override UniTask OnExitAsync()
|
||
{
|
||
_sAssetDatas.Clear();
|
||
return UniTask.CompletedTask;
|
||
}
|
||
}
|
||
} |