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<CodeLoader> { private Assembly model; public void Start() { if (Define.EnableCodes) { GlobalConfig globalConfig = Resources.Load<GlobalConfig>("GlobalConfig"); if (globalConfig.CodeMode != CodeMode.ClientServer) { throw new Exception("ENABLE_CODES mode must use ClientServer code mode!"); } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Dictionary<string, Type> types = AssemblyHelper.GetAssemblyTypes(assemblies); EventSystem.Instance.Add(types); foreach (Assembly ass in assemblies) { string name = ass.GetName().Name; if (name == "Unity.Model.Codes") { this.model = ass; } } IStaticMethod start = new StaticMethod(this.model, "ET.Entry", "Start"); start.Run(); } else { LoadAssetsAndHotfix().Forget(); } } private async UniTaskVoid LoadAssetsAndHotfix() { // 启动YooAsset引擎,并在初始化完毕后进行热更代码加载 await YooAssetProxy.StartYooAssetEngine(YooAssets.EPlayMode.HostPlayMode); // Shader Warm Up /*ShaderVariantCollection shaderVariantCollection = (await YooAssetProxy.LoadAssetAsync<ShaderVariantCollection>( YooAssetProxy.GetYooAssetFormatResPath("ProjectSShaderVariant", YooAssetProxy.YooAssetResType.Shader))) .GetAssetObject<ShaderVariantCollection>(); Stopwatch stopwatch = Stopwatch.StartNew(); shaderVariantCollection.WarmUp(); stopwatch.Stop(); Log.Info($"Shader Warm Up完成, 耗时: {stopwatch.ElapsedMilliseconds}ms,shaderCount: {shaderVariantCollection.shaderCount} variantCount: {shaderVariantCollection.variantCount}");*/ #if !UNITY_EDITOR //给mscorlib.dll等AOT补充元数据 await LoadMetadataForAOT(); #endif await LoadHotfixCode(); } // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码 private async UniTask LoadMetadataForAOT() { //TODO: DLL列表 List<string> DLLNameList_ForABLoad = new List<string> (){ } ; List<UniTask<RawFileOperation>> tasks = new List<UniTask<RawFileOperation>>(); 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.Info($"LoadMetadataForAOTAssembly({task.GetBundleName()}) ok."); } else { Log.Error($"LoadMetadataForAOTAssembly({task.GetBundleName()}) Error: {ret}"); } } } //TODO: load model.dll hotfix.dll public async UniTask LoadHotfixCode() { Log.Info("to load hotfix.dll."); byte[] assBytes = (await YooAssetProxy.GetRawFileAsync("Code_ProjectS_Hotfix.dll")).GetRawBytes(); byte[] pdbBytes = (await YooAssetProxy.GetRawFileAsync("Code_ProjectS_Hotfix.pdb")).GetRawBytes(); var assembly = Assembly.Load(assBytes, pdbBytes); //Dictionary<string, Type> types = AssemblyHelper.GetAssemblyTypes(typeof(Game).Assembly, typeof(Init).Assembly, this.model, hotfixAssembly); //EventSystem.Instance.Add(types); Log.Info("to call Client.Entry."); IStaticMethod start = new MonoStaticMethod(assembly, "ET.Client.Entry", "Start"); start.Run(); } } }