474 lines
17 KiB
C#
474 lines
17 KiB
C#
using asap.core;
|
|
using GameCore;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
public interface ILoadResourceService
|
|
{
|
|
Task<bool> Load(string label);
|
|
Task<bool> Loads(List<string> label);
|
|
//后台排队静默下载
|
|
void Load(List<string> label);
|
|
/// <summary>
|
|
/// 登陆游戏预下载地图资源
|
|
/// </summary>
|
|
/// <param name="assetName"></param>
|
|
/// <param name="progress"></param>
|
|
/// <returns></returns>
|
|
Task<bool> Loading(List<string> assetName, System.Action<float> progress);
|
|
//检查是否需要下载资源,不下载
|
|
Task<bool> CheckResource(string label);
|
|
Task<bool> CheckResourceLoadQueue(string key, List<string> label);
|
|
Task<bool> CheckResourceLoadQueue(List<string> label);
|
|
string curName { get; }
|
|
string oldName { get; }
|
|
}
|
|
public class LoadResourceData
|
|
{
|
|
public string name;
|
|
public AsyncOperationHandle downloadOp;
|
|
}
|
|
public struct LoadEventResourceEvent
|
|
{
|
|
public string key;
|
|
public List<string> label;
|
|
public bool isSucceeded;
|
|
}
|
|
public class LoadProgressEvent
|
|
{
|
|
public string name;
|
|
public float progress;
|
|
public float totalDownloadSize;
|
|
public bool isSucceeded;
|
|
public bool isFailed;
|
|
}
|
|
public class LoadResourceService : ILoadResourceService
|
|
{
|
|
[Inject]
|
|
public IConfig config { get; set; }
|
|
Dictionary<string, AsyncOperationHandle> loadResourceDatas = new Dictionary<string, AsyncOperationHandle>();
|
|
LinkedList<string> loadQueue = new LinkedList<string>();
|
|
LinkedList<LoadEventResourceEvent> loadEventQueue = new LinkedList<LoadEventResourceEvent>();
|
|
bool LoadEventResourceing = false;
|
|
Dictionary<string, bool> loadRecord = new Dictionary<string, bool>();
|
|
//检查资源是否需要更新
|
|
public string curName { get; private set; }
|
|
public string oldName { get; private set; }
|
|
|
|
/// <summary>
|
|
/// 登陆游戏预下载地图资源
|
|
/// </summary>
|
|
/// <param name="assetName"></param>
|
|
/// <param name="progress"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> Loading(List<string> assetName, System.Action<float> progress)
|
|
{
|
|
if (!loadResourceDatas.ContainsKey(assetName[0]))
|
|
{
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(assetName, Addressables.MergeMode.Union);
|
|
var locations = await locationsOp.Task;
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
|
|
if (totalDownloadSize > 1024)
|
|
{
|
|
AsyncOperationHandle download = Addressables.DownloadDependenciesAsync(locations.Select(_ => _.PrimaryKey), Addressables.MergeMode.Union);
|
|
loadResourceDatas[assetName[0]] = download;
|
|
}
|
|
Addressables.Release(locationsOp);
|
|
}
|
|
bool result = true;
|
|
if (loadResourceDatas.ContainsKey(assetName[0]))
|
|
{
|
|
#if AGG
|
|
using (var e = GEvent.GameEvent("Preload_start"))
|
|
{
|
|
e.AddContent("expected_assets", string.Join(',', assetName));
|
|
}
|
|
#endif
|
|
float percent = 0;
|
|
LoadingScreen.SetLoadingInfo(LocalizationMgr.GetText("UI_ToastPanel_26"));
|
|
|
|
AsyncOperationHandle downloadOp = loadResourceDatas[assetName[0]];
|
|
DateTime startTime = DateTime.Now;
|
|
LoadingScreen.SetSubProgress(0, "");
|
|
LoadingScreen.ShowSubProgressBar();
|
|
while (!downloadOp.IsDone && downloadOp.Status != AsyncOperationStatus.Failed)
|
|
{
|
|
var downloadStatus = downloadOp.GetDownloadStatus();
|
|
if (downloadStatus.Percent > percent)
|
|
percent = downloadStatus.Percent;
|
|
progress?.Invoke(percent);
|
|
LoadingScreen.SetSubProgress(percent, GetSizeByBytes(downloadStatus.TotalBytes, percent));
|
|
await Awaiters.NextFrame;
|
|
}
|
|
LoadingScreen.HideSubProgressBar();
|
|
loadResourceDatas.Remove(assetName[0]);
|
|
if (downloadOp.Status == AsyncOperationStatus.Failed
|
|
|| downloadOp.OperationException != null)
|
|
{
|
|
result = false;
|
|
}
|
|
DateTime endTime = DateTime.Now;
|
|
Debug.Log($"Preload finished, result:{result}, time cost:{(endTime - startTime).TotalSeconds}s");
|
|
#if AGG
|
|
using (var e = GEvent.GameEvent("Preload_finish"))
|
|
{
|
|
e.AddContent("status", result ? "Succeeded" : "Failed")
|
|
.AddContent("duration_ms", (endTime - startTime).TotalMilliseconds);
|
|
if (downloadOp.OperationException != null)
|
|
{
|
|
e.AddContent("error", downloadOp.OperationException.Message);
|
|
}
|
|
}
|
|
#endif
|
|
Addressables.Release(downloadOp);
|
|
}
|
|
progress?.Invoke(1);
|
|
return result;
|
|
}
|
|
|
|
|
|
private const float byte2mb = 1024 * 1024;
|
|
private string GetSizeByBytes(long total, float percent)
|
|
{
|
|
return $"{(percent * total / byte2mb).ToString("0.0")}MB/{(total / byte2mb).ToString("0.0")}MB";
|
|
}
|
|
|
|
private string GetSizeByBytes(long total)
|
|
{
|
|
return $"{(total / byte2mb).ToString("0.00")}MB";
|
|
}
|
|
|
|
public async Task<bool> Load(string label)
|
|
{
|
|
try
|
|
{
|
|
oldName = label;
|
|
if (loadResourceDatas.ContainsKey(label))
|
|
{
|
|
curName = label;
|
|
return false;
|
|
}
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(label);
|
|
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Load");
|
|
var locations = await locationsOp.Task;
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Load");
|
|
if (totalDownloadSize > 1)
|
|
{
|
|
Load(label, totalDownloadSize, locations.Select(_ => _.PrimaryKey).ToList());
|
|
return false;
|
|
}
|
|
Addressables.Release(locationsOp);
|
|
return true;
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService:Load");
|
|
Debug.LogError(e);
|
|
}
|
|
return false;
|
|
}
|
|
public async Task<bool> Loads(List<string> labels)
|
|
{
|
|
try
|
|
{
|
|
oldName = labels[0];
|
|
if (loadResourceDatas.ContainsKey(labels[0]))
|
|
{
|
|
curName = labels[0];
|
|
return false;
|
|
}
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(labels, Addressables.MergeMode.Union);
|
|
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Loads");
|
|
var locations = await locationsOp.Task;
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Loads");
|
|
if (totalDownloadSize > 1)
|
|
{
|
|
Load(labels[0], totalDownloadSize, locations.Select(_ => _.PrimaryKey).ToList());
|
|
return false;
|
|
}
|
|
Addressables.Release(locationsOp);
|
|
return true;
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Loads");
|
|
Debug.LogError(e);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
public async Task<bool> CheckResource(string label)
|
|
{
|
|
try
|
|
{
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(label);
|
|
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Load");
|
|
var locations = await locationsOp.Task;
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Load");
|
|
Addressables.Release(locationsOp);
|
|
if (totalDownloadSize > 1)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService:Load");
|
|
Debug.LogError(e);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public async void Load(List<string> label)
|
|
{
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(label, Addressables.MergeMode.Union);
|
|
var locations = await locationsOp.Task;
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
if (totalDownloadSize > 0)
|
|
{
|
|
for (int i = 0; locations.Count > i; i++)
|
|
{
|
|
//判断 loadQueue 是否包含当前资源
|
|
if (loadQueue.Contains(locations[i].PrimaryKey))
|
|
{
|
|
continue;
|
|
}
|
|
loadQueue.AddLast(locations[i].PrimaryKey);
|
|
if (loadQueue.Count == 1)
|
|
{
|
|
LoadKey();
|
|
}
|
|
}
|
|
}
|
|
Addressables.Release(locationsOp);
|
|
}
|
|
async void Load(string name, float totalDownloadSize, IList<string> keys)
|
|
{
|
|
try
|
|
{
|
|
curName = name;
|
|
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(keys, Addressables.MergeMode.Union);
|
|
loadResourceDatas[name] = downloadOp;
|
|
LoadProgressEvent loadProgressEvent = new LoadProgressEvent() { name = name, progress = downloadOp.GetDownloadStatus().Percent, totalDownloadSize = totalDownloadSize };
|
|
while (!downloadOp.IsDone && downloadOp.Status != AsyncOperationStatus.Failed)
|
|
{
|
|
if (name == curName)
|
|
{
|
|
loadProgressEvent.progress = downloadOp.GetDownloadStatus().Percent;
|
|
loadProgressEvent.totalDownloadSize = totalDownloadSize;
|
|
GContext.Publish(loadProgressEvent);
|
|
}
|
|
await Awaiters.Seconds(0.2f);
|
|
}
|
|
|
|
if (name == curName)
|
|
{
|
|
if (downloadOp.Status == AsyncOperationStatus.Succeeded)
|
|
{
|
|
loadProgressEvent.progress = 1.0001f;
|
|
loadProgressEvent.isSucceeded = true;
|
|
}
|
|
else
|
|
{
|
|
loadProgressEvent.isFailed = true;
|
|
}
|
|
loadProgressEvent.totalDownloadSize = totalDownloadSize;
|
|
GContext.Publish(loadProgressEvent);
|
|
}
|
|
try
|
|
{
|
|
OnLoadGameEvent(downloadOp, string.Join(',', keys));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError(e);
|
|
}
|
|
|
|
Addressables.Release(downloadOp);
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogError(e);
|
|
}
|
|
loadResourceDatas.Remove(name);
|
|
}
|
|
async void LoadKey()
|
|
{
|
|
while (loadQueue.Count > 0)
|
|
{
|
|
string key = loadQueue.First.Value;
|
|
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(key);
|
|
await downloadOp.Task;
|
|
|
|
OnLoadGameEvent(downloadOp, key);
|
|
|
|
Addressables.Release(downloadOp);
|
|
await Awaiters.NextFrame;
|
|
loadQueue.RemoveFirst();
|
|
}
|
|
}
|
|
public async Task<bool> CheckResourceLoadQueue(List<string> label)
|
|
{
|
|
string key = string.Join(",", label);
|
|
return await ResourceLoadQueue(key, label);
|
|
}
|
|
public async Task<bool> CheckResourceLoadQueue(string key, List<string> label)
|
|
{
|
|
bool NoCheckResource = config.Get("NoCheckResource", "0") == "1";
|
|
if (NoCheckResource)
|
|
return true;
|
|
return await ResourceLoadQueue(key, label);
|
|
}
|
|
async Task<bool> ResourceLoadQueue(string key, List<string> label)
|
|
{
|
|
try
|
|
{
|
|
if (loadRecord.ContainsKey(key))
|
|
{
|
|
return loadRecord[key];
|
|
}
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(label, Addressables.MergeMode.Union);
|
|
GameCore.UIManager.ShowWaitingBlock("LoadResourceService::Load");
|
|
var locations = await locationsOp.Task;
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService::Load");
|
|
Addressables.Release(locationsOp);
|
|
if (totalDownloadSize > 1)
|
|
{
|
|
loadRecord[key] = false;
|
|
LoadEventResourceEvent loadEventData = new LoadEventResourceEvent();
|
|
loadEventData.key = key;
|
|
loadEventData.label = label;
|
|
LoadEventResource(loadEventData);
|
|
return false;
|
|
}
|
|
loadRecord[key] = true;
|
|
return true;
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
loadRecord.Remove(key);
|
|
GameCore.UIManager.HideWaitingBlock("LoadResourceService:Load");
|
|
Debug.LogError(e);
|
|
}
|
|
return false;
|
|
}
|
|
/// <summary>
|
|
/// 排队下载活动资源
|
|
/// </summary>
|
|
/// <param name="loadEventData"></param>
|
|
void LoadEventResource(LoadEventResourceEvent loadEventData)
|
|
{
|
|
if (loadEventData.label == null || loadEventData.label.Count == 0)
|
|
return;
|
|
loadEventQueue.AddLast(loadEventData);
|
|
if (loadEventQueue.Count == 1)
|
|
{
|
|
LoadEventKey();
|
|
}
|
|
}
|
|
async void LoadEventKey()
|
|
{
|
|
LoadEventResourceing = true;
|
|
while (loadEventQueue.Count > 0)
|
|
{
|
|
LoadEventResourceEvent loadEventData = loadEventQueue.First.Value;
|
|
if (loadEventData.label == null || loadEventData.label.Count == 0)
|
|
{
|
|
loadEventQueue.RemoveFirst();
|
|
continue;
|
|
}
|
|
try
|
|
{
|
|
var locationsOp = Addressables.LoadResourceLocationsAsync(loadEventData.label, Addressables.MergeMode.Union);
|
|
var locations = await locationsOp.Task;
|
|
Addressables.Release(locationsOp);
|
|
|
|
// 检查locations是否有效
|
|
if (locations == null || locations.Count == 0)
|
|
{
|
|
Debug.Log("未找到任何资源位置");
|
|
loadEventData.isSucceeded = false;
|
|
GContext.Publish(loadEventData);
|
|
loadEventQueue.RemoveFirst();
|
|
continue;
|
|
}
|
|
var totalDownloadSize = await Addressables.GetDownloadSizeAsync(locations).Task;
|
|
if (totalDownloadSize > 0)
|
|
{
|
|
var keys = locations.Select(_ => _.PrimaryKey).ToList();
|
|
string keyStr = string.Join(",", keys);
|
|
Debug.Log($"资源名称:{keyStr}");
|
|
Debug.Log($"资源大小:{GetSizeByBytes(totalDownloadSize)}");
|
|
|
|
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(keys, Addressables.MergeMode.Union);
|
|
await downloadOp.Task;
|
|
await Awaiters.NextFrame;
|
|
OnLoadGameEvent(downloadOp, keyStr);
|
|
bool isSucceeded = downloadOp.Status == AsyncOperationStatus.Succeeded;
|
|
loadEventData.isSucceeded = isSucceeded;
|
|
GContext.Publish(loadEventData);
|
|
if (isSucceeded)
|
|
{
|
|
loadRecord[loadEventData.key] = isSucceeded;
|
|
}
|
|
else
|
|
{
|
|
loadRecord.Remove(loadEventData.key);
|
|
}
|
|
Addressables.Release(downloadOp);
|
|
}
|
|
else
|
|
{
|
|
Debug.Log($"资源大小:{0}");
|
|
await Awaiters.NextFrame;
|
|
loadEventData.isSucceeded = true;
|
|
GContext.Publish(loadEventData);
|
|
loadRecord[loadEventData.key] = true;
|
|
}
|
|
loadEventQueue.RemoveFirst();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"资源下载: {e.Message} {e.StackTrace}");
|
|
loadEventData.isSucceeded = false;
|
|
GContext.Publish(loadEventData);
|
|
loadRecord.Remove(loadEventData.key);
|
|
loadEventQueue.RemoveFirst();
|
|
Debug.Log($"错误下载活动资源队列 count == {loadEventQueue.Count}");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static void OnLoadGameEvent(AsyncOperationHandle downloadOp, string key)
|
|
{
|
|
if (downloadOp.Status == AsyncOperationStatus.Failed || downloadOp.OperationException != null)
|
|
{
|
|
Exception exception = downloadOp.OperationException;
|
|
using (var e = GEvent.GameEvent("resource_load_finish"))
|
|
{
|
|
e.AddContent("status", "Failed")
|
|
.AddContent("keys", key)
|
|
;
|
|
if (exception != null)
|
|
{
|
|
e.AddContent("error", exception.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|