322 lines
13 KiB
C#
322 lines
13 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 =
|
||
{
|
||
"System.Core.dll",
|
||
"UnityEngine.CoreModule.dll",
|
||
"mscorlib.dll",
|
||
"DOTween.dll",
|
||
"com.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)
|
||
{
|
||
var domainConfig = param as DomainConfig;
|
||
Debug.Log("UnityEvo:热更脚本...");
|
||
var package = YooAssets.GetPackage(AppConfig.PackageDomainName);
|
||
// Editor环境下,HotUpdate.dll.bytes已经被自动加载,不需要加载,重复加载反而会出问题。
|
||
|
||
|
||
// 添加类型存在性检查
|
||
var 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
|
||
var hotUpdateAssemblyName = $"HotUpdate_{AppConfig.PackageDomainName}";
|
||
|
||
|
||
var 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)
|
||
{
|
||
Debug.Log("UnityEvo:hotfixDll读取成功!!");
|
||
var hotfixDllAsset = hotfixDll.AssetObject as TextAsset;
|
||
if (hotfixPdb.Status == EOperationStatus.Succeed)
|
||
{
|
||
Debug.Log("UnityEvo:hotfixPdb:读取成功!!");
|
||
var hotfixPdbAsset = hotfixPdb.AssetObject as TextAsset;
|
||
if (hotfixPdbAsset != null)
|
||
{
|
||
Debug.Log("UnityEvo:开始加载DLL和PDB...");
|
||
try
|
||
{
|
||
// 分步骤验证字节数组有效性
|
||
if (hotfixDllAsset.bytes == null || hotfixDllAsset.bytes.Length == 0)
|
||
{
|
||
Debug.LogError("UnityEvo:热更DLL字节数组为空!");
|
||
return;
|
||
}
|
||
|
||
if (hotfixPdbAsset.bytes == null || hotfixPdbAsset.bytes.Length == 0)
|
||
{
|
||
Debug.LogWarning("UnityEvo:PDB字节数组为空,尝试仅加载DLL...");
|
||
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes);
|
||
}
|
||
else
|
||
{
|
||
// 尝试加载DLL和PDB
|
||
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes, hotfixPdbAsset.bytes);
|
||
}
|
||
|
||
Debug.Log(
|
||
$"UnityEvo:Assembly加载成功,大小:DLL={hotfixDllAsset.bytes.Length} bytes, PDB={hotfixPdbAsset.bytes.Length} bytes");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"UnityEvo:Assembly加载异常: {ex}");
|
||
// 尝试仅加载DLL作为备选方案
|
||
try
|
||
{
|
||
Debug.Log("UnityEvo:尝试仅加载DLL...");
|
||
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes);
|
||
}
|
||
catch (Exception ex2)
|
||
{
|
||
Debug.LogError($"UnityEvo:仅加载DLL也失败: {ex2}");
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("UnityEvo:hotfixPdb: AssetObject为空!!");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (hotfixDllAsset != null)
|
||
try
|
||
{
|
||
Debug.Log("UnityEvo:开始加载DLL...");
|
||
// 分步骤验证字节数组有效性
|
||
if (hotfixDllAsset.bytes == null || hotfixDllAsset.bytes.Length == 0)
|
||
{
|
||
Debug.LogError("UnityEvo:热更DLL字节数组为空!");
|
||
return;
|
||
}
|
||
|
||
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes);
|
||
Debug.Log(
|
||
$"UnityEvo:Assembly加载成功,大小:DLL={hotfixDllAsset.bytes.Length} bytes");
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError($"UnityEvo:Assembly加载异常: {e}");
|
||
}
|
||
|
||
else
|
||
Debug.LogError("UnityEvo:hotfixDll: AssetObject为空!!");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError($"UnityEvo:Android_HotUpdate_{AppConfig.PackageDomainName}.dll加载失败!!!!!");
|
||
}
|
||
|
||
|
||
#endif
|
||
Debug.Log($"UnityEvo:dll: Assembly.Load加载后是否为空:{hotUpdateAss == null}");
|
||
if (hotUpdateAss != null)
|
||
{
|
||
var 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检查!!");
|
||
var onEnterMethod = type.GetMethod("OnEnter");
|
||
var 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检查成功!!");
|
||
var onExitMethod = type.GetMethod("OnExit");
|
||
var 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;
|
||
}
|
||
|
||
private Type IsAssetLoaded(string assemblyName)
|
||
{
|
||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||
foreach (var assembly in assemblies)
|
||
{
|
||
var 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;
|
||
}
|
||
|
||
#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();
|
||
|
||
|
||
// 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()
|
||
{
|
||
var 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)
|
||
{
|
||
var dllBytes = aotDll.bytes;
|
||
// 添加元数据加载校验
|
||
if (dllBytes == null || dllBytes.Length == 0)
|
||
{
|
||
Debug.LogError($"AOT元数据加载失败:{aotDll.name}");
|
||
continue;
|
||
}
|
||
|
||
var err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
|
||
|
||
Debug.Log($"UnityEvo:【补元】{aotDll.name} 加载结果: {err} 字节数: {dllBytes.Length}");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |