Files
plugin-library/Assets/Main/Script/Runtime/Fsm/HotFixState.cs

257 lines
9.7 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
{
public class HotFixState : AbstractFSMIState
{
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(IFsmSystem system) : base(system)
{
}
public override async UniTask OnEnterAsync<T>(T param)
{
DomainConfig domainConfig = param as DomainConfig;
Debug.Log("UnityEvo:热更脚本...");
var package = YooAssets.GetPackage(AppConfig.ASSETPACKGENAME);
// 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.ASSETPACKGENAME}");
#else
string hotUpdateAssemblyName = $"HotUpdate_{AppConfig.ASSETPACKGENAME}";
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.ASSETPACKGENAME}.dll");
await hotfixDll;
var hotfixPdb = package.LoadAssetAsync<TextAsset>($"Android_HotUpdate_{AppConfig.ASSETPACKGENAME}.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);
}
else
{
if (hotfixDllAsset != null)
hotUpdateAss = Assembly.Load(hotfixDllAsset.bytes);
}
}
else
{
Debug.LogError($"UnityEvo:Android_HotUpdate_{AppConfig.ASSETPACKGENAME}.dll加载失败");
}
#endif
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;
}
// 添加方法存在性检查
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;
}
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:Type检查成功");
// 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;
}
}
}