using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Common.Event;
using UnityEngine;
using SandboxMap.Data;
using Object = UnityEngine.Object;
public enum AssetBundleType
{
WoldMap,
Construction,
UI,
NPC, //NPC模型的组件
NPCModel,//若干AB组件结合成的NPC模型,3D人物模型
FILMSCENE,//电影场景
}
/// <summary>
/// 资源加载工具
/// </summary>
public class AssetBundleTool : MonoManagerBase<AssetBundleTool>
{
/// <summary>
/// 预加载资源
/// </summary>
public void ReadyLoad()
{
ReadyLoadAsset = new List<string>();
_elapsedTime = 0;
StartCoroutine(ElapsedTimeEnumer());
AddReadyLoadAsset("labelpanel", AssetBundleType.UI);
AddReadyLoadAsset("commen_npc", AssetBundleType.NPC);
AddReadyLoadAsset("commen_construction", AssetBundleType.Construction);
AddReadyLoadAsset("StoryDialoguePanel", AssetBundleType.UI);
AddReadyLoadAsset("TaskReceiveWindow", AssetBundleType.UI);
AddReadyLoadAsset("TaskCommitWindow", AssetBundleType.UI);
ReadyLoadBuild();
Debug.Log("******AssetBundleReadyLoadAssetCount*******" + ReadyLoadAsset.Count);
}
/// <summary>
/// 资源更新完成后 预加载
/// </summary>
public void PreLoad()
{
LoadResourceAsync<Font>("Font", AssetBundleType.UI, "DENG");
}
private float _elapsedTime;
private List<string> ReadyLoadAsset;
private void AddReadyLoadAsset(string data,AssetBundleType type)
{
data = data.ToLower();
ReadyLoadAsset.Add(data);
LoadResource(data, type, null);
}
public void ReadyLoadEnd(string data)
{
if (ReadyLoadAsset == null) return;
if (ReadyLoadAsset.Contains(data))
{
ReadyLoadAsset.Remove(data);
}
else
{
Debug.Log("不在预加载集合中*********" + data);
}
if (ReadyLoadAsset.Count == 0)
{
ReadyLoadAsset = null;
GameManager.Instance.ToStartGame();
Debug.Log("******AssetBundleReadyLoadAssetEnd*******ElapsedTime:" + _elapsedTime);
}
}
private IEnumerator ElapsedTimeEnumer()
{
while (ReadyLoadAsset != null)
{
_elapsedTime += Time.deltaTime;
yield return 1;
}
}
/// <summary>
/// 预加载建筑
/// </summary>
/// <param name="data"></param>
private void ReadyLoadBuild()
{
BuildingConfigData data = ConfigManager.Instance.load<global::BuildingConfigData>();
if (data == null || data.datas == null) return;
for (int i = 0; i < data.datas.Length; i++)
{
ConstructionConfig building = data.datas[i];
AddReadyLoadAsset(building.modeID + "_" + building.level , AssetBundleType.Construction);
}
}
/*
/// <summary>
/// 同步获得资源
/// </summary>
/// <param name="data"></param>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public GameObject GetReadyObject(string data, AssetBundleType type)
{
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/" + type
+ "/" + data + ".data";
try
{
return AssetTool.GetAssetByName<GameObject>(ResourcesDic[resUrl],data) as GameObject;
}
catch (Exception e)
{
throw new Exception(data + ":没有做预加载" + e.Message);
}
}
*/
private EventDispatcher _eventManager;
public EventDispatcher EventManager => _eventManager;
private Queue<Dependence> _dependences;
/// <summary>
/// 依赖资源
/// </summary>
private List<string> DependencesList;
/// <summary>
/// 资源缓存字典
/// </summary>
public Dictionary<string, UnityEngine.Object[]> AssetsDic;
public bool CheckAssetsContains(string url)
{
if (AssetsDic!=null && AssetsDic.ContainsKey(url))
{
return true;
}
return false;
}
public void AddAssets2Dic(string key,UnityEngine.Object[] assets)
{
if (AssetsDic == null)
{
AssetsDic=new Dictionary<string, UnityEngine.Object[]>();
}
if (AssetsDic.ContainsKey(key))
{
Debug.LogError("已存在ResourcesDic*********" + key + "*********" + assets);
}
else
{
AssetsDic.Add(key, assets);
}
}
public Object[] GetAssets(string key)
{
if (AssetsDic != null && AssetsDic.ContainsKey(key))
{
return AssetsDic[key];
}
return null;
}
/// <summary>
/// 正在加载中
/// </summary>
public List<string> InLoadResources;
private AssetBundleManifest _woldMapManifest; //
private AssetBundleManifest _constructionManifest;
private AssetBundleManifest _uiManifest;
private AssetBundleManifest _npcManifest;
private string PATHRESROOTDIR;
public void unload(string assetBundleName, AssetBundleType type = AssetBundleType.UI)
{
assetBundleName = assetBundleName.ToLower();
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/" + type + "/" + assetBundleName + ".data";
UnityEngine.Object[] ress = GetAssets(resUrl);
AssetsDic.Remove(resUrl);
Resources.UnloadUnusedAssets();
GC.Collect();
}
/// <summary>
/// 加载item方便实用
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="type"></param>
/// <param name="assetName"></param>
/// <returns></returns>
public RectTransform Load(string assetBundleName, string assetName = "")
{
GameObject asset = LoadResource<GameObject>(assetBundleName, AssetBundleType.UI, assetName);
return Instantiate(asset).transform as RectTransform;
}
/// <summary>
/// 同步加载
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="type"></param>
/// <param name="back"></param>
/// <param name="assetName"></param>
/// <returns></returns>
public T LoadResource<T>(string assetBundleName, AssetBundleType type, string assetName = "")
where T : UnityEngine.Object
{
assetBundleName = assetBundleName.ToLower();
assetName = assetName.ToLower();
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/" + type + "/" + assetBundleName + ".data";
if (string.IsNullOrEmpty(assetName))
assetName = assetBundleName;
if (CheckAssetsContains(resUrl))
{
return AssetTool.GetAsset<T>(GetAssets(resUrl), assetName) as T;
}
else
{
AssetBundle ab = null;
ab = AssetBundle.LoadFromFile(resUrl);
if (ab == null)
{
Debug.LogError("文件不存在! fileName : " + resUrl);
return null;
}
UnityEngine.Object[] assets = ab.LoadAllAssets();
AddAssets2Dic(resUrl, assets);
T obj = AssetTool.GetAsset<T>(assets,assetName) as T;
ab.Unload(false);
return obj;
}
}
public void LoadSceneAsync(string assetBundleName, AssetBundleType type, Action action)
{
StartCoroutine(LoadSceneAsyncFun(assetBundleName, type, action));
}
private IEnumerator LoadSceneAsyncFun(string assetBundleName, AssetBundleType type, Action action)
{
assetBundleName = assetBundleName.ToLower();
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/" + type + "/" + assetBundleName + ".data";
if (CheckAssetsContains(resUrl) && action != null)
{
action();
}
else
{
AssetBundleCreateRequest abReq;
AssetBundle ab = null;
abReq = AssetBundle.LoadFromFileAsync(resUrl);
yield return abReq;
ab = abReq.assetBundle;
if (ab == null)
{
Debug.LogError("文件不存在! fileName : " + resUrl);
if (action != null) action();
}
if (ab.isStreamedSceneAssetBundle)
{
AddAssets2Dic(resUrl, new Object[] { ab });
if (action != null) action();
yield break;
}
if (action != null) action();
}
}
/// <summary>
/// 资源异步加载,返回Asset资源
/// </summary>
/// <param name="assetBundleName">包名</param>
/// <param name="type">资源类型</param>
/// <param name="assetName">在包中的资源名</param>
/// <param name="action">加载完成后的回调函数</param>
/// <param name="save">是否需要在内存中保留assetBundle镜像资源</param>
/// <typeparam name="T"></typeparam>
public void LoadResourceAsync<T>(string assetBundleName, AssetBundleType type, string assetName = "",
Action<T> action = null,bool save = true) where T : UnityEngine.Object
{
StartCoroutine(LoadResourceAsyncFun(assetBundleName, type, assetName, action, save));
}
private IEnumerator LoadResourceAsyncFun<T>(string assetBundleName, AssetBundleType type, string assetName,
Action<T> action,bool save) where T : UnityEngine.Object
{
assetBundleName = assetBundleName.ToLower();
assetName = assetName.ToLower();
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/" + type + "/" + assetBundleName + ".data";
string key = resUrl + assetName;
if (CheckAssetsContains(key) && action != null)
{
Object obj = AssetTool.GetAsset<T>(GetAssets(resUrl), assetBundleName);
if (obj is T)
{
action(obj as T);
}
else if (obj is AssetBundle)
{
action(null);
}
}
else
{
AssetBundleCreateRequest abReq;
AssetBundle ab = null;
abReq = AssetBundle.LoadFromFileAsync(resUrl);
yield return abReq;
ab = abReq.assetBundle;
if (ab == null)
{
Debug.LogError("文件不存在! fileName : " + resUrl);
if(action != null) action(null);
}
if (string.IsNullOrEmpty(assetName))
assetName = assetBundleName;
if(ab.isStreamedSceneAssetBundle)
{
AddAssets2Dic(resUrl, new Object[] { ab });
if (action != null) action(null);
yield break;
}
AssetBundleRequest assets = ab.LoadAllAssetsAsync();
yield return assets;
AddAssets2Dic(resUrl,assets.allAssets);
T obj = AssetTool.GetAsset<T>(assets.allAssets,assetName) as T;
if (!save)
{
ab.Unload(false);
}
if (action != null) action(obj);
}
}
/// <summary>
/// 根据name加载一个预设文件,设置为parent的子物体 -- 异步 --
/// </summary>
public void LoadResource(string data, AssetBundleType type, Action<GameObject> back)
{
data = data.ToLower();
if (_eventManager == null)
{
_eventManager = new EventDispatcher();
_eventManager.AddEventListener(AssetBundleEventType.LoadEnd, LoadEvent);
_dependences = new Queue<Dependence>();
DependencesList = new List<string>();
InLoadResources = new List<string>();
}
StartCoroutine(Load(data, type, back));
}
private IEnumerator Load(string data, AssetBundleType type, Action<GameObject> back)
{
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/" + type + "/" + data + ".data";
while (InLoadResources.Contains(resUrl))
{
yield return 1;
}
if (CheckAssetsContains(resUrl))
{
_eventManager.DispatchEvent(new GameEventArgs(AssetBundleEventType.LoadEnd));
GameObject obj = AssetTool.GetAsset<GameObject>(GetAssets(resUrl), data) as GameObject;
back?.Invoke(obj);
yield break;
}
if (!File.Exists(resUrl))
{
Debug.LogWarning("文件不存在: " + resUrl);
ReadyLoadEnd(data);
_eventManager.DispatchEvent(new GameEventArgs(AssetBundleEventType.LoadEnd));
back?.Invoke(null);
yield break;
}
InLoadResources.Add(resUrl);
AssetBundleManifest manifest = null;
switch (type)
{
case AssetBundleType.WoldMap:
if (_woldMapManifest != null) manifest = _woldMapManifest;
break;
case AssetBundleType.Construction:
if (_constructionManifest != null) manifest = _constructionManifest;
break;
case AssetBundleType.UI:
if (_uiManifest != null) manifest = _uiManifest;
break;
case AssetBundleType.NPC:
if (_npcManifest != null) manifest = _npcManifest;
break;
}
if (manifest == null)
{
string manifestPath =
Path.Combine(ClientInfo.DataPath + "/AssetBundleDatas/", type.ToString());
manifestPath = Path.Combine(manifestPath, type.ToString());
// if (!File.Exists(manifestPath))
// {
// _eventManager.DispatchEvent(new GameEventArgs(AssetBundleEventType.LoadEnd));
// back?.Invoke(null);
// }
AssetBundle asset = AssetBundle.LoadFromFile(manifestPath);
manifest = asset.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
switch (type)
{
case AssetBundleType.WoldMap:
_woldMapManifest = manifest;
break;
case AssetBundleType.Construction:
_constructionManifest = manifest;
break;
case AssetBundleType.UI:
_uiManifest = manifest;
break;
case AssetBundleType.NPC:
_npcManifest = manifest;
break;
}
asset.Unload(false);
}
Dependence dep = new Dependence(data, type.ToString(), manifest, back);
_dependences.Enqueue(dep);
if (_isFrist)
{
_isFrist = false;
_eventManager.DispatchEvent(new GameEventArgs(AssetBundleEventType.LoadEnd));
}
}
private bool _isFrist = true;
private void LoadEvent(GameEventArgs e)
{
if (_dependences.Count > 0)
{
_dependences.Dequeue().Init();
}
else
{
_isFrist = true;
}
}
public bool GetDepContain(string key)
{
if (!DependencesList.Contains(key))
{
DependencesList.Add(key);
return false;
}
return true;
}
public void LoadScene(string sceneName, Action action)
{
StartCoroutine(LoadSceneFun(sceneName, action));
}
private IEnumerator LoadSceneFun(string sceneName, Action action)
{
sceneName = sceneName.ToLower();
string resUrl = ClientInfo.DataPath + "/AssetBundleDatas/WorldMap/" + sceneName + ".data";
string key = resUrl;
if (CheckAssetsContains(key) && action != null)
{
action();
}
else
{
AssetBundleCreateRequest abReq;
AssetBundle ab = null;
abReq = AssetBundle.LoadFromFileAsync(resUrl);
yield return abReq;
/*
ab = abReq.assetBundle;
if (ab == null)
{
Debug.LogError("文件不存在! fileName : " + resUrl);
if(action != null) action();
}
AssetBundleRequest assets = SceneManager.LoadScene()
yield return assets;
AddAssets2Dic(resUrl,assets.allAssets);
ab.Unload(false);
*/
if (action != null) action();
}
}
}
public static class AssetBundleEventType
{
public const string LoadEnd = "LOADEND";
}
public class Dependence
{
private readonly string _data;
private readonly string _url;
private readonly string _type;
private readonly AssetBundleManifest _manifest;
private readonly Action<GameObject> _back;
public Dependence(string data, string type, AssetBundleManifest manifest, Action<GameObject> back)
{
_data = data;
_url = ClientInfo.DataPath + "/AssetBundleDatas/" + type + "/" + data + ".data";
_type = type;
_manifest = manifest;
_back = back;
}
public void Init()
{
AssetBundleTool.instance.StartCoroutine(LoadDependences());
}
/// <summary>
/// 加载依赖项
/// </summary>
/// <returns></returns>
private IEnumerator LoadDependences()
{
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(_url);
yield return request;
if (string.Equals(_data, "commen_npc") || string.Equals(_data, "commen_construction"))
{
AssetBundleTool.instance.ReadyLoadEnd(_data);
AssetBundleTool.instance.EventManager.DispatchEvent(new GameEventArgs(AssetBundleEventType.LoadEnd));
yield break;
}
AssetBundle assetBundle = request.assetBundle;
if (assetBundle == null)
{
Debug.LogError("SceneProp assetsBundle is null! fileName : " + _url);
yield break;
}
AssetBundleRequest result = assetBundle.LoadAllAssetsAsync();
yield return result;
object temp = AssetTool.GetAsset<GameObject>(result.allAssets,_data);
UnityEngine.Object obj = temp as UnityEngine.Object;
_back?.Invoke(obj as GameObject);
AssetBundleTool.instance.ReadyLoadEnd(_data);
AssetBundleTool.instance.AddAssets2Dic(_url, result.allAssets);
AssetBundleTool.instance.InLoadResources.Remove(_url);
AssetBundleTool.instance.EventManager.DispatchEvent(new GameEventArgs(AssetBundleEventType.LoadEnd));
if(_type == "Construction" || _type == "NPC")
{
assetBundle.Unload(false);
}
}
}
public class AssetTool
{
public static UnityEngine.Object GetAsset<T>(UnityEngine.Object[] assets, string name)
{
UnityEngine.Object temp = null;
for (int i = 0; i < assets.Length; i++)
{
temp = assets[i];
if (temp is T)
{
string nameValue = temp.ToString();
string tempName = nameValue.Substring(0, nameValue.IndexOf(" ")).ToLower();
if (tempName == name)
{
//Debug.Log(tempName);
return temp;
}
}
}
return null;
}
public static T[] GetAssetAll<T>(UnityEngine.Object[] assets)
{
List<T> tempResult= new List<T>();
System.Object temp = null;
for (int i = 0; i < assets.Length; i++)
{
temp = assets[i];
if (temp is T)
{
//Debug.Log(temp);
tempResult.Add((T)temp);
}
}
return tempResult.ToArray();
}
}