using Cysharp.Threading.Tasks; using HybridCLR; using Sirenix.Utilities; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; 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列表的配置也可以通过热更新下下来,这样增加了新的泛型就不怕了 ConfigStringList hotUpdateAOTDlls = (await YooAssetProxy.LoadAssetAsync("HotUpdateAOTDlls")) .GetAssetObject(); List> tasks = new List>(); foreach (var aotDll in hotUpdateAOTDlls.List) { 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() { Dictionary typesInAssembly = new Dictionary(); Assembly modelAss = null; #if ! UNITY_EDITOR var battleDlls = (await YooAssetProxy.LoadAssetAsync("HotupdateBattleDlls")).GetAssetObject(); foreach (var dll in battleDlls.List) { Log.Info($"to load: {dll}"); Assembly.Load((await YooAssetProxy.GetRawFileAsync(dll)).GetRawBytes()); } #endif var hotDlls = (await YooAssetProxy.LoadAssetAsync("HotupdateDlls")).GetAssetObject(); foreach(var kv in hotDlls.keyValueMaps) { Assembly ass; if(kv.Value.IsNullOrWhitespace()) { Log.Info($"to load: {kv.Key}"); ass = Assembly.Load((await YooAssetProxy.GetRawFileAsync(kv.Key)).GetRawBytes()); } else { Log.Info($"to load: {kv.Key}"); ass = Assembly.Load((await YooAssetProxy.GetRawFileAsync(kv.Key)).GetRawBytes(), (await YooAssetProxy.GetRawFileAsync(kv.Value)).GetRawBytes()); } foreach (Type type in ass.GetTypes()) { typesInAssembly[type.FullName] = type; } if(kv.Key.Equals("Model.dll")) { modelAss = ass; } } EventSystem.Instance.Add(typesInAssembly); if(modelAss == null) { Log.Error("Not Found 'Model.dll'! "); return; } Log.Info("to call Client.Entry."); IStaticMethod start = new MonoStaticMethod(modelAss, "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() { //防裁剪 var xx = ImageConversion.EnableLegacyPngGammaRuntimeLoadBehavior; Image x = Image.FromFile(""); } } }