Files
plugin-library/Assets/00.StaryEvoTools/Runtime/HybridLoad/Fsm/HotFixState.cs

321 lines
13 KiB
C#
Raw Normal View History

2025-05-23 18:26:47 +08:00
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
{
2025-09-02 14:15:18 +08:00
public class HotFixState : AbstractFSMIStateAsync
2025-05-23 18:26:47 +08:00
{
2025-09-04 11:43:35 +08:00
public string[] PatchedAOTAssemblyList =
2025-05-23 18:26:47 +08:00
{
"System.Core.dll",
"UnityEngine.CoreModule.dll",
"mscorlib.dll",
2025-09-10 12:21:42 +08:00
"com.audiocore.runtime",
2025-05-23 18:26:47 +08:00
"UniTask.dll",
"YooAsset.dll",
"com.stary.evo.runtime.dll"
};
2025-09-04 11:43:35 +08:00
2025-09-02 14:15:18 +08:00
public HotFixState(IFsmSystemAsync system) : base(system)
2025-05-23 18:26:47 +08:00
{
}
public override async UniTask OnEnterAsync<T>(T param)
{
2025-09-04 11:43:35 +08:00
var domainConfig = param as DomainConfig;
2025-05-23 18:26:47 +08:00
Debug.Log("UnityEvo:热更脚本...");
2025-05-30 14:50:46 +08:00
var package = YooAssets.GetPackage(AppConfig.PackageDomainName);
2025-05-23 18:26:47 +08:00
// Editor环境下HotUpdate.dll.bytes已经被自动加载不需要加载重复加载反而会出问题。
2025-09-04 11:43:35 +08:00
2025-05-23 18:26:47 +08:00
// 添加类型存在性检查
2025-09-04 11:43:35 +08:00
var fullClassName = $"{domainConfig.@namespace}.{domainConfig.className}";
2025-05-23 18:26:47 +08:00
#if EDITOR_SIMULATEMODE
// Editor下无需加载直接查找获得HotUpdate程序集
Assembly hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies()
2025-07-02 10:05:26 +08:00
.First(a => a.GetName().Name == $"HotUpdate_{AppConfig.PackageDomainName}");
2025-05-23 18:26:47 +08:00
#else
2025-09-04 11:43:35 +08:00
var hotUpdateAssemblyName = $"HotUpdate_{AppConfig.PackageDomainName}";
2025-05-23 18:26:47 +08:00
2025-09-04 11:43:35 +08:00
var assemblyType = IsAssetLoaded(fullClassName);
if (assemblyType != null)
2025-05-23 18:26:47 +08:00
{
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
2025-05-30 14:50:46 +08:00
var hotfixDll = package.LoadAssetAsync<TextAsset>($"Android_HotUpdate_{AppConfig.PackageDomainName}.dll");
2025-05-23 18:26:47 +08:00
await hotfixDll;
2025-05-30 14:50:46 +08:00
var hotfixPdb = package.LoadAssetAsync<TextAsset>($"Android_HotUpdate_{AppConfig.PackageDomainName}.pdb");
2025-05-23 18:26:47 +08:00
await hotfixPdb;
Assembly hotUpdateAss = null;
if (hotfixDll.Status == EOperationStatus.Succeed)
{
2025-09-04 11:43:35 +08:00
Debug.Log("UnityEvo:hotfixDll读取成功");
2025-05-23 18:26:47 +08:00
var hotfixDllAsset = hotfixDll.AssetObject as TextAsset;
if (hotfixPdb.Status == EOperationStatus.Succeed)
{
2025-09-04 11:43:35 +08:00
Debug.Log("UnityEvo:hotfixPdb:读取成功!!");
2025-05-23 18:26:47 +08:00
var hotfixPdbAsset = hotfixPdb.AssetObject as TextAsset;
2025-09-04 11:43:35 +08:00
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为空");
}
2025-05-23 18:26:47 +08:00
}
else
{
if (hotfixDllAsset != null)
2025-09-04 11:43:35 +08:00
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为空");
2025-05-23 18:26:47 +08:00
}
}
else
{
2025-05-30 14:50:46 +08:00
Debug.LogError($"UnityEvo:Android_HotUpdate_{AppConfig.PackageDomainName}.dll加载失败");
2025-05-23 18:26:47 +08:00
}
#endif
2025-07-02 10:05:26 +08:00
Debug.Log($"UnityEvo:dll: Assembly.Load加载后是否为空:{hotUpdateAss == null}");
2025-05-23 18:26:47 +08:00
if (hotUpdateAss != null)
{
2025-09-04 11:43:35 +08:00
var type = hotUpdateAss.GetType(fullClassName);
2025-05-23 18:26:47 +08:00
if (type == null)
{
Debug.LogError($"UnityEvo:热更类不存在!程序集: {hotUpdateAss.FullName}\n" +
$"期望类名: {fullClassName}\n" +
$"可用类型列表:{string.Join("\n", hotUpdateAss.GetTypes().Select(t => t.FullName))}");
return;
}
// 添加方法存在性检查
2025-09-04 11:43:35 +08:00
Debug.Log("UnityEvo:dll:开始MethodInfo检查");
var onEnterMethod = type.GetMethod("OnEnter");
var onEnterAsyncMethod = type.GetMethod("OnEnterAsync");
2025-05-23 18:26:47 +08:00
if (onEnterMethod == null || onEnterAsyncMethod == null)
{
2025-09-04 11:43:35 +08:00
Debug.LogError("UnityEvo:热更类进入方法缺失!\n" +
2025-05-23 18:26:47 +08:00
$"存在方法:{string.Join(", ", type.GetMethods().Select(m => m.Name))}");
return;
}
2025-09-04 11:43:35 +08:00
Debug.Log("UnityEvo:dll:OnEnter检查成功");
var onExitMethod = type.GetMethod("OnExit");
var onExitAsyncMethod = type.GetMethod("OnExitAsync");
2025-05-23 18:26:47 +08:00
if (onExitMethod == null || onExitAsyncMethod == null)
{
2025-09-04 11:43:35 +08:00
Debug.LogError("UnityEvo:热更类退出方法缺失!\n" +
2025-05-23 18:26:47 +08:00
$"存在方法:{string.Join(", ", type.GetMethods().Select(m => m.Name))}");
return;
}
2025-09-04 11:43:35 +08:00
Debug.Log("UnityEvo:dll:OnExit检查成功");
2025-05-23 18:26:47 +08:00
// 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
{
2025-09-04 11:43:35 +08:00
Debug.LogError("UnityEvo:热更类不存在!程序集: hotUpdateAss 不存在\n" +
2025-05-23 18:26:47 +08:00
$"期望类名: {fullClassName}\n" +
$"可用类型列表:{string.Join("\n", hotUpdateAss.GetTypes().Select(t => t.FullName))}");
}
}
2025-09-04 11:43:35 +08:00
public override UniTask OnEnterAsync()
2025-05-23 18:26:47 +08:00
{
return UniTask.CompletedTask;
}
public override UniTask OnEnterAsync<T1, T2>(T1 param1, T2 param2)
{
return UniTask.CompletedTask;
}
2025-09-04 11:43:35 +08:00
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;
}
2025-05-23 18:26:47 +08:00
#region
// //补充元数据dll的列表
// //通过RuntimeApi.LoadMetadataForAOTAssembly()函数来补充AOT泛型的原始元数据
// private List<string> AOTMetaAssemblyFiles { get; } =new()
// {
// "Android_mscorlib.dll", "Android_System.dll", "Android_System.Core.dll",
// };
2025-09-04 11:43:35 +08:00
private readonly List<TextAsset> _sAssetDatas = new();
2025-05-23 18:26:47 +08:00
// public byte[] ReadBytesFromStreamingAssets(string dllName)
// {
// if (_sAssetDatas.ContainsKey(dllName))
// {
// return _sAssetDatas[dllName].bytes;
// }
//
// return Array.Empty<byte>();
// }
/// <summary>
2025-09-04 11:43:35 +08:00
/// 为aot assembly加载原始metadata 这个代码放aot或者热更新都行。
/// 一旦加载后如果AOT泛型函数对应native实现不存在则自动替换为解释模式执行
2025-05-23 18:26:47 +08:00
/// </summary>
private void LoadMetadataForAOTAssemblies()
{
2025-09-04 11:43:35 +08:00
var mode = HomologousImageMode.SuperSet;
2025-05-23 18:26:47 +08:00
// foreach (var aotDllName in AOTGenericReferences.PatchedAOTAssemblyList)
foreach (var aotDll in _sAssetDatas)
// var aotName = $"Android_{aotDllName}";
//
// byte[] dllBytes = ReadBytesFromStreamingAssets(aotName);
if (aotDll != null)
{
2025-09-04 11:43:35 +08:00
var dllBytes = aotDll.bytes;
2025-05-23 18:26:47 +08:00
// 添加元数据加载校验
if (dllBytes == null || dllBytes.Length == 0)
{
Debug.LogError($"AOT元数据加载失败{aotDll.name}");
continue;
}
2025-09-04 11:43:35 +08:00
var err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
2025-05-23 18:26:47 +08:00
Debug.Log($"UnityEvo:【补元】{aotDll.name} 加载结果: {err} 字节数: {dllBytes.Length}");
}
}
#endregion
}
}