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