Ignore AIClient/Library and AIClient/HybridCLRData permanently; include HybridCLR/YooAsset project setup and UI tooling. Co-authored-by: Cursor <cursoragent@cursor.com>
127 lines
4.1 KiB
C#
127 lines
4.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using AOT.Boot;
|
|
using UnityEngine;
|
|
using YooAsset;
|
|
#if !UNITY_EDITOR
|
|
using HybridCLR;
|
|
#endif
|
|
|
|
namespace AOT.HotUpdate
|
|
{
|
|
/// <summary>
|
|
/// 加载热更程序集并调用稳定入口 HotUpdate.Entry.Start(BootContext)。
|
|
/// </summary>
|
|
public static class HotUpdateLoader
|
|
{
|
|
const string EntryTypeName = "HotUpdate.Entry";
|
|
const string EntryMethodName = "Start";
|
|
|
|
public static IEnumerator LoadAndStart(BootContext ctx, BootSettings settings, Action<string> onError)
|
|
{
|
|
#if UNITY_EDITOR
|
|
if (settings.EditorDirectHotUpdate || ctx.Package == null)
|
|
{
|
|
var err = InvokeEntry(FindLoadedAssembly("HotUpdate.Runtime"), ctx);
|
|
if (err != null) onError?.Invoke(err);
|
|
yield break;
|
|
}
|
|
#endif
|
|
|
|
if (ctx.Package == null)
|
|
{
|
|
onError?.Invoke("ResourcePackage 为空,无法加载热更 DLL");
|
|
yield break;
|
|
}
|
|
|
|
var handle = ctx.Package.LoadAssetAsync<RawFileObject>(settings.HotUpdateDllLocation);
|
|
yield return handle;
|
|
if (handle.Status != EOperationStatus.Succeeded)
|
|
{
|
|
onError?.Invoke($"加载热更 DLL 失败: {handle.Error}");
|
|
yield break;
|
|
}
|
|
|
|
var raw = handle.GetAssetObject<RawFileObject>();
|
|
if (raw == null)
|
|
{
|
|
onError?.Invoke("热更 DLL RawFileObject 为空");
|
|
yield break;
|
|
}
|
|
|
|
byte[] dllBytes = raw.GetBytes();
|
|
handle.Release();
|
|
|
|
if (dllBytes == null || dllBytes.Length < 64)
|
|
{
|
|
onError?.Invoke($"热更 DLL 字节异常 length={dllBytes?.Length ?? 0}");
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log($"[HotUpdateLoader] RawFile loaded location={settings.HotUpdateDllLocation} bytes={dllBytes.Length}");
|
|
|
|
#if UNITY_EDITOR
|
|
// 编辑器域内已加载同名程序集,不能重复 Assembly.Load;验证 RawFile 后走反射入口。
|
|
{
|
|
var err = InvokeEntry(FindLoadedAssembly("HotUpdate.Runtime"), ctx);
|
|
if (err != null) onError?.Invoke(err);
|
|
yield break;
|
|
}
|
|
#else
|
|
// AOT 补充元数据:后续由 HybridCLR Generate 产物批量加载。
|
|
// HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(metaBytes, HomologousImageMode.SuperSet);
|
|
|
|
Assembly asm;
|
|
try
|
|
{
|
|
asm = Assembly.Load(dllBytes);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
onError?.Invoke($"Assembly.Load 失败: {e.Message}");
|
|
yield break;
|
|
}
|
|
|
|
var invokeErr = InvokeEntry(asm, ctx);
|
|
if (invokeErr != null)
|
|
onError?.Invoke(invokeErr);
|
|
#endif
|
|
}
|
|
|
|
static Assembly FindLoadedAssembly(string name)
|
|
{
|
|
return AppDomain.CurrentDomain.GetAssemblies()
|
|
.FirstOrDefault(a => string.Equals(a.GetName().Name, name, StringComparison.Ordinal));
|
|
}
|
|
|
|
static string InvokeEntry(Assembly asm, BootContext ctx)
|
|
{
|
|
if (asm == null)
|
|
return "未找到热更程序集 HotUpdate.Runtime";
|
|
|
|
var type = asm.GetType(EntryTypeName, throwOnError: false);
|
|
if (type == null)
|
|
return $"未找到类型 {EntryTypeName}";
|
|
|
|
var method = type.GetMethod(EntryMethodName, BindingFlags.Public | BindingFlags.Static);
|
|
if (method == null)
|
|
return $"未找到方法 {EntryTypeName}.{EntryMethodName}";
|
|
|
|
try
|
|
{
|
|
method.Invoke(null, new object[] { ctx });
|
|
return null;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var inner = e is TargetInvocationException tie && tie.InnerException != null
|
|
? tie.InnerException
|
|
: e;
|
|
return $"调用热更入口失败: {inner.Message}";
|
|
}
|
|
}
|
|
}
|
|
}
|