using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; using hirdParty.DownloadSystem; using HybridCLR; using ThirdParty; using ThirdParty.DownloadSystem; using UnityEditor; using UnityEngine; public class GameLoadDll { private bool _isHadNetwork; private bool _hadEnterGame; private float _per; private float _currentProgress; private bool _isMarkClose; private readonly Dictionary _assetBytes = new Dictionary(); string versionName = "versionInfo.txt"; private System.Action callBack; private AssetMD5Info remoteMD5Info; private GameStartUIPanel _downloadUI; private string[] localVersionInfo; private GameStart gameStart; public void StartLoadDll(GameStart gameStart, string url, System.Action callBack) { this.gameStart = gameStart; // _downloadUI = HotSyncContent.DownloadUI; _downloadUI.SetMassge("开始校验脚本"); this.callBack = callBack; if (HotSyncContent.isOpenHotFix) { if (HotSyncContent.isOpenDllStreamingLoad) { LoadStreamingDllLoad(); } else { LoadBenDiVersion(); } } } private void LoadStreamingDllLoad() { string DllMD5 = HotSyncContent.GetDllWebRequestPath("DllMD5.txt"); DownloadFileData versiondownloadFileData = new DownloadFileData(); versiondownloadFileData.remoteUrl = DllMD5; DownloadHander downloadHander = FileDownloadSystem.Instance.DownloadFile(versiondownloadFileData); downloadHander.OnFinishCallBack = delegate(DownloadHander hander) { remoteMD5Info = JsonUtility.FromJson(hander.Text, typeof(AssetMD5Info)) as AssetMD5Info; LoadLoaclDll(); }; } private byte[] GetAssetBytes(string dllName) { if (_assetBytes.ContainsKey(dllName)) { return _assetBytes[dllName]; } else { Debug.Log("没有找到dll数据" + dllName); return new byte[] { }; } } // private void LoadVersion() // { // string md5Name = "DllMD5.txt"; // string versionInfoUrl = ($"{HotSyncContent.AssetURL}/{HotSyncContent.platform}/{versionName}"); // DownloadFileData versiondownloadFileData = new DownloadFileData(); // versiondownloadFileData.remoteUrl = versionInfoUrl; // DownloadHander downloadHander = FileDownloadSystem.Instance.DownloadFile(versiondownloadFileData); // downloadHander.OnFinishCallBack = delegate(DownloadHander hander) // { // string[] remoteVersionInfo = hander.Text.Split('\n'); // string versionInfo = // $"{remoteVersionInfo[0].Split('=')[1]}.{remoteVersionInfo[1].Split('=')[1]}.{remoteVersionInfo[2].Split('=')[1]}"; // HotSyncContent.Currversion = versionInfo; // if (localVersionInfo[0]!=remoteVersionInfo[0]) // { // // 本地版本和远程一致也需要更新,防止散文件错误 // Debug.Log("本地版本更大,不需要更新"); // } // else // { // LoadMD5(); // } // }; // } private void LoadBenDiVersion() { string versionInfoUrl = HotSyncContent.GetWebRequestPath(versionName); DownloadFileData versiondownloadFileData = new DownloadFileData(); versiondownloadFileData.remoteUrl = versionInfoUrl; DownloadHander downloadHander = FileDownloadSystem.Instance.DownloadFile(versiondownloadFileData); downloadHander.OnFinishCallBack = delegate(DownloadHander hander) { localVersionInfo = hander.Text.Split('\n'); GetAssetUrl(); }; } private async void GetAssetUrl() { #if UNITY_EDITOR || UNITY_STANDALONE_WIN string appSettingPath = "file://" + Application.streamingAssetsPath + "/AppSetting.txt"; #elif UNITY_ANDROID string appSettingPath = Application.streamingAssetsPath + "/AppSetting.txt"; #elif UNITY_IPHONE string appSettingPath = "file://"+ Application.streamingAssetsPath+"/AppSetting.txt"; #else string appSettingPath = ""; #endif WWW loader = new WWW(appSettingPath); while (!loader.isDone) { } if (!string.IsNullOrEmpty(loader.error)) { Debug.LogError(appSettingPath); Debug.LogError(loader.error); } string url = ""; string settingData = loader.text; string[] datas = settingData.Split('\n'); for (int i = 0; i < datas.Length; i++) { datas[i] = datas[i].Replace("\r", ""); string[] configInfo = datas[i].Split('='); if (configInfo[0].Contains("//") || configInfo.Length <= 1) { continue; } if (configInfo[0].Equals("loginServer")) { url = configInfo[1]; } } url += "/client_config"; LoadAsset(url, localVersionInfo[0].Split('=')[1]); } private async Task LoadAsset(string url, string v) { var replace = v.Replace("\r", ""); _downloadUI.SetMassge($"等待服务器地址"); Debug.Log("等待下载资源服地址" + url); Dictionary dictionary = new Dictionary(); dictionary.Add("buildVer", replace); FormUrlEncodedContent formUrlEncodedContent = new FormUrlEncodedContent(dictionary); HttpClient httpClient = new HttpClient(); httpClient.Timeout = TimeSpan.FromSeconds(5); string json = ""; try { HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(url, formUrlEncodedContent); if (httpResponseMessage.StatusCode != HttpStatusCode.OK) { Debug.LogError(httpResponseMessage.RequestMessage); _downloadUI.SetMassge($"获取配置错误,正在在重新获取!"); LoadAsset(url, v); return; } json = await httpResponseMessage.Content.ReadAsStringAsync(); } catch (Exception e) { Debug.LogError(e); LoadAsset(url, v); return; } httpClient.Dispose(); Debug.Log(json); _downloadUI.SetMassge($"地址获取成功"); // UnityWebRequest webRequest = UnityWebRequest.Post(url, dictionary); // webRequest.timeout = 5; // UnityWebRequestAsyncOperation unityWebRequestAsyncOperation = webRequest.SendWebRequest(); // while (!unityWebRequestAsyncOperation.isDone) // { // yield return 0; // } // if (!string.IsNullOrEmpty(webRequest.error)) // { // Debug.LogError(webRequest.error); // _downloadUI.SetMassge($"获取配置错误,正在在重新获取!"); // gameStart.StartCoroutine(LoadAsset(url, v)); // } // string json = webRequest.downloadHandler.text; AssetUrlInfo assetUrlInfo = JsonUtility.FromJson(json); HotSyncContent.AssetURL = assetUrlInfo.assetsUrl; // webRequest.Dispose(); //HotSyncContent.AssetURL = "http://42.192.110.229/010"; HotSyncContent.loadType = assetUrlInfo.loadType; HotSyncContent.assetsVer = assetUrlInfo.assetsVer; HotSyncContent.Currversion = $"{assetUrlInfo.apkVer}.{assetUrlInfo.buildVer}.{assetUrlInfo.assetsVer}"; Debug.Log("版本号:" + HotSyncContent.Currversion); Debug.Log(HotSyncContent.Currversion + "获得的下载资源服地址" + HotSyncContent.AssetURL); if (localVersionInfo[0].Split('=')[1] != assetUrlInfo.apkVer.ToString()) { Debug.Log("版本号:" + HotSyncContent.Currversion); Debug.Log(HotSyncContent.Currversion + "获得的下载资源服地址" + HotSyncContent.AssetURL); if (localVersionInfo[0].Split('=')[1] != assetUrlInfo.apkVer.ToString()) { // 本地版本和远程一致也需要更新,防止散文件错误 Debug.LogError("本地版本更大,不需要更新"); } else { LoadMD5(); } } else { LoadMD5(); } // LoadVersion(); // Debug.Log(assetUrlInfo.assetsUrl); } private void LoadBenDiVersion(string[] remoteVersionInfo) { string versionInfoUrl = HotSyncContent.GetWebRequestPath(versionName); DownloadFileData versiondownloadFileData = new DownloadFileData(); versiondownloadFileData.remoteUrl = versionInfoUrl; DownloadHander downloadHander = FileDownloadSystem.Instance.DownloadFile(versiondownloadFileData); downloadHander.OnFinishCallBack = delegate(DownloadHander hander) { }; } private void LoadMD5() { _downloadUI.SetMassge($"资源检查中"); string md5Url = $"{HotSyncContent.AssetURL}/{HotSyncContent.platform}/{HotSyncContent.Currversion}/DLL/DllMD5.txt"; DownloadFileData versiondownloadFileData = new DownloadFileData(); versiondownloadFileData.remoteUrl = md5Url; versiondownloadFileData.maxCount = int.MaxValue; versiondownloadFileData.timeOut = 10; DownloadHander downloadHander = FileDownloadSystem.Instance.DownloadFile(versiondownloadFileData); downloadHander.OnFinishCallBack = delegate(DownloadHander hander) { remoteMD5Info = JsonUtility.FromJson(hander.Text, typeof(AssetMD5Info)) as AssetMD5Info; if (HotSyncContent.loadType == 1) { LoadLoaclDll(); } else { JianYan(); } }; } private void JianYan() { List CheckFile = new List(); CheckFile.AddRange(remoteMD5Info.fileInfo); string rootPath = HotSyncContent.AppHotfixResPath; CheckFilePool _checkFileThrans = new CheckFilePool(); _checkFileThrans.isStreamingAssetsPath = true; _checkFileThrans.streamingAssetsPath = HotSyncContent.RootStreamingURL + "/Dll/"; SliderData sliderData = new SliderData(); sliderData.maxValue = CheckFile.Count; _downloadUI.SetMassge($"校验本地文件"); sliderData.CcurrValue = delegate { float m = _checkFileThrans.FileCount(); if (_checkFileThrans.isFinish) { // _downloadUI.ClearSlider(); if (_checkFileThrans.shiBaiFile != null && _checkFileThrans.shiBaiFile.Count > 0) { DownJiaoBen(_checkFileThrans.shiBaiFile); } else { LoadLoaclDll(); } } else { _downloadUI.SetMassge( $"校验本地文件{m} / {sliderData.maxValue}"); } return m; }; // _downloadUI.SetSlider(sliderData); _checkFileThrans.Start(rootPath, CheckFile); } private void DownJiaoBen(List updateFlieInfo) { DownLoadHanderGroup downLoadHanderGroup = new DownLoadHanderGroup(); long size = 0; for (int i = 0; i < updateFlieInfo.Count; i++) { MD5FileInfo md5FileInfo = updateFlieInfo[i]; if (md5FileInfo.size <= 0) { continue; } DownloadFileData downloadFileData = new DownloadFileData(); size += md5FileInfo.size; downloadFileData.remoteUrl = $"{HotSyncContent.AssetURL}/{HotSyncContent.platform}/{HotSyncContent.Currversion}/DLL/{md5FileInfo.fileName}"; Debug.Log("下载文件" + downloadFileData.remoteUrl); downloadFileData.localPath = Path.Combine(HotSyncContent.AppHotfixResPath, md5FileInfo.fileName); DownloadHander fileDow = FileDownloadSystem.Instance.DownloadFile(downloadFileData); downLoadHanderGroup.AddHander(fileDow); } float sizeM = size / 1024f / 1024f; SliderData sliderData = new SliderData(); sliderData.maxValue = size; _downloadUI.SetMassge($"开始下载文件,个数{updateFlieInfo.Count} 大小{sizeM}"); sliderData.CcurrValue = delegate { float m = downLoadHanderGroup.size / 1024f / 1024f; float speed = downLoadHanderGroup.speed / 1024f; _downloadUI.SetMassge( $"开始下载文件,个数{updateFlieInfo.Count} 大小{m.ToString("0.00")}M / {sizeM.ToString("0.00")}M 速度{speed.ToString(".00")} Kb"); return downLoadHanderGroup.size; }; // _downloadUI.SetSlider(sliderData); downLoadHanderGroup.OnCallBack = JianYan; downLoadHanderGroup.StartUpdate(); } private void LoadLoaclDll() { DownLoadHanderGroup downLoadHanderGroup = new DownLoadHanderGroup(); for (int i = 0; i < remoteMD5Info.fileInfo.Count; i++) { MD5FileInfo md5FileInfo = remoteMD5Info.fileInfo[i]; DownloadFileData downloadFileData = new DownloadFileData(); downloadFileData.remoteUrl = HotSyncContent.GetDllWebRequestPath(md5FileInfo.fileName); Debug.Log("下载文件" + downloadFileData.remoteUrl); DownloadHander fileDow = FileDownloadSystem.Instance.DownloadFile(downloadFileData); fileDow.OnFinishCallBack = delegate(DownloadHander hander) { byte[] dllBytes = hander.Data; // dllBytes = DllTool.Instance.KeyDecryption(dllBytes); _assetBytes[md5FileInfo.fileName] = dllBytes; Debug.Log($"资源:{md5FileInfo.fileName} 大小:{dllBytes.Length}"); HomologousImageMode mode = HomologousImageMode.SuperSet; // 加载Assembly对应的Dll,会自动为它hook。一旦AOT泛型函数的Native函数不存在,用解释器版本代码 LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode); Debug.Log($"LoadMetadataForAOTAssembly:{md5FileInfo.fileName}. mode:{mode} ret:{err}"); }; downLoadHanderGroup.AddHander(fileDow); } downLoadHanderGroup.OnCallBack = LoadDll; downLoadHanderGroup.StartUpdate(); } private void LoadDll() { _downloadUI.SetMassge($"初始化资源中,请稍等"); Debug.Log("开始Fort23.Proto"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.Proto.dll.bytes")); // Debug.Log("开始FMODUnity"); // System.Reflection.Assembly.Load(GetAssetBytes("FMODUnity.dll.bytes")); // Debug.Log("开始FMODUnityResonance"); // System.Reflection.Assembly.Load(GetAssetBytes("FMODUnityResonance.dll.bytes")); Debug.Log("开始Fort23.Core"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.Core.dll.bytes")); Debug.Log("开始BGMController"); System.Reflection.Assembly.Load(GetAssetBytes("BGMController.dll.bytes")); Debug.Log("开始Fort23.GameData"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.GameData.dll.bytes")); Debug.Log("开始spine-unity"); System.Reflection.Assembly.Load(GetAssetBytes("spine-unity.dll.bytes")); Debug.Log("开始spine-timeline"); System.Reflection.Assembly.Load(GetAssetBytes("spine-timeline.dll.bytes")); Debug.Log("开始Fort23.CombatCore"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.CombatCore.dll.bytes")); Debug.Log("开始Fort23.UTool"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.UTool.dll.bytes")); Debug.Log("开始Fort23.Combat"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.Combat.dll.bytes")); Debug.Log("开始Fort23.Mono"); System.Reflection.Assembly.Load(GetAssetBytes("Fort23.Mono.dll.bytes")); // Debug.Log("spine-unity"); // System.Reflection.Assembly.Load(GetAssetBytes("spine-unity.dll")); // Debug.Log("spine-timeline"); // System.Reflection.Assembly.Load(GetAssetBytes("spine-timeline.dll")); Debug.Log("开始Assembly-CSharp"); System.Reflection.Assembly.Load(GetAssetBytes("Assembly-CSharp.dll.bytes")); AppDomain.CurrentDomain.GetAssemblies() .First(assembly => assembly.GetName().Name == "Assembly-CSharp"); Debug.Log("Assembly-CSharp.dll加载成功"); // 2. 开始执行热更新代码逻辑,加载Init进入游戏流程 Debug.Log("开始加载进入游戏"); string path = Application.persistentDataPath + "/Bundle/init"; if (!File.Exists(path)) { path = Application.streamingAssetsPath + "/Bundle/init"; } Debug.Log("path=" + path); // string[] assemblyNames = // { // "Fort23.Core.dll", "Fort23.MonoCore.dll", "Fort23.Mono.dll", "Fort23.Model.dll", // "Fort23.CommonCore.dll", "Fort23.Common.dll", "Assembly-CSharp.dll", "Fort23.UTool.dll", // "Fort23.GameData.dll", "spine-unity.dll", "spine-timeline.dll", "BGMController.dll", "Fort23.Combat.dll", // "Fort23.CombatCore.dll" // }; // int addCount = 0; // foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) // { // string assemblyName = $"{assembly.GetName().Name}.dll"; // if (!((IList) assemblyNames).Contains(assemblyName)) // { // continue; // } // Debug.Log(assemblyName); // foreach (var type in assembly.GetTypes()) // { // // if ((typeof(MonoBehaviour).IsAssignableFrom(type))) // { // Debug.Log(type.Name); // var go = new GameObject(); // // 我们不希望挂载到这个GameObject上的脚本执行 // go.SetActive(false); // go.AddComponent(type); // GameObject.Destroy(go); // addCount++; // } // } // // } callBack?.Invoke(); } }