2025-06-07 17:43:34 +08:00

504 lines
19 KiB
C#
Raw Permalink 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 Cysharp.Threading.Tasks;
using HybridCLR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using YooAsset;
using FairyGUI;
namespace AOT
{
/// <summary>
/// 用于启动游戏,执行版本检查,版本更新,加载程序集,进入游戏
/// 错误处理是用的打印日志,正式上线的话需要一个错误处理系统来给玩家显示错误信息
/// </summary>
public class GameLaunch : MonoBehaviour
{
#region Inner Class
[Serializable]
public class MethodExecutionInfo
{
public string assemblyName;
public string typeName;
public string methodName;
public int sequence;
public MethodExecutionInfo(string assemblyName, string typeName, string methodName, int sequence)
{
this.assemblyName = assemblyName;
this.typeName = typeName;
this.methodName = methodName;
this.sequence = sequence;
}
public void Execute()
{
var assembly = FindObjectOfType<GameLaunch>().GetAssembly(assemblyName);
if (assembly == null)
{
Debug.LogError($"cant find assembly,name:{assemblyName}");
return;
}
var type = assembly.GetType(typeName);
if (type == null)
{
Debug.LogError($"cant find type,name:{typeName}");
return;
}
var method = type.GetMethod(methodName,
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
Debug.LogError($"cant find method,name:{methodName}");
return;
}
method.Invoke(null, null);
}
}
[Serializable]
public class RuntimeInitializeOnLoadMethodCollection
{
public List<MethodExecutionInfo> methodExecutionInfos = new List<MethodExecutionInfo>();
}
#endregion
const string START_SCENE_NAME = "Assets/Art/Scenes/main.unity";
public static string META_DATA_DLL_PATH
{
get
{
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.LinuxEditor:
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/MetaDataDll/";
case RuntimePlatform.Android:
return "Assets/Scripts/Dlls/Android/HotUpdateDlls/MetaDataDll/";
default:
Debug.LogWarning($"Unsupported platform: {Application.platform}. Using PC path as fallback.");
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/MetaDataDll/";
}
}
}
//const string META_DATA_DLL_PATH = "Assets/Scripts/Dlls/HotUpdateDlls/MetaDataDll/";
//const string HOT_UPDATE_DLL_PATH = "Assets/Scripts/Dlls/HotUpdateDlls/HotUpdateDll/";
//public const string META_DATA_DLLS_TO_LOAD_PATH = "Assets/Scripts/Dlls/HotUpdateDlls/MetaDataDllToLoad.txt";
//public const string RUN_TIME_INITIALIZE_ON_LOAD_METHOD_COLLECTION_PATH = "Assets/Scripts/Dlls/HotUpdateDlls/RuntimeInitializeOnLoadMethodCollection.txt";
// 定义静态属性,根据平台返回不同的 HOT_UPDATE_DLL_PATH
public static string HOT_UPDATE_DLL_PATH
{
get
{
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.LinuxEditor:
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/HotUpdateDll/";
case RuntimePlatform.Android:
return "Assets/Scripts/Dlls/Android/HotUpdateDlls/HotUpdateDll/";
default:
Debug.LogWarning($"Unsupported platform: {Application.platform}. Using PC path as fallback.");
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/HotUpdateDll/";
}
}
}
// 定义静态属性,根据平台返回不同的 META_DATA_DLLS_TO_LOAD_PATH
public static string META_DATA_DLLS_TO_LOAD_PATH
{
get
{
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.LinuxEditor:
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/MetaDataDllToLoad.txt";
case RuntimePlatform.Android:
return "Assets/Scripts/Dlls/Android/HotUpdateDlls/MetaDataDllToLoad.txt";
default:
Debug.LogWarning($"Unsupported platform: {Application.platform}. Using PC path as fallback.");
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/MetaDataDllToLoad.txt";
}
}
}
// 定义静态属性,根据平台返回不同的 RUN_TIME_INITIALIZE_ON_LOAD_METHOD_COLLECTION_PATH
public static string RUN_TIME_INITIALIZE_ON_LOAD_METHOD_COLLECTION_PATH
{
get
{
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.LinuxEditor:
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/RuntimeInitializeOnLoadMethodCollection.txt";
case RuntimePlatform.Android:
return "Assets/Scripts/Dlls/Android/HotUpdateDlls/RuntimeInitializeOnLoadMethodCollection.txt";
default:
Debug.LogWarning($"Unsupported platform: {Application.platform}. Using PC path as fallback.");
return "Assets/Scripts/Dlls/PC/HotUpdateDlls/RuntimeInitializeOnLoadMethodCollection.txt";
}
}
}
const string GAMEPLAY_DLL_NAME = "HotUpdate.dll";
public const string META_DATA_DLL_SEPARATOR = "_";
private Dictionary<string, Assembly> _allHotUpdateAssemblies = new Dictionary<string, Assembly>();
///GamePlay程序集依赖的热更程序集这些程序集要先于gameplay程序集加载需要手动填写
private readonly List<string> _gamePlayDependencyDlls = new List<string>()
{
};
/// <summary>
/// 资源系统运行模式
/// </summary>
public EPlayMode playMode = EPlayMode.EditorSimulateMode;
//DeviceInfoManager deviceInfo = new DeviceInfoManager();
public _UI_VersionUpdate version;
private void Awake()
{
//SetFullScreen(version.transform.parent as RectTransform);
}
public void SetFullScreen(RectTransform full)
{
//var full = transform.Find("full") as RectTransform;
//这里写让full的Top自适应到安全屏幕。
//这是一个竖屏的AppTop就是顶部屏幕有刘海的位置
if (full != null)
{
// 获取安全区域
Rect safeArea = Screen.safeArea;
// 计算顶部偏移量屏幕高度减去安全区域顶部的y坐标
float topOffset = Screen.height - safeArea.yMax;
if (topOffset > 0)
{
//LogYellow($"不安全区域像素:{topOffset}");
if (topOffset < 0)
{
topOffset = 0;
}
}
// 获取full的offsetMax
Vector2 offsetMax = full.offsetMax;
// 设置顶部偏移量
offsetMax.y = -topOffset;
// 应用新的offsetMax
full.offsetMax = offsetMax;
}
}
async void Start()
{
//deviceInfo.InitDeviceInfo();
await Launch();
}
private async UniTask Launch()
{
InitFairyGUI();
await RequestVersionInfo();
//await Framework_AOT.Init(this.gameObject);
//暂时注释
//_ui_versionUpdate.gameObject.SetActive(true);
//出现更新界面
//if (playMode == EPlayMode.HostPlayMode)
//{
// LogRed($"开始zip下载流程");
// //ZIP包补丁更新需要在YooAsset初始化之前
// //await XPatchManager.Instance.Init(m_DownloadManager, m_ZipManager);
// //LogRed($"XPatchManager初始化结束");
// //解锁帧率
// Application.targetFrameRate = -1;
// var updateSucceed = await XPatchManager.Instance.StartUpdateResourcesAsync();
// LogRed($"zip下载流程结束");
// if (!updateSucceed)
// {
// LogRed($"补丁更新失败\n");
// //清空此次更新下载的资源
// XPatchManager.Instance.ClearUpdateResources();
// //TODO 要么弹窗让玩家重试,要么退出游戏
// return;
// }
// Application.targetFrameRate = 60;
//}
YooAssetManager_AOT.instance.onStart = LoadAssemblies;
YooAssetManager_AOT.instance.onFinish = EnterGame;
await YooAssetManager_AOT.YooInit(playMode);
//启动游戏加载字体
//await yooManager.LoadAssetAsync<Font>("Assets/Art/Font/hpqdqxj.ttf");
Debug.Log("YooInit 完成");
//await LoadAssemblies();
//EnterGame();
}
private void InitFairyGUI()
{
// 1. 初始化UI根节点
GRoot.inst.SetContentScaleFactor((int)AppConst_AOT.screenSize_Width, (int)AppConst_AOT.screenSize_Height,
UIContentScaler.ScreenMatchMode.MatchWidthOrHeight);
// 2. 加载Loading界面
UIPackage.AddPackage("Loading");
GComponent view = UIPackage.CreateObject("Loading", "mainbg").asCom;
GRoot.inst.AddChild(view);
var versionUpdate = new _UI_VersionUpdate(view);
}
/// <summary>
/// 请求版本文件
/// assets_version_info.json
/// </summary>
private async UniTask RequestVersionInfo()
{
AOT.Event.PatchEventDefine.RequestVersionInfo.SendEventMessage("下载 assets_version_info.json");
var url =
$"{AppConst_AOT.AssetsServerPath}/CDN/{GetPlatformName()}/{AppConst_AOT.AssetsVersion}/assets_version_info.json";
//Debug.Log($"## 请求版本文件 {url}");
if (AppConst_AOT.UpdateMode)
{
AppConst_AOT.yoo_Package_Info = await Downloader.DownloadJSONAsync<Yoo_Package_Info>(url);
//Debug.Log("## 版本文件下载完成");
}
else
{
//编辑器模式读assets_version_info.json
//后续改为从服务器下载版本信息。
AppConst_AOT.yoo_Package_Info = VersionUtils.GetYooPackageVersion();
}
}
public static string GetPlatformName()
{
#if UNITY_EDITOR
switch (EditorUserBuildSettings.activeBuildTarget)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.StandaloneOSX:
case BuildTarget.StandaloneLinux64:
return "PC";
case BuildTarget.iOS:
return "IPhone";
case BuildTarget.Android:
return "Android";
default:
return EditorUserBuildSettings.activeBuildTarget.ToString();
}
#else
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
return "PC";
case RuntimePlatform.IPhonePlayer:
return "IPhone";
case RuntimePlatform.Android:
return "Android";
default:
return Application.platform.ToString();
}
#endif
}
private async UniTask LoadAssemblies()
{
//if (!enableHybridCLR)
// return;
#if !UNITY_EDITOR
if (playMode == EPlayMode.EditorSimulateMode)
return;
Debug.Log("LoadAssemblies start!");
HybridCLROptimizer.OptimizeHybridCLR();
await LoadMetadataForAOTAssemblies();
await LoadGamePlayDependencyAssemblies();
await LoadGamePlayAssemblies();
ExecuteRuntimeInitializeOnLoadMethodAttribute();
await UniTask.Yield();
Debug.Log("LoadAssemblies finish!");
#endif
}
//补充元数据
private async UniTask LoadMetadataForAOTAssemblies()
{
var aotAssemblies = await GetMetaDataDllToLoad();
if (aotAssemblies == null)
{
return;
}
foreach (var aotDllName in aotAssemblies)
{
if (string.IsNullOrEmpty(aotDllName))
continue;
Debug.Log($"补充元数据 {META_DATA_DLL_PATH}{aotDllName}.bytes");
var path = $"{META_DATA_DLL_PATH}{aotDllName}.bytes";
var asset = await ReadDllBytes(path);
if (asset != null)
{
var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(asset, HomologousImageMode.SuperSet);
Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. ret:{err}");
}
}
Debug.Log("LoadMetadataForAOTAssemblies finish!");
}
private async UniTask<string[]> GetMetaDataDllToLoad()
{
string[] result = null;
var metaDataToLoad = await YooAssetManager_AOT.LoadAssembliesAsset<TextAsset>(META_DATA_DLLS_TO_LOAD_PATH);
if (metaDataToLoad == null)
{
Debug.LogError($"cant load metaDataText,path:{META_DATA_DLLS_TO_LOAD_PATH}");
}
else
{
var text = metaDataToLoad.text;
Debug.Log($"下载到的dll名称{text}");
result = text.Split(META_DATA_DLL_SEPARATOR);
//yooManager.UnloadAsset(metaDataToLoad);
}
return result;
}
private async UniTask<byte[]> ReadDllBytes(string path)
{
var dllText = await YooAssetManager_AOT.LoadAssembliesAsset<TextAsset>(path);
return dllText.bytes;
//_dllBytes = (dllText.AssetObject as TextAsset).bytes;
}
//加载GamePlay依赖的第三方程序集
private async UniTask LoadGamePlayDependencyAssemblies()
{
foreach (var dllName in _gamePlayDependencyDlls)
await LoadSingleHotUpdateAssembly(dllName);
Debug.Log("LoadGamePlayDependencyAssemblies finish!");
}
//加载GamePlay程序集
private async UniTask LoadGamePlayAssemblies()
{
await LoadSingleHotUpdateAssembly(GAMEPLAY_DLL_NAME);
Debug.Log("LoadGamePlayAssemblies finish!");
}
private async UniTask OnLoadScene()
{
//StartCoroutine(YooAssetManager.ChangeScene());
transform.Find("EventSystem").gameObject.SetActive(false);
await YooAssetManager_AOT.ChangeScene(START_SCENE_NAME);
}
private async void EnterGame()
{
if (YooAssetManager_AOT.instance.isFinish)
await OnLoadScene();
else
return;
Debug.Log("EnterGame finish!");
}
private async UniTask LoadSingleHotUpdateAssembly(string dllName)
{
var path = $"{HOT_UPDATE_DLL_PATH}{dllName}.bytes";
Debug.Log($"开始读取dll bytes{path}");
var asset = await ReadDllBytes(path);
if (asset != null)
{
var assembly = Assembly.Load(asset);
_allHotUpdateAssemblies.Add(assembly.FullName, assembly);
Debug.Log($"加载程序集成功, 程序集名称:{assembly.FullName}");
}
await UniTask.Yield();
}
/// <summary>
/// 反射执行被RuntimeInitializeOnLoadMethod attribute标注的函数HybridCLR不支持该attribute
/// </summary>
private async void ExecuteRuntimeInitializeOnLoadMethodAttribute()
{
//var runtimeInitializeOnLoadMethodCollection = await YooAssetManager_AOT.LoadAsset<TextAsset>(RUN_TIME_INITIALIZE_ON_LOAD_METHOD_COLLECTION_PATH);
//var json = runtimeInitializeOnLoadMethodCollection.text;
//var collection = JsonUtility.FromJson<RuntimeInitializeOnLoadMethodCollection>(json);
//foreach (var methodInfo in collection.methodExecutionInfos)
// methodInfo.Execute();
//Debug.Log("execute RuntimeInitializeOnLoadMethod finish!");
}
private Assembly GetAssembly(string assemblyName)
{
assemblyName = assemblyName.Replace(".dll", "");
IEnumerable<Assembly> allAssemblies;
#if !UNITY_EDITOR
allAssemblies = _allHotUpdateAssemblies.Values;
#else
allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
#endif
//enableHybridCLR ? _allHotUpdateAssemblies.Values : AppDomain.CurrentDomain.GetAssemblies();
return allAssemblies.First(assembly => assembly.FullName.Contains(assemblyName));
}
}
}