Add hot-update boot pipeline, UI bundles/atlas assets, and design docs.
Ignore AIClient/Library and AIClient/HybridCLRData permanently; include HybridCLR/YooAsset project setup and UI tooling. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user