313 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C#
		
	
	
		
		
			
		
	
	
			313 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C#
		
	
	
| 
								 | 
							
								using System;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using UnityEngine.Networking;
							 | 
						||
| 
								 | 
							
								using Object = UnityEngine.Object;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Guru
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    public enum ResType
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        Unknown = 0,
							 | 
						||
| 
								 | 
							
								        Bundle,
							 | 
						||
| 
								 | 
							
								        Texture,
							 | 
						||
| 
								 | 
							
								        File,
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    public class ResUriHelper
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        public const string FilePrefix = "file::";
							 | 
						||
| 
								 | 
							
								        public const string BundlePrefix = "bundle::";
							 | 
						||
| 
								 | 
							
								        public const string TexturePrefix = "texture::";
							 | 
						||
| 
								 | 
							
								        public const string HttpPrefix = "http://";
							 | 
						||
| 
								 | 
							
								        public const string HttpsPrefix = "https://";
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public static string GetFileUri(string url)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return $"{FilePrefix}{url}";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public static string GetBundleUri(string url)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return $"{BundlePrefix}{url}";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public static string GetTextureUri(string url)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return $"{TexturePrefix}{url}";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public static void UriToType(string uri, out ResType type, out string url)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            type = ResType.Unknown;
							 | 
						||
| 
								 | 
							
								            url = uri;
							 | 
						||
| 
								 | 
							
								            if (uri.StartsWith(FilePrefix))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                type = ResType.File;
							 | 
						||
| 
								 | 
							
								                url = uri.Substring(FilePrefix.Length);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (uri.StartsWith(BundlePrefix))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                type = ResType.Bundle;
							 | 
						||
| 
								 | 
							
								                url = uri.Substring(BundlePrefix.Length);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (uri.StartsWith(TexturePrefix))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                type = ResType.Texture;
							 | 
						||
| 
								 | 
							
								                url = uri.Substring(TexturePrefix.Length);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else if (uri.StartsWith(HttpPrefix) || uri.StartsWith(HttpsPrefix))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                type = ResType.File;
							 | 
						||
| 
								 | 
							
								                url = uri;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    public class ResLoaderBase: IResLoader
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        public int RetryTimes { get; set; } = 3;
							 | 
						||
| 
								 | 
							
								        private bool _iSBusy = false;
							 | 
						||
| 
								 | 
							
								        public bool IsBusy
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            get => _iSBusy;
							 | 
						||
| 
								 | 
							
								            set
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _iSBusy = value;
							 | 
						||
| 
								 | 
							
								                if(!_iSBusy) OnLoaderFree?.Invoke(this);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public Action<ResLoaderBase> OnLoaderFree;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private Queue<OneResLoadTask> _taskPool = new Queue<OneResLoadTask>(10);
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #region 加载逻辑
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        internal static OneResLoadTask CreateBundleTask(string url, Action<ResLoadInfo> callback, Action<bool, OneResLoadTask> handler)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return OneResLoadTask.Create(url, callback, handler, UnityWebRequestAssetBundle.GetAssetBundle(url));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        internal static OneResLoadTask CreateTextureTask(string url, Action<ResLoadInfo> callback, Action<bool, OneResLoadTask> handler)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return OneResLoadTask.Create(url, callback, handler, UnityWebRequestTexture.GetTexture(url, true));;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        internal static OneResLoadTask CreateFileTask(string url, Action<ResLoadInfo> callback, Action<bool, OneResLoadTask> handler)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return OneResLoadTask.Create(url, callback, handler, new UnityWebRequest(url));;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 异步加载
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="resUri"></param>
							 | 
						||
| 
								 | 
							
								        /// <param name="onLoadComplete"></param>
							 | 
						||
| 
								 | 
							
								        public void LoadAsync(string resUri, Action<ResLoadInfo> onLoadComplete)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            ResUriHelper.UriToType(resUri, out var type, out var url);
							 | 
						||
| 
								 | 
							
								            switch (type)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                case ResType.Bundle:
							 | 
						||
| 
								 | 
							
								                    LoadBundle(url, onLoadComplete);
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                case ResType.Texture:
							 | 
						||
| 
								 | 
							
								                    LoadTexture(url, onLoadComplete);
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                case ResType.File:
							 | 
						||
| 
								 | 
							
								                    LoadFile(url, onLoadComplete);
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                default:
							 | 
						||
| 
								 | 
							
								                    Debug.LogError($"--- Unknown ResType: {type}");
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 开始异步加载
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="task"></param>
							 | 
						||
| 
								 | 
							
								        /// <param name="onLoadComplete"></param>
							 | 
						||
| 
								 | 
							
								        private void StartAsyncLoading(OneResLoadTask task)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            IsBusy = true;
							 | 
						||
| 
								 | 
							
								            task.www.SendWebRequest().completed += ao =>
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (task.www.result == UnityWebRequest.Result.Success)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    task.loadHandler?.Invoke(true, task);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    if (task.retryTimes < RetryTimes)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        task.retryTimes++;
							 | 
						||
| 
								 | 
							
								                        StartAsyncLoading(task);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        task.loadHandler?.Invoke(false, task);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void AddLoadTask(OneResLoadTask task)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (IsBusy)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                _taskPool.Enqueue(task); // 入队等待
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                StartAsyncLoading(task); // 直接加载
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        #endregion
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        #region 加载 Bundle 资源
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// 加载 Bundle
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="url"></param>
							 | 
						||
| 
								 | 
							
								        /// <param name="onLoadComplete"></param>
							 | 
						||
| 
								 | 
							
								        public void LoadBundle(string url, Action<ResLoadInfo> onLoadComplete)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            AddLoadTask(CreateBundleTask(url, onLoadComplete, OnBundleLoaded));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        private void OnBundleLoaded(bool success, OneResLoadTask task)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var info = new ResLoadInfo(task.url);
							 | 
						||
| 
								 | 
							
								            if (success)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var ab = DownloadHandlerAssetBundle.GetContent(task.www);
							 | 
						||
| 
								 | 
							
								                if(ab != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    info.success = true;
							 | 
						||
| 
								 | 
							
								                    info.target = ab;
							 | 
						||
| 
								 | 
							
								                    info.bundleName = ab.name;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            task.callback?.Invoke(info);
							 | 
						||
| 
								 | 
							
								            SetFree();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        #endregion
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #region 加载二进制文件
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void LoadFile(string url, Action<ResLoadInfo> onLoadComplete)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (IsBusy)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Debug.LogError($"--- Loader is busy, canot load this task");
							 | 
						||
| 
								 | 
							
								                return; 
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            
							 | 
						||
| 
								 | 
							
								            StartAsyncLoading(CreateFileTask(url, onLoadComplete, OnFileLoaded));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void OnFileLoaded(bool success, OneResLoadTask task)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var info = new ResLoadInfo(task.url);
							 | 
						||
| 
								 | 
							
								            if (success)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var bytes = task.www.downloadHandler?.data ?? null;
							 | 
						||
| 
								 | 
							
								                if(bytes != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    info.success = true;
							 | 
						||
| 
								 | 
							
								                    info.target = bytes;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            task.callback?.Invoke(info);
							 | 
						||
| 
								 | 
							
								            SetFree();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        #endregion
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #region 加载图片
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public void LoadTexture(string url, Action<ResLoadInfo> onLoadComplete)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var request = CreateTextureTask(url, onLoadComplete, OnTextureLoaded);
							 | 
						||
| 
								 | 
							
								            if (!IsBusy)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                StartAsyncLoading(request);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            _taskPool.Enqueue(request);
							 | 
						||
| 
								 | 
							
								             
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        void OnTextureLoaded(bool success, OneResLoadTask task)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var info = new ResLoadInfo(task.url);
							 | 
						||
| 
								 | 
							
								            if (success)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var texture = DownloadHandlerTexture.GetContent(task.www);
							 | 
						||
| 
								 | 
							
								                if (texture != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    info.success = true;
							 | 
						||
| 
								 | 
							
								                    info.target = texture;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            task.callback?.Invoke(info);
							 | 
						||
| 
								 | 
							
								            SetFree();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #endregion
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        #region 加载器空闲
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void SetFree()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (_taskPool.Count > 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                StartAsyncLoading(_taskPool.Dequeue());
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            IsBusy = false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #endregion
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /// <summary>
							 | 
						||
| 
								 | 
							
								    /// 单挑加载任务类
							 | 
						||
| 
								 | 
							
								    /// </summary>
							 | 
						||
| 
								 | 
							
								    internal struct OneResLoadTask
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        public string url;
							 | 
						||
| 
								 | 
							
								        public int retryTimes;
							 | 
						||
| 
								 | 
							
								        public Action<ResLoadInfo> callback;
							 | 
						||
| 
								 | 
							
								        public UnityWebRequest www;
							 | 
						||
| 
								 | 
							
								        public Action<bool, OneResLoadTask> loadHandler;
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        public static OneResLoadTask Create(string url, Action<ResLoadInfo> callback, Action<bool, OneResLoadTask> handler,
							 | 
						||
| 
								 | 
							
								            UnityWebRequest www)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return new OneResLoadTask()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                url = url,
							 | 
						||
| 
								 | 
							
								                callback = callback,
							 | 
						||
| 
								 | 
							
								                loadHandler = handler,
							 | 
						||
| 
								 | 
							
								                www = www,
							 | 
						||
| 
								 | 
							
								                retryTimes = 0,
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 |