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;
}
}