Prefab loading ideas

public class LoadPrefabManager : MonoSingleton<LoadPrefabManager>
    {
        #region Contents
        private AssetBundleManifest m_AssetBundleManifest = null;//主菜单
        private HashSet<string> m_LoadingBundles = new HashSet<string>();//加载中的资源
        private Dictionary<string, AssetBundle> m_LoadedBundles = new Dictionary<string, AssetBundle>();//已加载资源
        private Dictionary<string, List<Action<AssetBundle>>> m_InterestedActions = new Dictionary<string, List<Action<AssetBundle>>>();//加载回调
        private Dictionary<string, Dictionary<string, UnityEngine.Object>> m_ObjectsMap = new Dictionary<string, Dictionary<string, UnityEngine.Object>>();
        #endregion

        #region API
        public IEnumerator LoadManifestCoroutine()
        {
            yield return LoadSingleAssetBundle(HotUpdateConfig.StreamingAssets, (assetBundle) =>
            {
                m_AssetBundleManifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
                assetBundle.Unload(false);
            });
        }

        public AssetBundleManifest GetAssetBundleManifest()
        {
            return m_AssetBundleManifest;
        }

        public void LoadPrefab(string prefabName, LuaFunction func)
        {
            LoadPrefab(prefabName, (obj) => 
            {
                if (func != null)
                {
                    func.Call(obj);
                    func.Dispose();
                    func = null;
                }
            });
        }

#if UNITY_EDITOR
        Dictionary<string, string> resourceFilePaths = new Dictionary<string, string>();
        Dictionary<string, GameObject> resourceObjects = new Dictionary<string, GameObject>();
#endif
        /// <summary>
        /// 其它LoadPrefab调用最终来到这里
        /// </summary>
        /// <param name="abName"></param>
        /// <param name="prefabName"></param>
        /// <param name="callback"></param>
        public void LoadPrefab(string prefabName, Action<Object> callback = null)
        {
            #region Get From Resources
#if UNITY_EDITOR
            if (HotUpdateConfig.DEBUG_MODE)
            {
                if (resourceObjects.ContainsKey(prefabName))
                {
                    GameObject gameObj = resourceObjects[prefabName];
                    callback?.Invoke(gameObj);
                    return;
                }
                if (resourceFilePaths.Count <= 0)
                {
                    string[] files1 = System.IO.Directory.GetFiles("Assets/Art/.../...", "*.prefab", SearchOption.AllDirectories);
                    string[] files2 = System.IO.Directory.GetFiles("Assets/Art/.../...", "*.prefab", SearchOption.AllDirectories);
                    for (int i = 0; i < files1.Length; i++)
                    {
                        resourceFilePaths.Add(System.IO.Path.GetFileNameWithoutExtension(files1[i]), files1[i]);
                    }
                    for (int i = 0; i < files2.Length; i++)
                    {
                        resourceFilePaths.Add(System.IO.Path.GetFileNameWithoutExtension(files2[i]), files2[i]);
                    }
                }
                if (resourceFilePaths.ContainsKey(prefabName))
                {
                    string path = resourceFilePaths[prefabName];
                    GameObject prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path);
                    resourceObjects.Add(prefabName, prefab);
                    callback?.Invoke(prefab);
                }
                else
                {
                    callback?.Invoke(null);
                }
                return;
            }
#endif
            #endregion

            if (string.IsNullOrEmpty(prefabName)) { callback?.Invoke(null); return; }
            string abName = AssetBundleMapper.Instance.GetABNameByAssetName(prefabName);
            if (string.IsNullOrEmpty(abName)) { Debug.LogError("No bundle : " + prefabName); callback?.Invoke(null); return; }
            StartCoroutine(LoadObject(abName, prefabName, true, (obj) =>
            {
                callback?.Invoke(obj);
            }));
        }
        #endregion

        #region Internal
        IEnumerator LoadObject(string abName, string objectName, bool withDependencies, Action<UnityEngine.Object> callback)
        {
            if (m_AssetBundleManifest == null)
            {
                Debug.LogError("Manifest not load yet");
            }
            UnityEngine.Object result = GetObjectFromCache(abName, objectName);
            if (result != null)
            {
                callback?.Invoke(result);
                yield break;
            }
            Action<AssetBundle> onCompleted = (assetBundle) =>
            {
                UnityEngine.Object _result = GetObjectFromCache(abName, objectName);
                if (_result != null)
                {
                    callback?.Invoke(_result);
                    return;
                }
                var assetLoadRequest = assetBundle.LoadAssetAsync<UnityEngine.Object>(objectName);
                assetLoadRequest.completed += (op) =>
                {
                    if (assetLoadRequest.asset != null)
                    {
                        m_ObjectsMap[abName] = new Dictionary<string, UnityEngine.Object>() { { objectName, assetLoadRequest.asset } };
                    }
                    callback?.Invoke(assetLoadRequest.asset);
                };
            };
            yield return withDependencies ? LoadAssetBundleWithDependencies(abName, onCompleted) : LoadSingleAssetBundle(abName, onCompleted);
        }
        IEnumerator LoadBundle(string abName, bool withDependencies, Action<AssetBundle> callback)
        {
            yield return withDependencies ? LoadAssetBundleWithDependencies(abName, callback) : LoadSingleAssetBundle(abName, callback);
        }
        IEnumerator LoadAssetBundleWithDependencies(string assetBundleName, Action<AssetBundle> callback)
        {
            // Get dependecies from the AssetBundleManifest object..
            string[] dependencies = m_AssetBundleManifest.GetAllDependencies(assetBundleName);
            int loadedCount = 0;
            for (int i = 0; i < dependencies.Length; i++)
            {
                yield return LoadSingleAssetBundle(dependencies[i],
                    (ab) =>
                    { loadedCount++; });
            }
            while (loadedCount != dependencies.Length)
            {
                yield return null;
            }
            yield return LoadSingleAssetBundle(assetBundleName, callback);
        }
        public IEnumerator LoadSingleAssetBundle(string assetBundleName, Action<AssetBundle> callback)
        {
            if (m_LoadedBundles.ContainsKey(assetBundleName))//检查已加载
            {
                AssetBundle assetBundle = m_LoadedBundles[assetBundleName];
                if (assetBundle != null)
                {
                    callback?.Invoke(m_LoadedBundles[assetBundleName]);
                    yield break;
                }
                else
                {
                    m_LoadedBundles.Remove(assetBundleName);
                }
            }
            if (m_LoadingBundles.Contains(assetBundleName))//检查加载中
            {
                if (callback != null)
                {
                    if (!m_InterestedActions.ContainsKey(assetBundleName))
                        m_InterestedActions.Add(assetBundleName, new List<Action<AssetBundle>>());
                    m_InterestedActions[assetBundleName].Add(callback);
                }
                yield break;
            }
            string path = AssetBundleMapper.Instance.GetAssetBundleFullPath(assetBundleName);
            Action fail = () =>
            {
                Debug.LogError("Failed to load AssetBundle : " + path);
                m_InterestedActions.Remove(assetBundleName);
                callback?.Invoke(null);
            };
            m_LoadingBundles.Add(assetBundleName);
            var request = AssetBundle.LoadFromFileAsync(path);
            yield return request;
            m_LoadingBundles.Remove(assetBundleName);
            AssetBundle ab = request.assetBundle;
            if (ab == null)
            {
                fail();
                yield break;
            }
            m_LoadedBundles.Add(assetBundleName, ab);
            callback?.Invoke(ab);
            if (m_InterestedActions.ContainsKey(assetBundleName))
            {
                List<Action<AssetBundle>> actions = m_InterestedActions[assetBundleName];
                for (int i = 0; i < actions.Count; i++)
                {
                    actions[i]?.Invoke(ab);
                    actions[i] = null;
                }
                m_InterestedActions.Remove(assetBundleName);
            }
        }
        UnityEngine.Object GetObjectFromCache(string abName, string objectName)
        {
            if (m_ObjectsMap.ContainsKey(abName))
            {
                var dict = m_ObjectsMap[abName];
                UnityEngine.Object target = null;
                if (dict.TryGetValue(objectName, out target))
                {
                    return target;
                }
            }
            return null;
        }

    }

 

Guess you like

Origin blog.csdn.net/Momo_Da/article/details/105131213