using Cysharp.Threading.Tasks; using HybridCLR; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using UnityEngine; using YooAsset; namespace ET { public class CodeLoader: Singleton { public void Start() { AsyncLoadResAndCode().Forget(); } private async UniTaskVoid AsyncLoadResAndCode() { YooAssets.EPlayMode playMode; if (Define.EnableCodes) { playMode = YooAssets.EPlayMode.EditorSimulateMode; } else { GlobalConfig globalConfig = Resources.Load("GlobalConfig"); playMode = globalConfig.PlayMode; } Log.Info($"start mode: {playMode}"); // 启动YooAsset引擎 await YooAssetProxy.StartYooAssetEngine(playMode); // Shader Warm Up ShaderVariantCollection shaderVariantCollection = (await YooAssetProxy.LoadAssetAsync( YooAssetProxy.GetYooAssetFormatResPath("ProjectSShaderVariant", YooAssetProxy.YooAssetResType.Shader))) .GetAssetObject(); Stopwatch stopwatch = Stopwatch.StartNew(); shaderVariantCollection.WarmUp(); stopwatch.Stop(); Log.Info($"Shader Warm Up完成, 耗时: {stopwatch.ElapsedMilliseconds}ms,shaderCount: {shaderVariantCollection.shaderCount} variantCount: {shaderVariantCollection.variantCount}"); //加载代码入口 if (Define.EnableCodes) { LoadLocalCode(); } else { await LoadMetadataForAOT(); await LoadHotfixCode(); } } // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码 private async UniTask LoadMetadataForAOT() { //AOT dll列表的配置也可以通过热更新下下来,这样增加了新的泛型就不怕了 HotUpdateAssemblyManifest mainfest = (await YooAssetProxy.LoadAssetAsync("HotUpdateAssemblyManifest")) .GetAssetObject(); var DLLNameList_ForABLoad = mainfest.AOTMetadataDlls; List> tasks = new List>(); foreach (var aotDll in DLLNameList_ForABLoad) { tasks.Add(YooAssetProxy.GetRawFileAsync(aotDll)); } RawFileOperation[] rawFileOperations = await UniTask.WhenAll(tasks); foreach (var task in rawFileOperations) { var ret = RuntimeApi.LoadMetadataForAOTAssembly(task.GetRawBytes(), HomologousImageMode.SuperSet); if (ret != LoadImageErrorCode.OK) { Log.Error($"Error occurs when loadMetadataForAOT: {ret}"); } } } //热更加载 model.dll & hotfix.dll private async UniTask LoadHotfixCode() { Log.Info("to load model.dll & hotfix.dll."); var rawfile_modeldll = await YooAssetProxy.GetRawFileAsync("Model.dll"); var rawfile_modelpdb = await YooAssetProxy.GetRawFileAsync("Model.pdb"); var modelAssembly = Assembly.Load(rawfile_modeldll.GetRawBytes(), rawfile_modelpdb.GetRawBytes()); var rawfile_hotfixdll = await YooAssetProxy.GetRawFileAsync("Hotfix.dll"); var rawfile_hotfixpdb = await YooAssetProxy.GetRawFileAsync("Hotfix.pdb"); var hotfixAssembly = Assembly.Load(rawfile_hotfixdll.GetRawBytes(), rawfile_hotfixpdb.GetRawBytes()); var mdll = await YooAssetProxy.GetRawFileAsync("Unity.Mono.dll"); var mAssembly = Assembly.Load(mdll.GetRawBytes()); Dictionary types = AssemblyHelper.GetAssemblyTypes(typeof(Game).Assembly, typeof(Init).Assembly, modelAssembly, hotfixAssembly, mAssembly); EventSystem.Instance.Add(types); Log.Info("to call Client.Entry."); IStaticMethod start = new MonoStaticMethod(modelAssembly, "ET.Entry", "Start"); start.Run(); } //不使用dll,打开了EnableCode,使用Editor编辑模式 private void LoadLocalCode() { //GlobalConfig globalConfig = Resources.Load("GlobalConfig"); //if (globalConfig.CodeMode != CodeMode.ClientServer) //{ // throw new Exception("ENABLE_CODES mode must use ClientServer code mode!"); //} Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Dictionary types = AssemblyHelper.GetAssemblyTypes(assemblies); EventSystem.Instance.Add(types); bool bStart = false; foreach (Assembly ass in assemblies) { string name = ass.GetName().Name; if (name == "Unity.Model.Codes") { bStart = true; IStaticMethod start = new StaticMethod(ass, "ET.Entry", "Start"); start.Run(); break; } } if (!bStart) { throw new Exception("not found Assembly: 'Unity.Model.Codes'"); } } //编译时会检查这个方法,需保留 public void LoadHotfix() { } } }