using System; using System.Collections.Generic; using System.IO; using UnityEngine; namespace XUtliPoolLib { public class AssetBundleManager : MonoBehaviour { public int BundleCount { get { return this._bundleCount; } } public AssetBundleDataReader depInfoReader { get { return this._depInfoReader; } } public bool isCurrentLoading { get { return this._isCurrentLoading; } } public static Version version = new Version(0, 1, 0); public static AssetBundleManager Instance; public static string NAME = "AssetBundleManager"; public static bool enableLog = false; private const int MAX_REQUEST = 100; private int _requestRemain = 100; private Queue _requestQueue = new Queue(); private List _currentLoadQueue = new List(); private HashSet _nonCompleteLoaderSet = new HashSet(); private HashSet _thisTimeLoaderSet = new HashSet(); private Dictionary _loadedAssetBundle = new Dictionary(); private Dictionary _loaderCache = new Dictionary(); private bool _isCurrentLoading; private Queue _requestUnloadBundleQueue = new Queue(); private AssetBundleLoadProgress _progress = new AssetBundleLoadProgress(); public AssetBundleManager.LoadProgressHandler onProgress; public AssetBundlePathResolver pathResolver; private AssetBundleDataReader _depInfoReader; private int _bundleCount = 0; private uint _defaultHash = 0u; public delegate void LoadAssetCompleteHandler(AssetBundleInfo info, int handlerID); public delegate void LoaderCompleteHandler(AssetBundleLoader info); public delegate void LoadProgressHandler(AssetBundleLoadProgress progress); public AssetBundleManager() { AssetBundleManager.Instance = this; this.pathResolver = new AssetBundlePathResolver(); this._defaultHash = XSingleton.singleton.XHashLowerRelpaceDot(0u, "Assets.Resources."); } protected void Awake() { base.InvokeRepeating("CheckUnusedBundle", 0f, 5f); } public void Init() { this.RemoveAll(); this.LoadDepInfo(); } public void Init(byte[] data, Action callback) { bool flag = data.Length > 4; if (flag) { XBinaryReader xbinaryReader = XBinaryReader.Get(); xbinaryReader.InitByte(data, 0, 0); bool flag2 = xbinaryReader.ReadChar() == 'A' && xbinaryReader.ReadChar() == 'B' && xbinaryReader.ReadChar() == 'D'; if (flag2) { bool flag3 = xbinaryReader.ReadChar() == 'T'; if (flag3) { this._depInfoReader = new AssetBundleDataReader(); } else { this._depInfoReader = new AssetBundleDataBinaryReader(); } this._depInfoReader.Read(xbinaryReader); } XBinaryReader.Return(xbinaryReader, false); } bool flag4 = callback != null; if (flag4) { callback(); } } private void LoadDepInfo() { string path = string.Format("{0}/{1}", this.pathResolver.BundleCacheDir, this.pathResolver.DependFileName); bool flag = File.Exists(path); if (flag) { this.Init(File.ReadAllBytes(path), null); } else { TextAsset textAsset = Resources.Load("dep"); bool flag2 = textAsset != null; if (flag2) { this.Init(textAsset.bytes, null); Resources.UnloadAsset(textAsset); } else { XSingleton.singleton.AddErrorLog("depFile not exist!", null, null, null, null, null); } } } private void OnDestroy() { this.RemoveAll(); } public AssetBundleLoader Load(uint hash, string path, string suffix, string prefix = null, AssetBundleManager.LoadAssetCompleteHandler handler = null, int handlerID = -1) { bool flag = this.depInfoReader == null; AssetBundleLoader result; if (flag) { result = null; } else { AssetBundleLoader assetBundleLoader = this.CreateLoader(hash, path, suffix, prefix); bool flag2 = assetBundleLoader == null; if (flag2) { result = null; } else { assetBundleLoader.loadHandlerID = handlerID; this._thisTimeLoaderSet.Add(assetBundleLoader); bool isComplete = assetBundleLoader.isComplete; if (isComplete) { bool flag3 = handler != null; if (flag3) { handler(assetBundleLoader.bundleInfo, handlerID); } } else { bool flag4 = handler != null; if (flag4) { AssetBundleLoader assetBundleLoader2 = assetBundleLoader; assetBundleLoader2.onComplete = (AssetBundleManager.LoadAssetCompleteHandler)Delegate.Combine(assetBundleLoader2.onComplete, handler); } this._isCurrentLoading = true; bool flag5 = assetBundleLoader.state < LoadState.State_LoadingAsync; if (flag5) { this._nonCompleteLoaderSet.Add(assetBundleLoader); } this.StartLoad(); } result = assetBundleLoader; } } return result; } public AssetBundleInfo LoadImm(uint hash, string path, string suffix, string prefix = null) { bool flag = this.depInfoReader == null; AssetBundleInfo result; if (flag) { result = null; } else { AssetBundleLoader assetBundleLoader = this.CreateLoader(hash, path, suffix, prefix); bool flag2 = assetBundleLoader == null; if (flag2) { result = null; } else { this._thisTimeLoaderSet.Add(assetBundleLoader); bool isComplete = assetBundleLoader.isComplete; if (isComplete) { result = assetBundleLoader.bundleInfo; } else { this._isCurrentLoading = true; bool flag3 = assetBundleLoader.state < LoadState.State_Loading; if (flag3) { this._nonCompleteLoaderSet.Add(assetBundleLoader); } this.StartLoadImm(); result = assetBundleLoader.bundleInfo; } } } return result; } public bool CheckInDep(uint hash) { bool flag = this.depInfoReader == null; return !flag && this._depInfoReader.GetAssetBundleInfo(hash) != null; } internal AssetBundleLoader CreateLoader(uint abFileName, string location = null, string suffix = null, string prefix = null) { bool flag = this._loaderCache.ContainsKey(abFileName); AssetBundleLoader assetBundleLoader; if (flag) { assetBundleLoader = this._loaderCache[abFileName]; } else { AssetBundleData assetBundleData = this._depInfoReader.GetAssetBundleInfo(abFileName); bool flag2 = assetBundleData == null; if (flag2) { bool flag3 = prefix != null; uint num; if (flag3) { num = XSingleton.singleton.XHashLowerRelpaceDot(0u, prefix); } else { num = this._defaultHash; } bool flag4 = location != null; if (flag4) { num = XSingleton.singleton.XHashLowerRelpaceDot(num, location); } bool flag5 = suffix != null; if (flag5) { num = XSingleton.singleton.XHashLowerRelpaceDot(num, suffix); } assetBundleData = this._depInfoReader.GetAssetBundleInfoByShortName(num); } bool flag6 = assetBundleData == null; if (flag6) { return null; } assetBundleLoader = this.CreateLoader(); assetBundleLoader.bundleManager = this; assetBundleLoader.bundleData = assetBundleData; assetBundleLoader.bundleName = assetBundleData.fullName; this._loaderCache[abFileName] = assetBundleLoader; } return assetBundleLoader; } protected virtual AssetBundleLoader CreateLoader() { RuntimePlatform platform = Application.platform; AssetBundleLoader result; if ((int)platform != 8) { if ((int)platform != 11) { result = new MobileAssetBundleLoader(); } else { result = new AndroidAssetBundleLoader(); } } else { result = new IOSAssetBundleLoader(); } return result; } private void StartLoad() { bool flag = this._nonCompleteLoaderSet.Count > 0; if (flag) { List list = ListPool.Get(); list.AddRange(this._nonCompleteLoaderSet); this._nonCompleteLoaderSet.Clear(); foreach (AssetBundleLoader item in list) { this._currentLoadQueue.Add(item); } this._progress = new AssetBundleLoadProgress(); this._progress.total = this._currentLoadQueue.Count; foreach (AssetBundleLoader assetBundleLoader in list) { assetBundleLoader.Load(); } ListPool.Release(list); } } private void StartLoadImm() { bool flag = this._nonCompleteLoaderSet.Count > 0; if (flag) { bool flag2 = this._nonCompleteLoaderSet.Count == 1; if (flag2) { HashSet.Enumerator enumerator = this._nonCompleteLoaderSet.GetEnumerator(); enumerator.MoveNext(); this._currentLoadQueue.Add(enumerator.Current); this._nonCompleteLoaderSet.Clear(); this._progress.percent = 0f; this._progress.complete = 0; this._progress.loader = null; this._progress.total = this._currentLoadQueue.Count; enumerator.Current.LoadImm(); } else { List list = ListPool.Get(); list.AddRange(this._nonCompleteLoaderSet); this._nonCompleteLoaderSet.Clear(); foreach (AssetBundleLoader item in list) { this._currentLoadQueue.Add(item); } this._progress.percent = 0f; this._progress.complete = 0; this._progress.loader = null; this._progress.total = this._currentLoadQueue.Count; foreach (AssetBundleLoader assetBundleLoader in list) { assetBundleLoader.LoadImm(); } ListPool.Release(list); } } } public void RemoveAll() { this._currentLoadQueue.Clear(); this._requestQueue.Clear(); foreach (KeyValuePair keyValuePair in this._loadedAssetBundle) { keyValuePair.Value.Dispose(); } this._loadedAssetBundle.Clear(); this._loaderCache.Clear(); this._requestUnloadBundleQueue.Clear(); } public AssetBundleInfo GetBundleInfo(uint key) { foreach (KeyValuePair keyValuePair in this._loadedAssetBundle) { AssetBundleInfo value = keyValuePair.Value; bool flag = value.bundleName == key; if (flag) { return value; } } return null; } internal void RequestLoadBundle(AssetBundleLoader loader) { bool flag = this._requestRemain < 0; if (flag) { this._requestRemain = 0; } bool flag2 = this._requestRemain == 0; if (flag2) { this._requestQueue.Enqueue(loader); } else { this.LoadBundle(loader); } } internal void RequestLoadBundleImm(AssetBundleLoader loader) { bool flag = this._requestRemain < 0; if (flag) { this._requestRemain = 0; } bool flag2 = this._requestRemain == 0; if (flag2) { this._requestQueue.Enqueue(loader); } else { this.LoadBundleImm(loader); } } private void CheckRequestList() { while (this._requestRemain > 0 && this._requestQueue.Count > 0) { AssetBundleLoader loader = this._requestQueue.Dequeue(); this.LoadBundle(loader); } } private void LoadBundle(AssetBundleLoader loader) { bool flag = !loader.isComplete; if (flag) { loader.LoadBundle(); this._requestRemain--; } } private void LoadBundleImm(AssetBundleLoader loader) { bool flag = !loader.isComplete; if (flag) { loader.LoadBundleImm(); this._requestRemain--; } } internal void LoadError(AssetBundleLoader loader) { this.LoadComplete(loader); } internal void LoadComplete(AssetBundleLoader loader) { this._requestRemain++; this._currentLoadQueue.Remove(loader); bool flag = this.onProgress != null; if (flag) { this._progress.loader = loader; this._progress.complete = this._progress.total - this._currentLoadQueue.Count; this.onProgress(this._progress); } bool flag2 = this._currentLoadQueue.Count == 0 && this._nonCompleteLoaderSet.Count == 0; if (flag2) { this._isCurrentLoading = false; foreach (AssetBundleLoader assetBundleLoader in this._thisTimeLoaderSet) { bool flag3 = assetBundleLoader.bundleInfo != null; if (flag3) { assetBundleLoader.bundleInfo.ResetLifeTime(); } } this._thisTimeLoaderSet.Clear(); } else { this.CheckRequestList(); } } internal AssetBundleInfo CreateBundleInfo(AssetBundleLoader loader, AssetBundleInfo abi = null, AssetBundle assetBundle = null) { bool flag = abi == null; if (flag) { abi = new AssetBundleInfo(); } abi.bundleName = loader.bundleName; abi.bundle = assetBundle; abi.data = loader.bundleData; this._loadedAssetBundle[abi.bundleName] = abi; this._bundleCount++; return abi; } public void DeleteBundleCount() { this._bundleCount--; } internal void RemoveBundleInfo(AssetBundleInfo abi) { abi.Dispose(); this._loadedAssetBundle.Remove(abi.bundleName); } private void CheckUnusedBundle() { this.UnloadUnusedBundle(false); } public void UnloadUnusedBundle(bool force = false) { bool flag = (!this._isCurrentLoading && !XSingleton.singleton.isCurrentLoading) || force; bool flag2 = flag; if (flag2) { List list = ListPool.Get(); list.AddRange(this._loadedAssetBundle.Keys); int num = force ? 100000 : 20; int num2 = 0; bool flag3; do { flag3 = false; int num3 = 0; while (num3 < list.Count && flag && num2 < num) { uint key = list[num3]; AssetBundleInfo assetBundleInfo = this._loadedAssetBundle[key]; bool isUnused = assetBundleInfo.isUnused; if (isUnused) { flag3 = true; num2++; this.RemoveBundleInfo(assetBundleInfo); list.RemoveAt(num3); num3--; } num3++; } } while (flag3 && flag && num2 < num); ListPool.Release(list); while (this._requestUnloadBundleQueue.Count > 0 && flag && num2 < num) { AssetBundleInfo assetBundleInfo2 = this._requestUnloadBundleQueue.Dequeue(); bool flag4 = assetBundleInfo2 != null; if (flag4) { assetBundleInfo2.UnloadBundle(); num2++; } } } } public void UnloadNotUsedLoader() { List list = ListPool.Get(); list.AddRange(this._loadedAssetBundle.Keys); List list2 = ListPool.Get(); list2.AddRange(this._nonCompleteLoaderSet); list2.AddRange(this._currentLoadQueue); foreach (AssetBundleLoader assetBundleLoader in list2) { this.RemoveLoadingLoader(assetBundleLoader.bundleName, list); } for (int i = 0; i < list.Count; i++) { AssetBundleInfo abi = this._loadedAssetBundle[list[i]]; this.RemoveBundleInfo(abi); list.RemoveAt(i); i--; } ListPool.Release(list); ListPool.Release(list2); } private void RemoveLoadingLoader(uint hash, List list) { AssetBundleData assetBundleInfo = this._depInfoReader.GetAssetBundleInfo(hash); list.Remove(assetBundleInfo.fullName); bool flag = assetBundleInfo.dependencies != null; if (flag) { for (int i = 0; i < assetBundleInfo.dependencies.Length; i++) { this.RemoveLoadingLoader(assetBundleInfo.dependencies[i], list); } } } public void AddUnloadBundleQueue(AssetBundleInfo info) { this._requestUnloadBundleQueue.Enqueue(info); bool flag = this._requestUnloadBundleQueue.Count > 3; if (flag) { this.UnloadUnusedBundle(false); } } public void RemoveBundle(uint key) { AssetBundleInfo bundleInfo = this.GetBundleInfo(key); bool flag = bundleInfo != null; if (flag) { this.RemoveBundleInfo(bundleInfo); } } } }