using System.Collections; using System.Collections.Generic; using System.Security.Cryptography; using System.IO; using UnityEngine; using UnityEngine.UI; using MEC; public class ResManager { private struct BundleInfo{ public long size; public string hash; } public static ResManager Instance { get { if (_instance == null) _instance = new ResManager(); return _instance; } } static ResManager _instance; Test test; string Content; static string BundleRoot = "PackData"; static string ManifestBundleName = "PackData"; static string ManifestFileResName = "bundles"; // under Resources/bundles.manifest static string ManifesteRemotePath = "bundles.manifest"; #if UNITY_STANDALONE_WIN static string cdnAddress = "http://localhost/bundles/"; // PC #elif UNITY_ANDROID static string cdnAddress = "http://10.0.2.2/bundles/"; // AndroidEmu #endif Dictionary CachedBundles = new Dictionary(); Dictionary FileMapping = new Dictionary(); AssetBundleManifest Manifest; #region 更新相关 // 本地streamingAssetsPath下的bundles数据,从固化的bundles.manifest中读取 Dictionary localBundles = new Dictionary(); // CDN上的bundles数据 Dictionary remoteBundles = new Dictionary(); #endregion public void Init(Test test) { this.test = test; LoadLocalBundlesInfo(); Timing.Instance.RunCoroutineOnInstance(DownloadManifest()); } void Print(string content , bool alert = false) { test.Print(content, alert); } public string ResContent(string path) { TextAsset text = Resources.Load(path) as TextAsset; if (text == null) return null; return text.text; } public void ReadFileMapping() { AssetBundle bundle = LoadBundle("bundle00.ab"); // 不可以省略后缀 if (bundle == null) { string path = PathHelper.GetStreamingFullFilePath(BundleRoot + "/bundle00.ab"); Print("Bundle 为空, path = " + path, true); return; } TextAsset text = bundle.LoadAsset("fileMapping"); if (text == null) return; string content = text.text; content = content.Replace("\r", string.Empty); string[] lines = content.Split('\n'); Print("Load FileMapping:"); foreach (string line in lines) { string[] part = line.Split(','); FileMapping.Add(part[0], part[1]); Print(part[0] + " " + part[1]); } } /// /// 刚开始进入游戏的时候要写入.manifest,用来后续对比更新 /// public void LoadManifest() { AssetBundle bundle = LoadBundle(ManifestBundleName); if (bundle == null) { Print("没有Manifest", true); return; } Manifest = bundle.LoadAsset("AssetBundleManifest"); if (Manifest == null) { Print("AssetBundleManifest", true); return; } Print("All bundles:"); string[] bundleNames = Manifest.GetAllAssetBundles(); foreach (var bundleName in bundleNames) { Print(bundleName); } } public AssetBundle LoadBundle(string name) { AssetBundle bundle; if (CachedBundles.TryGetValue(name, out bundle)) { return bundle; } string path = PathHelper.GetPersistentFullFilePath(BundleRoot + "/" + name); Print(path); if (!File.Exists(path)) { Print("不在persistent里"); path = PathHelper.GetStreamingFullFilePath(BundleRoot + "/" + name); } bundle = AssetBundle.LoadFromFile(path); if(bundle == null) Print("是空的"); CachedBundles.Add(name, bundle); return bundle; } public string GetBundleName(string assetName) { string bundleName; FileMapping.TryGetValue(assetName, out bundleName); return bundleName; } public string BundleContent(string resName) { string bundleName = GetBundleName(resName); if (bundleName == null) return null; AssetBundle bundle = LoadBundle(bundleName); if (bundle == null) return null; TextAsset text = bundle.LoadAsset(resName); if (text == null) return null; return text.text; } /// /// 根据Resources/bundles.manifest读取本地bundle数据 /// private void LoadLocalBundlesInfo() { TextAsset manifest = Resources.Load(ManifestFileResName); if(manifest == null) { Debug.LogError("本地Resources目录下没有bundles.manifest"); return; } string[] bundles = manifest.text.Replace("\r", string.Empty).Split('\n'); string[] info; foreach(string bundle in bundles) { info = bundle.Split(','); if (info.Length != 3) continue; BundleInfo bi = new BundleInfo(); bi.size = long.Parse(info[1]); bi.hash = info[2]; localBundles.Add(info[0], bi); } } IEnumerator DownloadManifest() { WWW www = new WWW(cdnAddress + ManifesteRemotePath); while(!www.isDone) { yield return Timing.WaitForSeconds(0.01f); } string content = www.text; string[] bundles = content.Replace("\r", string.Empty).Split('\n'); string[] info; foreach (string bundle in bundles) { info = bundle.Split(','); if (info.Length != 3) continue; BundleInfo bi = new BundleInfo(); bi.size = long.Parse(info[1]); bi.hash = info[2]; remoteBundles.Add(info[0], bi); } // Download bundles Timing.Instance.RunCoroutineOnInstance(DownloadBundles()); } IEnumerator DownloadBundles() { List downloadBundles = new List(); foreach(var b in remoteBundles) { string bundleName = b.Key; long size = b.Value.size; string hash = b.Value.hash; BundleInfo localInfo; //1. 剔除首包中就有的 if (localBundles.TryGetValue(bundleName, out localInfo) && localInfo.hash == hash) continue; //2. 剔除上次小版本更新下载下来的 string persistentPath = PathHelper.GetPersistentFullFilePath(BundleRoot + "/" + bundleName); if(File.Exists(persistentPath)) { long lastsize = new FileInfo(persistentPath).Length; if(lastsize == size) { string lasthash = FileUtil.GetMD5Hash(persistentPath); if (lasthash == "") { Debug.LogError("计算md5出错"); } else if (lasthash == hash) continue; } } downloadBundles.Add(bundleName); } //3. 下载 foreach (string bundle in downloadBundles) { WWW www = new WWW(cdnAddress + bundle); while(!www.isDone) { yield return Timing.WaitForSeconds(0.01f); } // save to persistentDataPath Print("->下载" + bundle + "完毕"); byte[] data = www.bytes; string folder = PathHelper.GetPersistentFullFilePath(BundleRoot); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); File.WriteAllBytes(folder + "/" + bundle, data); } Print("Bundle 下载完毕,共下载" + downloadBundles.Count + "个"); Print("------------------------------------------------------------------------"); // test test ResManager.Instance.ReadFileMapping(); ResManager.Instance.LoadManifest(); // Done OnDownloaded(); } void OnDownloaded() { if (test != null) test.Testing(); } }