using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.Networking; public class AssetDownloader : SingletonMono { private Dictionary tasks; private List downloadDataEntities; private List downloadSuccessDataEntities; private List downloadErrDataEntities; private int curTaskNum; private int maxTasknum; public bool CancelDownLoad { get; set; } private void Awake() { Debug.Log("AssetDownloader 111"); Init(); } void Start() { } void Update() { if (!CancelDownLoad && HasNotDownloadedEntity()) { if (HasIdleTask()) { DownloadTask task = FindIdleTask(); // DownloadDataEntity entity = FindNotDownloadedEntityByFirst(); if (entity != null) { task.CurDownloadEntity = entity; DownLoad(task); } } } } protected override void Dispose() { StopAllCoroutines(); base.Dispose(); } private void Init() { maxTasknum = DownloadMgr.Instance.DownloadTaskMaxNum; tasks = new Dictionary(maxTasknum); downloadDataEntities = new List(); downloadSuccessDataEntities = new List(); downloadErrDataEntities = new List(); for (int i = 0; i < maxTasknum; i++) { GameObject go = new GameObject("DownloadTask_"+i, typeof(DownloadTask)); DontDestroyOnLoad(go); go.transform.SetParent(transform); DownloadTask task = go.GetComponent(); task.Callback = TaskCallback; tasks.Add(task, true); } curTaskNum = 0; CancelDownLoad = false; } private IEnumerator DownloadFile(string url, Action callback, int _timeout = 5) { Debug.Log($"url = {url}"); UnityWebRequest webRqst = UnityWebRequest.Get(url); float timeOut = Time.time; webRqst.timeout = _timeout; UnityWebRequestAsyncOperation asyncOperation = webRqst.SendWebRequest(); float progress = 0; while (!webRqst.isDone) { if (progress < webRqst.downloadProgress) { timeOut = Time.time; progress = webRqst.downloadProgress; Debug.Log($"下载 {progress}% DownloadSize = {webRqst.downloadedBytes}"); } if (Time.time - timeOut > DownloadMgr.TimeOut) { Debug.LogWarning("下载超时!!!"); callback?.Invoke(null); yield break; } yield return null; } progress = webRqst.downloadProgress; //yield return asyncOperation; if (webRqst != null && webRqst.result == UnityWebRequest.Result.Success) { Debug.Log($"[{url}] 下载完成"); callback?.Invoke(webRqst); } else { callback?.Invoke(null); Debug.Log($"下载失败;Error = {webRqst.error}"); Debug.Log("下载失败 Error url = " + url); } webRqst.Dispose(); } private IEnumerator AssetLoadToLocal(string url, string toPath, Action callback) { Debug.Log(url); using (WWW www = new WWW(url)) { yield return www; if (www.error == null) { string localPath = FileHelper.PathRemoveBack(toPath); FileHelper.CreateDir(localPath); using (FileStream fs = File.Create(toPath, www.bytes.Length)) { fs.Write(www.bytes, 0, www.bytes.Length); fs.Close(); callback?.Invoke(www.bytes); } } else { Debug.Log("WWW Error = "+www.error); Debug.Log("WWW Error url = " + url); callback?.Invoke(null); } } } private IEnumerator AssetLoad(string url, Action callback) { using (WWW www = new WWW(url)) { Debug.Log("WWW Url = " + url); yield return www; if (www.error == null) { callback?.Invoke(www.bytes); } else { callback?.Invoke(null); } } } private void DownLoad(DownloadTask task) { SetTaskState(task, false); if (task.SetUrl(task.CurDownloadEntity.Url)) { // StartCoroutine(task.Task()); task.StartTask(); } } private void TaskCallback(DownloadTask task) { if (task.State == DownloadTaskState.DownloadSuccess) { OnDownloadSuccess(task.CurDownloadEntity); task.CurDownloadEntity.Callback?.Invoke(task); } else if (task.State == DownloadTaskState.Error) { task.CurDownloadEntity.State = DownloadTaskState.Error; task.CurDownloadEntity.Callback?.Invoke(task); task.CurDownloadEntity.DownloadErrCount++; task.CurDownloadEntity.State = DownloadTaskState.None; if (task.CurDownloadEntity.DownloadErrCount >= 10) { OnDownloadErr(task.CurDownloadEntity); Debug.Log("下载失败:" + task.CurDownloadEntity.FullName); } } SetTaskState(task, true); } private void SetTaskState(DownloadTask task, bool isIdle) { if (tasks.ContainsKey(task)) { tasks[task] = isIdle; } if (isIdle) { curTaskNum--; } else { curTaskNum++; } } private DownloadDataEntity FindNotDownloadedEntityByFirst() { DownloadDataEntity entity = null; int size = downloadDataEntities.Count; for (int i = 0; i < size; i++) { if (downloadDataEntities[i].State == DownloadTaskState.None ) { entity = downloadDataEntities[i]; break; } } return entity; } private DownloadTask FindIdleTask() { DownloadTask idletask = null; foreach (var item in tasks) { if (item.Value == true) { idletask = item.Key; } } return idletask; } private void OnDownloadSuccess(DownloadDataEntity entity) { downloadSuccessDataEntities.Add(entity); downloadDataEntities.Remove(entity); } private void OnDownloadErr(DownloadDataEntity entity) { downloadErrDataEntities.Add(entity); downloadDataEntities.Remove(entity); } public bool HasIdleTask() { return curTaskNum < maxTasknum; } public bool HasTask() { return downloadDataEntities.Count > 0; } public bool HasNotDownloadedEntity() { return downloadDataEntities != null && downloadDataEntities.Count > 0; } public void AddDownloadTask(DownloadDataEntity dataEntity) { if (!downloadDataEntities.Contains(dataEntity) && !downloadSuccessDataEntities.Contains(dataEntity)) { downloadDataEntities.Add(dataEntity); } } public void AddDownloadTasks(List dataEntities) { downloadDataEntities.AddRange(dataEntities); } public void DownLoadFileByCoroutine(string url, Action callback,int timeout = 5) { StartCoroutine(DownloadFile(url, callback,5)); } public void AssetLoadToLocalByCorutine(string url, string toPath, Action callback = null) { StartCoroutine(AssetLoadToLocal(url, toPath, callback)); } public void AssetLoadByCorutine(string url, Action callback = null) { StartCoroutine(AssetLoad(url, callback)); } public void DoByCorutine(Func callback) { if (callback != null) StartCoroutine(callback.Invoke()); } public void ClearTasks() { downloadDataEntities.Clear(); downloadSuccessDataEntities.Clear(); } }