using System; using System.Collections; using System.Collections.Generic; using System.IO; using AssetManagement; using AssetUpdate; using GCGame.Table; using Module.Log; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using System.Linq; using Object = UnityEngine.Object; #if UNITY_EDITOR using UnityEditor; using System.Runtime.Serialization.Formatters.Binary; #endif public class LoadAssetBundle : MonoBehaviour { #region Load Asset - 加载资源包的主体 public const string atlasPathConvertTable = "AtlasPathConvert"; public const string BUNDLE_MAIN_BASE_UI = "MainBase"; public const string BUNDLE_PATH_MODEL = "model/"; public const string BUNDLE_PATH_PET = "model/"; public const string BUNDLE_PATH_EFFECT = "effect/"; public const string BUNDLE_PATH_UI = "ui/"; public const string BUNDLE_PATH_SOUND = "sounds/"; public const string BUNDLE_PATH_SPRITE = "ui/sprite/commonitem"; public const string BUNDLE_PATH_Other = "other/"; public const string bundleFileExtension = AssetConst.bundleVariant; public const string BUNDLE_PATH_GAMERES = "gameres"; // 无用的Bundle,仅仅用于打包时,让Unity可以正常收集Shader之类的资源引用 public const string BUNDLE_PATH_DUMMY = "dummy"; // CommonItem的Bundle名称 - 原位于Editor程序集ClassifyBundles public const string uiCommonSpriteBundle = uiSpriteBundleHeader + "commonitem"; // Sprite类Bundle名称头 - 原位于Editor程序集ClassifyBundles public const string uiSpriteBundleHeader = "ui/sprite/"; private readonly LoadAssetRequestList _gameObjectList = new LoadAssetRequestList(); private readonly LoadAssetRequestList _assetList = new LoadAssetRequestList(); private readonly LoadAssetRequestList _audioList = new LoadAssetRequestList(); private readonly LoadAssetRequestList _textAssetList = new LoadAssetRequestList(); private readonly LoadSpriteRequestList _spriteList = new LoadSpriteRequestList(); private readonly LoadRawImageRequestList _rawImageList = new LoadRawImageRequestList(); public AssetPathHub pathHub { get; private set; } // Use this for initialization private void Awake() { Instance = this; if (!AssetUpdateManager.useResources) { // 暂时不考虑动态切换资源路径的流程,需要再处理类型情况 pathHub = new AssetPathHub(); // 加载全部资源资料 string uri; if (string.IsNullOrEmpty(AssetUpdateManager.assetUri)) { Debug.LogError("Cannot find assetInfo. You should start the game from AssetUpdate instead of Login!"); // 这个问题无法正确恢复,仅仅测试版本可以继续使用本地资源 uri = string.Empty; } else { uri = AssetUpdateManager.assetUri; } var dependencyPath = AssetConst.persistentDataPath.Open(AssetUtils.GetTextMd5(AssetConst.versionFile) + AssetConst.bundleVariant); AssetDependencyInfo dependencyInfo = null; if (!File.Exists(dependencyPath)) { Debug.LogError( "Cannot find dependency file. You should start the game from AssetUpdate instead of Login!"); } else dependencyInfo = AssetDependencyInfo.Create(dependencyPath); Debug.Log("LoaderAssetsBundle"); if (dependencyInfo == null) { Debug.LogError("Unable to load dependency file! This is not recoverable!"); LiteConfirmWin.Open("资源错误", "无法加载资源依赖!\n需要重启游戏修复!", new LiteConfirmButtonData("确定", () => SdkControl.instance.CloseGame())); } else { pathHub.Init(uri, dependencyInfo); var loadHub = new BundleLoadHub(); // 暂时限制到同时5个并行加载 loadHub.Init(pathHub, new List { new AsyncLoadRule(int.MaxValue, 5) }); var downloadHub = new BundleDownloadHub(); // 后台下载限制到最大一个;主动加载限制到最大三个; downloadHub.Init(pathHub, new List { new AsyncLoadRule(0, 1), new AsyncLoadRule(int.MaxValue, 3) }); downloadHub.onComplete += pathHub.DownloadComplete; // 注:BundleManager需要在PathHub绑定后执行初始化,否则无法正确更新PathData var bundleManager = new BundleManager(pathHub, loadHub, downloadHub); if (AssetManager.instance == null) AssetManager.CreateInstance(); var assetManager = AssetManager.instance; // ReSharper disable once PossibleNullReferenceException assetManager.Init(bundleManager); } } DontDestroyOnLoad(gameObject); } public void StartBackGround() { if (!AssetUpdateManager.useResources) AssetManager.instance.bundleManager.downloadHub.StartBackGroundDownload(); } public static void CreateInstance() { var loadObject = new GameObject("LoadAssetBundle"); loadObject.AddComponent(); } public void ClearCallbacks() { _gameObjectList.Clear(); _assetList.Clear(); _audioList.Clear(); _textAssetList.Clear(); _spriteList.Clear(); _rawImageList.Clear(); } private bool IsBundleAndAssetValid(string bundleName, string assetName) { return !string.IsNullOrEmpty(bundleName) && !string.IsNullOrEmpty(assetName) && !bundleName.Equals("-1") && !assetName.Equals("-1"); } private void LoadAssetFromList(string bundleName, string assetName, LoadBundleAssetCallback callback, Hashtable hashtable, LoadAssetRequestList list, bool archive) where T : Object { // 已知问题,即使已经加载的资源,仍然会产生一次列表推入和回调监听,造成少量性能浪费 // 暂时不修改这个结构,保持当前强健的逻辑流程 list.AddCallback(bundleName, assetName, callback, hashtable); LoadAssetInternal(bundleName, assetName); } private void RemoveAllCallback(string bundleName, string assetName) { _gameObjectList.RemoveAllCallback(bundleName, assetName); _assetList.RemoveAllCallback(bundleName, assetName); _audioList.RemoveAllCallback(bundleName, assetName); _textAssetList.RemoveAllCallback(bundleName, assetName); _spriteList.RemoveAllCallback(bundleName, assetName); _rawImageList.RemoveAllCallback(bundleName, assetName); } public void LoadGameObject(string bundleName, string assetName, LoadBundleAssetCallback callback, Hashtable hashParam, bool archive = false) { if (IsBundleAndAssetValid(bundleName, assetName)) { bundleName += assetName; bundleName = FixBundleName(bundleName); LoadAssetFromList(bundleName, assetName, callback, hashParam, _gameObjectList, archive); } } public void LoadAsset(string bundleName, string assetName, LoadBundleAssetCallback callback, Hashtable hashParam, bool archive = false) { if (IsBundleAndAssetValid(bundleName, assetName)) { bundleName = FixBundleName(bundleName); LoadAssetFromList(bundleName, assetName, callback, hashParam, _assetList, archive); } } public void RemoveAssetCallback(string bundleName, string assetName, LoadBundleAssetCallback callback) { if (IsBundleAndAssetValid(bundleName, assetName)) { bundleName = FixBundleName(bundleName); _assetList.RemoveCallback(bundleName, assetName, callback); } } /// /// GameObject加载需求的析构接口,因为会修改AssetBundle名称,使用一个统一接口 /// public void UnloadAssetWithPathFix(string bundleName, string assetName) { if (!AssetUpdateManager.useResources && IsBundleAndAssetValid(bundleName, assetName)) { bundleName = bundleName + assetName; bundleName = FixBundleName(bundleName); RemoveAllCallback(bundleName, assetName); AssetManager.instance.RemoveAsset(bundleName, assetName); } } /// /// GameObject加载需求的析构接口,不会修改bundleName,因此不要给会用资源名校正包名资源的使用 /// public void UnloadAsset(string bundleName, string assetName) { if (!AssetUpdateManager.useResources && IsBundleAndAssetValid(bundleName, assetName)) { bundleName = FixBundleName(bundleName); RemoveAllCallback(bundleName, assetName); AssetManager.instance.RemoveAsset(bundleName, assetName); } } public void LoadUI(string bundleName, string assetName, LoadBundleAssetCallback callback, Hashtable hashParam, bool archive = true) { if (IsBundleAndAssetValid(bundleName, assetName)) { bundleName = FixBundleName(bundleName); LoadAssetFromList(bundleName, assetName, callback, hashParam, _gameObjectList, archive); } } public void LoadSoundAsync(string bundlePath, string assetName, LoadBundleAssetCallback callback, Hashtable hashParam) { if (!string.IsNullOrEmpty(assetName)) if (IsBundleAndAssetValid(bundlePath, assetName)) { bundlePath = FixBundleName(bundlePath); LoadAssetFromList(bundlePath, assetName, callback, hashParam, _audioList, true); } } public void SetRawTexture(RawImage image, string assetName, string bundleName) { var valid = false; if (image != null) { if (image.texture == null) { image.enabled = false; valid = true; } else { valid = !image.texture.name.Equals(assetName); } } if (valid && IsBundleAndAssetValid(bundleName, assetName)) { bundleName = FixBundleName(bundleName); _rawImageList.AddCallback(bundleName, assetName, image); LoadAssetInternal(bundleName, assetName); } } public void SetImageSprite(Image image, string assetName, LoadSpritesCallback callback = null) { var valid = false; if (image != null) { if (image.sprite == null) { image.enabled = false; valid = true; } else { valid = !image.sprite.name.Equals(assetName); } } if (valid && IsBundleAndAssetValid(BUNDLE_PATH_SPRITE, assetName)) { // 试图校正精灵包名 var bundleName = GetAtlasBundleName(BUNDLE_PATH_SPRITE, assetName); _spriteList.AddCallback(bundleName, assetName, image, callback); LoadAssetInternal(bundleName, assetName); } } /// /// 统一使用一个接口来处理修复Bundle名称之类的问题 /// private void LoadAssetInternal(string bundleName, string assetName) where T : Object { #if UNITY_EDITOR if (AssetUpdateManager.useResources) LoadForSimulateMode(bundleName, assetName, typeof(T)); else #endif AssetManager.instance.LoadAsset(bundleName, assetName, this, OnAssetLoadedFinish); } private void OnAssetLoadedFinish(string bundleName, string assetName, T asset) where T : Object { _gameObjectList.FinishAsset(bundleName, assetName, asset); _assetList.FinishAsset(bundleName, assetName, asset); _audioList.FinishAsset(bundleName, assetName, asset); _textAssetList.FinishAsset(bundleName, assetName, asset); _spriteList.FinishAsset(bundleName, assetName, asset); _rawImageList.FinishAsset(bundleName, assetName, asset); } #if UNITY_EDITOR [Serializable] public class EditorBundleList { private readonly Dictionary _assetDataList = new Dictionary(); public EditorBundleList(IEnumerable assets) { foreach (var asset in assets) { _assetDataList[Path.GetFileName(asset).ToLower()] = asset; } } public string GetAssetPath(string assetName) { string result; if (!_assetDataList.TryGetValue(assetName, out result)) result = string.Empty; return result; } } private class EditorResourceAsync { public readonly string bundleName; public readonly string assetName; public readonly AsyncOperation operation; public EditorResourceAsync(string bundleName, string assetName, AsyncOperation operation) { this.bundleName = bundleName; this.assetName = assetName; this.operation = operation; } } public const string assetPathHeader = "Assets/Project3D/Resources"; public const string uiSpriteAssetPath = "Assets/Project3D/Sprites"; public const string bundleToAssetPath = "Assets/Editor/Config/BundleToAsset" + AssetConst.bytesExtension; private Dictionary _uiCommonPathDict; private Dictionary _resourcesDict; private const int _maxAsyncCount = 1; private readonly List _asyncList = new List(); private readonly Queue> _pendingList = new Queue>(); private void OnResourcesLoad(AsyncOperation operation) { var resourceRequest = operation as ResourceRequest; if (resourceRequest != null) { for (var i = _asyncList.Count - 1; i >= 0; i--) { var async = _asyncList[i]; if (async.operation == operation) { _asyncList.RemoveAt(i); OnAssetLoadedFinish(async.bundleName, async.assetName, resourceRequest.asset); } } while (_asyncList.Count < _maxAsyncCount && _pendingList.Count > 0) { var task = _pendingList.Dequeue(); StartResourceLoad(task.first, task.second); } } } private void StartResourceLoad(string bundleName, string assetName) { if (_resourcesDict == null) { var dataPath = Application.dataPath.MoveUp().Open(bundleToAssetPath); if (File.Exists(dataPath)) { var bitFormatter = new BinaryFormatter(); using (var fs = File.OpenRead(dataPath)) _resourcesDict = bitFormatter.Deserialize(fs) as Dictionary; } if (_resourcesDict == null) _resourcesDict = new Dictionary(); } EditorBundleList list; if (!_resourcesDict.TryGetValue(bundleName, out list)) { var assets = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName + AssetConst.bundleVariant) .Where(a => a.StartsWith(assetPathHeader)) .Select(a => a.RemoveExtension().Substring(assetPathHeader.Length + 1)).ToArray(); if (assets.Length > 0) { list = new EditorBundleList(assets); _resourcesDict[bundleName] = list; var bitFormatter = new BinaryFormatter(); var dataPath = Application.dataPath.MoveUp().Open(bundleToAssetPath); using (var fs = File.OpenWrite(dataPath)) bitFormatter.Serialize(fs, _resourcesDict); } } var path = list != null ? list.GetAssetPath(assetName.ToLower()) : string.Empty; if (string.IsNullOrEmpty(path)) { Debug.LogError(string.Format("Unable to load asset {0} from bundle {1}!", assetName, bundleName)); // ReSharper disable once ExpressionIsAlwaysNull OnAssetLoadedFinish(bundleName, assetName, default(Object)); } else { var request = Resources.LoadAsync(path); _asyncList.Add(new EditorResourceAsync(bundleName, assetName, request)); request.completed += OnResourcesLoad; } } private void LoadForSimulateMode(string bundleName, string assetName, Type assetType) { Object asset = null; // 2019.03.01 不再试图维护Simulate的流程;uiCommonSprite直接走内置流程。 if (bundleName.StartsWith("ui/sprite/")) { if (_uiCommonPathDict == null) { _uiCommonPathDict = new Dictionary(); var uiCommonPaths = from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(uiSpriteAssetPath) where !string.IsNullOrEmpty(Path.GetExtension(assetPath)) select assetPath; foreach (var uiPath in uiCommonPaths) { var key = Path.GetFileNameWithoutExtension(uiPath).ToLower(); if (_uiCommonPathDict.ContainsKey(key)) Debug.LogError("Duplicate Key Found for " + uiPath + " and " + _uiCommonPathDict[key]); else _uiCommonPathDict.Add(key, uiPath); } } string path; if (_uiCommonPathDict.TryGetValue(assetName.ToLower(), out path)) asset = AssetDatabase.LoadAssetAtPath(path, assetType); else Debug.LogError("No Path for item " + assetName.ToLower()); OnAssetLoadedFinish(bundleName, assetName, asset); } else { var callBack = _asyncList.Find(a => a.bundleName == bundleName && a.assetName == assetName); if (callBack == null) { if (_asyncList.Count < _maxAsyncCount) StartResourceLoad(bundleName, assetName); else _pendingList.Enqueue(new MyTuple(bundleName, assetName)); } } } #endif #endregion #region load init public static LoadAssetBundle Instance { get; private set; } // public void UnloadBundle(string bundleName) // { // Debug.Log("Unload Bundle: " + bundleName); // if (!AssetUpdateManager.useResources) // { // bundleName = FixBundleName(bundleName); // AssetManager.instance.RemovePreload(bundleName); // } // } /// /// 统一处理一些AssetBundle后缀名称问题 /// public static string FixBundleName(string bundleName) { // var extension = Path.GetExtension(); // if (string.IsNullOrEmpty(extension)) // { // bundleName += bundleFileExtension; // } // else if (!extension.Equals(bundleFileExtension, StringComparison.CurrentCultureIgnoreCase)) // { // bundleName = bundleName.Remove(bundleName.Length - extension.Length); // bundleName += bundleFileExtension; // } return bundleName.RemoveExtension().ToLower(); } // /// // /// 加载一个AssetBundle,如果Bundle已经加载就返回true // /// // private void LoadOneAssetBundle(string bundleName) // { // bundleName = FixBundleName(bundleName); // AssetManager.instance.Preload(bundleName, this, OnAssetBundleLoaded); // } #endregion #region 预加载过场动画 /// /// 预加载场景电影Bundle /// private readonly List _movieId = new List(); private string _preloadScene; private static string GetMovieName(int movieId) { var movieName = string.Empty; if (movieId >= 0) { var movieData = TableManager.GetSceneMovieByID(movieId); if (movieData != null) { var profession = GameManager.gameManager.PlayerDataPool.MainPlayerBaseAttr.Profession; movieName = movieData.GetResPathbyIndex(profession); } } return movieName; } private void AddMoviePreload(int movieId) { var movieName = GetMovieName(movieId); if (!string.IsNullOrEmpty(movieName)) Instance.LoadGameObject(BUNDLE_PATH_MODEL, movieName, null, null); } private void RemoveMoviePreload(int movieId) { var movieName = GetMovieName(movieId); if (!string.IsNullOrEmpty(movieName)) { var bundleName = BUNDLE_PATH_MODEL + movieName; bundleName = FixBundleName(bundleName); Instance.UnloadAsset(bundleName, movieName); } } public void StartPreloadScene(string sceneName, int movieId) { #if UNITY_EDITOR if (AssetUpdateManager.useResources) return; #endif sceneName = GetSceneBundleName(sceneName); // 如果场景对不上,则卸载之前的场景预加载 var loadScene = _preloadScene != sceneName; if (loadScene) { if (!string.IsNullOrEmpty(_preloadScene)) CleanPreloadScene(); _preloadScene = sceneName; } if (!_movieId.Contains(movieId)) AddMoviePreload(movieId); } public void CleanPreloadScene() { _preloadScene = string.Empty; foreach (var id in _movieId) RemoveMoviePreload(id); _movieId.Clear(); } #endregion #region loadScene /// /// 是否允许加载场景 /// // 注:如果当前有其他SceneLoadOperaction,则不允许继续加载场景 public bool AllowLoadScene() { return !AssetManager.instance.IsLoadingScene(); } public static string GetSceneBundleName(string sceneName) { var bundleName = "scene/" + sceneName; bundleName = FixBundleName(bundleName); return bundleName; } public void UnloadMainScene() { if (!AssetUpdateManager.useResources) AssetManager.instance.UnloadAllScene(); } /// /// 加载主要场景 - 主要场景加载时,会卸载之前的主要场景 /// public bool LoadMainScene(string assetName, LoadSceneMode mode, out SceneHandle loadHandle) { bool load; if (AssetUpdateManager.useResources) { load = true; loadHandle = null; SceneManager.LoadScene(assetName); } else { var bundleName = GetSceneBundleName(assetName); var current = AssetManager.instance.GetCurrentSceneHandle(); load = current == null || current.sceneName == assetName; if (!load) load = AllowLoadScene(); loadHandle = load ? AssetManager.instance.LoadScene(bundleName, assetName, mode, allowReload: true) : null; } return load; } #endregion #region loadGameRes public static string gameResBundleName { get { return FixBundleName(BUNDLE_PATH_GAMERES); } } #endregion #region LoadTable private const string _tableBundleName = "tables"; public TextAsset LoadTableAsset(string tableName) { return LoadTextAsset(_tableBundleName, tableName); } #if UNITY_EDITOR public const string tablePath = "Assets/Project3D/BundleData/Tables3D/"; private Dictionary _luaFiles; #endif private TextAsset LoadTextAsset(string bundleName, string assetName) { TextAsset result = null; #if UNITY_EDITOR if (AssetUpdateManager.useResources) { if (bundleName == _scriptBundleName) { if (_luaFiles == null) { _luaFiles = new Dictionary(); var luaPath = "Assets".Open("Project").Open("Script").Open("LuaScripts") + '/'; var scripts = AssetDatabase.GetAllAssetPaths().Where(a => a.StartsWith(luaPath)) .Where(a => AssetConst.textExtension.Equals(Path.GetExtension(a))); foreach (var script in scripts) _luaFiles.Add(Path.GetFileNameWithoutExtension(script).ToLower(), script); } string path; if (_luaFiles.TryGetValue(assetName.ToLower(), out path)) result = AssetDatabase.LoadAssetAtPath(path); } else if (bundleName == _tableBundleName) { var extension = string.Equals(assetName, atlasPathConvertTable, StringComparison.Ordinal) ? AssetConst.bytesExtension : AssetConst.textExtension; result = AssetDatabase.LoadAssetAtPath(tablePath + assetName + extension); } else Debug.LogError(string.Format("Unable to load TextAsset {1} from bundle {0}!", bundleName, assetName)); return result; } #endif if (AssetManager.instance == null) { throw new Exception("AssetManager is not initialized!"); } result = AssetManager.instance.LoadAssetSync(bundleName, assetName); return result; } #endregion #region LoadScript // 注:之前逻辑是和LoadTable在一起,但是没有监听过这个AssetBundle是否加载结束的 // 暂时保持接口和调用处不变 private const string _scriptBundleName = "script"; public TextAsset LoadScriptAsset(string script) { return LoadTextAsset(_scriptBundleName, script); } #endregion #region Atlas Path Convert private Dictionary _pathConvertDict; private void CreateAtlasConvert() { _pathConvertDict = new Dictionary(); var lines = AssetUtils.TextToLines(LoadTableAsset(atlasPathConvertTable).text); foreach (var line in lines) { if (!string.IsNullOrEmpty(line)) { var keyValue = line.Split('\t'); _pathConvertDict[keyValue[0]] = keyValue[1]; } } } private string GetAtlasBundleName(string bundleName, string assetName) { if (_pathConvertDict == null) CreateAtlasConvert(); string newName; if (_pathConvertDict.TryGetValue(assetName.ToLower(), out newName)) bundleName = newName; else { LogModule.ErrorLog(string.Format( "Try to load asset {0} from {1}, while Asset Load Manager hasn't init path conversion yet!", assetName, bundleName)); } return bundleName; } #endregion } #region Load Asset Data public delegate void LoadSpritesCallback(bool isSucess, GameObject obj); public delegate void LoadBundleAssetCallback(string assetName, T assetItem, Hashtable hashTable) where T : Object; public delegate void LoadAssetBundleFinish(string bundleName); public abstract class LoadAssetRequestBase { public readonly string assetName; public readonly string bundleName; protected LoadAssetRequestBase(string bundleName, string assetName) { this.bundleName = bundleName; this.assetName = assetName; } } public static class LoadAssetRequestMethods { public static int GetIndexFromList(this List requestList, string bundleName, string assetName) where T : LoadAssetRequestBase { var result = -1; for (var i = 0; i < requestList.Count; i++) if (requestList[i].bundleName.Equals(bundleName, StringComparison.OrdinalIgnoreCase) && requestList[i].assetName.Equals(assetName, StringComparison.Ordinal)) { result = i; break; } return result; } } public class LoadRawImageRequest : LoadAssetRequestBase { public readonly List rawImageList = new List(); public LoadRawImageRequest(string bundleName, string assetName) : base(bundleName, assetName) { } public void AddCallback(RawImage rawImage) { if (!rawImageList.Contains(rawImage)) rawImageList.Add(rawImage); } public void RemoveCallback(RawImage rawImage) { rawImageList.Remove(rawImage); } public void FinishAsset(Object asset) { var texture = asset as Texture; for (var i = 0; i < rawImageList.Count; i++) if (rawImageList[i]) { rawImageList[i].texture = texture; rawImageList[i].enabled = true; } } } public class LoadSpriteRequest : LoadAssetRequestBase { public readonly List> callBackList = new List>(); public LoadSpriteRequest(string bundleName, string assetName) : base(bundleName, assetName) { } public void AddCallback(Image image, LoadSpritesCallback callback) { var index = GetCallBackIndex(image); if (index >= 0) callBackList[index].second = callback; else callBackList.Add(new MyTuple(image, callback)); } public void RemoveCallback(Image image) { var index = GetCallBackIndex(image); if (index >= 0) callBackList.RemoveAt(index); } private int GetCallBackIndex(Image image) { var result = -1; for (var i = 0; i < callBackList.Count; i++) if (callBackList[i].first == image) { result = i; break; } return result; } public void FinishAsset(Object asset) { var sprite = asset as Sprite; for (var i = 0; i < callBackList.Count; i++) if (callBackList[i].first) { callBackList[i].first.sprite = sprite; callBackList[i].first.enabled = true; if (callBackList[i].second != null) callBackList[i].second.Invoke(true, callBackList[i].first.gameObject); } } } public class LoadAssetRequest : LoadAssetRequestBase where T : Object { public readonly List, Hashtable>> callBackList = new List, Hashtable>>(); public LoadAssetRequest(string bundleName, string assetName) : base(bundleName, assetName) { } public void AddCallback(LoadBundleAssetCallback callback, Hashtable hashTable) { var index = GetCallbackIndex(callback); if (index < 0) callBackList.Add(new MyTuple, Hashtable>(callback, hashTable)); else callBackList[index].second = hashTable; } public void RemoveCallback(LoadBundleAssetCallback callback) { var index = GetCallbackIndex(callback); if (index >= 0) callBackList.RemoveAt(index); } private int GetCallbackIndex(LoadBundleAssetCallback callback) { var result = -1; for (var i = 0; i < callBackList.Count; i++) if (callBackList[i].first == callback) { result = i; break; } return result; } public void FinishAsset(Object asset) { var item = asset as T; for (var i = 0; i < callBackList.Count; i++) if (callBackList[i].first != null) callBackList[i].first.Invoke(assetName, item, callBackList[i].second); } } public class LoadRawImageRequestList { private readonly List _callbackList = new List(); public void AddCallback(string bundleName, string assetName, RawImage rawImage) { var index = _callbackList.GetIndexFromList(bundleName, assetName); LoadRawImageRequest request; if (index < 0) { request = new LoadRawImageRequest(bundleName, assetName); _callbackList.Add(request); } else { request = _callbackList[index]; } request.AddCallback(rawImage); } public void RemoveCallback(string bundleName, string assetName, RawImage rawImage) { var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) { _callbackList[index].RemoveCallback(rawImage); if (_callbackList[index].rawImageList.Count <= 0) _callbackList.RemoveAt(index); } } public void RemoveAllCallback(string bundleName, string assetName) { var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) _callbackList.RemoveAt(index); } public void FinishAsset(string bundleName, string assetName, Object asset) { // 这个接收底层回调的消息,不会出现名字错误的问题 var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) { var item = _callbackList[index]; _callbackList.RemoveAt(index); item.FinishAsset(asset); } } public void Clear() { _callbackList.Clear(); } } public class LoadSpriteRequestList { private readonly List _callbackList = new List(); public void AddCallback(string bundleName, string assetName, Image image, LoadSpritesCallback callback) { bundleName = LoadAssetBundle.FixBundleName(bundleName); var index = _callbackList.GetIndexFromList(bundleName, assetName); LoadSpriteRequest request; if (index < 0) { request = new LoadSpriteRequest(bundleName, assetName); _callbackList.Add(request); } else { request = _callbackList[index]; } request.AddCallback(image, callback); } public void RemoveCallback(string bundleName, string assetName, Image image) { bundleName = LoadAssetBundle.FixBundleName(bundleName); var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) { _callbackList[index].RemoveCallback(image); if (_callbackList[index].callBackList.Count <= 0) _callbackList.RemoveAt(index); } } public void RemoveAllCallback(string bundleName, string assetName) { bundleName = LoadAssetBundle.FixBundleName(bundleName); var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) _callbackList.RemoveAt(index); } public void FinishAsset(string bundleName, string assetName, Object asset) { // 这个接收底层回调的消息,不会出现名字错误的问题 var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) { var item = _callbackList[index]; _callbackList.RemoveAt(index); item.FinishAsset(asset); } } public void Clear() { _callbackList.Clear(); } } public class LoadAssetRequestList where T : Object { private readonly List> _callbackList = new List>(); public void AddCallback(string bundleName, string assetName, LoadBundleAssetCallback callback, Hashtable hashTable) { var index = _callbackList.GetIndexFromList(bundleName, assetName); LoadAssetRequest request; if (index < 0) { request = new LoadAssetRequest(bundleName, assetName); _callbackList.Add(request); } else { request = _callbackList[index]; } request.AddCallback(callback, hashTable); } public void RemoveCallback(string bundleName, string assetName, LoadBundleAssetCallback callback) { var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) { _callbackList[index].RemoveCallback(callback); if (_callbackList[index].callBackList.Count <= 0) _callbackList.RemoveAt(index); } } public void RemoveAllCallback(string bundleName, string assetName) { var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) _callbackList.RemoveAt(index); } public void FinishAsset(string bundleName, string assetName, Object asset) { // 这个接收底层回调的消息,不会出现名字错误的问题 var index = _callbackList.GetIndexFromList(bundleName, assetName); if (index >= 0) { var item = _callbackList[index]; _callbackList.RemoveAt(index); item.FinishAsset(asset); } } public void Clear() { _callbackList.Clear(); } } /// /// 部分系统会需要穿越Asset级别,直接操作AssetBundle,保留这么一个回调 /// public class LoadWholeBundleRequest { public readonly List callbackList = new List(); public readonly string name; public LoadWholeBundleRequest(string bundleName) { name = bundleName; } public void AddCallback(LoadAssetBundleFinish callback) { if (!callbackList.Contains(callback)) callbackList.Add(callback); } public void RemoveCallback(LoadAssetBundleFinish callback) { callbackList.Remove(callback); } public void FinishAssetBundleLoad() { for (var i = 0; i < callbackList.Count; i++) try { if (callbackList[i] != null) callbackList[i].Invoke(name); } catch (Exception e) { LogModule.ErrorLog(e.ToString()); } } } // public class LoadWholeBundleList // { // private readonly List _callbackList = new List(); // // public void AddCallback(string bundleName, LoadAssetBundleFinish callback) // { // var index = GetCallbackIndex(bundleName); // LoadWholeBundleRequest request; // if (index < 0) // { // request = new LoadWholeBundleRequest(bundleName); // _callbackList.Add(request); // } // else // { // request = _callbackList[index]; // } // // request.AddCallback(callback); // } // // public void RemoveCallback(string bundleName, LoadAssetBundleFinish callback) // { // var index = GetCallbackIndex(bundleName); // if (index >= 0) // { // _callbackList[index].RemoveCallback(callback); // if (_callbackList[index].callbackList.Count <= 0) // _callbackList.RemoveAt(index); // } // } // // public void FinishBundle(string bundleName) // { // var index = GetCallbackIndex(bundleName); // if (index >= 0) // { // var item = _callbackList[index]; // _callbackList.RemoveAt(index); // item.FinishAssetBundleLoad(); // } // } // // private int GetCallbackIndex(string bundleName) // { // var index = -1; // for (var i = 0; i < _callbackList.Count; i++) // if (_callbackList[i].name.Equals(bundleName, StringComparison.OrdinalIgnoreCase)) // { // index = i; // break; // } // // return index; // } // // public void Clear() // { // _callbackList.Clear(); // } // } #endregion