Files
plugin-library/Assets/00.StaryEvoTools/Runtime/HybridLoad/Fsm/HotFixState.cs
zhangzheng 42161fa127 111
2025-12-16 17:21:46 +08:00

324 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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",
"UniTask.dll",
"YooAsset.dll",
"com.stary.evo.runtime.dll",
"com.staryevo.tools.runtime.dll",
"mscorlib.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
}
}