2025-05-18 01:04:31 +08:00

614 lines
14 KiB
C#

// ***********************************************************************
// Assembly : Unity
// Author : Kimch
// Created :
//
// Last Modified By : Kimch
// Last Modified On :
// ***********************************************************************
// <copyright file= "AssetProxy" company=""></copyright>
// <summary></summary>
// ***********************************************************************
//#if UNITY_EDITOR
//#define USE_ASSETDATABASE
//#endif
//#define USE_ASSETBUNDLE
//#define USE_RESOURCE
#define USE_ADDRESSABLES
namespace G
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Object = UnityEngine.Object;
#region INTERFACE
public interface IAsyncR
{
/// <summary>Gets a value indicating whether this <see cref="IAsyncR"/> is done.</summary>
bool done
{
get;
}
/// <summary>Gets the error.</summary>
string error
{
get;
}
/// <summary>Gets or sets the progress.</summary>
float progress
{
get;
}
/// <summary>Gets or sets the data.</summary>
object asyncData
{
get;
}
/// <summary>Gets the asset bundle.</summary>
AssetBundle assetBundle
{
get;
}
}
#endregion
/// <summary>
///
/// </summary>
partial class AssetProxy : F.GameProxy
{
private const string GLOBAL_ASSET_POOL_NAME = "global";
private const string TEMPORARY_ASSET_POOL_NAME = "temporary";
private const string INSTANCES_POOL_NAME = "instances";
#region Model
private class AsyncR : IAsyncR
{
#region Field
/// <summary>
///
/// </summary>
private float _progress;
/// <summary>
///
/// </summary>
private string _error;
/// <summary>
///
/// </summary>
private object _data;
#endregion
#region Property
bool IAsyncR.done
{
get
{
return _progress > 1f;
}
}
string IAsyncR.error
{
get
{
return _error;
}
}
float IAsyncR.progress
{
get
{
return _progress;
}
}
object IAsyncR.asyncData
{
get
{
return _data;
}
}
AssetBundle IAsyncR.assetBundle
{
get
{
return _data as AssetBundle;
}
}
#endregion
#region Method
public void AsyncProcess(float progress)
{
_progress = progress;
_error = null;
_data = null;
}
public void AsyncSuccess(object data)
{
_progress = 1.0001f;
_error = null;
_data = data;
}
public void AsyncFailure(string error)
{
_progress = 1.0001f;
_error = error;
_data = null;
}
#endregion
}
#endregion
#region FIELD
/// <summary>
/// 异步加载回调
/// </summary>
private AsyncR _asyncR = new AsyncR();
/// <summary>
///
/// </summary>
private Dictionary<string, Object> _persistentAssets = new Dictionary<string, Object>(StringComparer.OrdinalIgnoreCase);
/// <summary>
///
/// </summary>
private Dictionary<string, Object> _temporaryAssets = new Dictionary<string, Object>(StringComparer.OrdinalIgnoreCase);
#endregion
#region Proxy
/// <summary>
///
/// </summary>
public override int priority
{
get { return int.MaxValue; }
}
/// <summary>
/// 已经初始化
/// </summary>
public bool initialized
{
get;
private set;
}
public override void Init()
{
#if USE_ADDRESSABLES
Addressables.InitializeAsync().Completed += (handle) =>
{
this.initialized = true;
KUIBind.Bind(null, this.UIAsyncInstantiater, this.UIReleaser);
};
#elif USE_ASSETBUNDLE
F.KFramework.ResourceManager.InitResources((errorMsg) =>
{
if (string.IsNullOrEmpty(errorMsg))
{
initialized = true;
}
});
#else
this.initialized = true;
#endif
CreateReleasePool(INSTANCES_POOL_NAME);
CreateReleasePool(GLOBAL_ASSET_POOL_NAME);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override Task LoadAsync()
{
Preload();
return TryGetGlobalAssetsAsync<Object>("global").Task;
}
/// <summary>
///
/// </summary>
public override void LoadCompleted()
{
//Preload();
}
private void SceneManager_sceneLoaded(UnityEngine.SceneManagement.Scene arg0, UnityEngine.SceneManagement.LoadSceneMode arg1)
{
}
private void SceneManager_sceneUnloaded(UnityEngine.SceneManagement.Scene arg0)
{
RemoveReleasePool(TEMPORARY_ASSET_POOL_NAME);
CreateReleasePool(TEMPORARY_ASSET_POOL_NAME);
System.GC.Collect();
}
/// <summary>
/// 预加载
/// </summary>
void Preload()
{
StartCoroutine(PreloadCO());
}
/// <summary>
///
/// </summary>
/// <returns></returns>
IEnumerator PreloadCO()
{
//yield return null;
yield return new WaitForSeconds(0.3f);
//Debug.Log("Preload " + Time.frameCount);
//yield return new WaitForSecondsRealtime(5);
var handle = TryGetGlobalAssetsAsync<UnityEngine.U2D.SpriteAtlas>("icon");
yield return handle;
IconProxy.Instance.LoadAtlas(handle.Result);
//TryGetGlobalAssetAsync<GameObject>("ui_w_main");
}
#endregion
#region API
public void CheckAndUpdateAssets(Callback2 callback)
{
StartCoroutine(UpdateAsync(callback));
}
private IEnumerator UpdateAsync(Callback2 callback)
{
//手动检查更新
var checkHandle = Addressables.CheckForCatalogUpdates(false);
PostNotification(GlobalDefine.EVENT_CHECK_ASSET, (AsyncOperationHandle)checkHandle, "检查资源更新");
yield return checkHandle;
if (checkHandle.Result.Count > 0)
{
Debug.Log("有更新的CataLogs");
//ShowInfo("有更新的CataLog Count : " + checkHandle.Result.Count);
var updateHandle = Addressables.UpdateCatalogs(checkHandle.Result, false);
PostNotification(GlobalDefine.EVENT_UPDATE_ASSET, (AsyncOperationHandle)updateHandle, "更新资源目录");
yield return updateHandle;
var locators = updateHandle.Result;
foreach (var locator in locators)
{
var sizeHandle = Addressables.GetDownloadSizeAsync(locator.Keys);
yield return sizeHandle;
var downloadSize = sizeHandle.Result;
Debug.Log("下载资源大小: " + downloadSize);
Addressables.Release(sizeHandle);
if (downloadSize > 0)
{
var downloadHandle = Addressables.DownloadDependenciesAsync(locator.Keys, Addressables.MergeMode.Union);
PostNotification(GlobalDefine.EVENT_DOWNLOAD_ASSET, downloadHandle, $"下载{locator.ToString()}");
while (!downloadHandle.IsDone)
{
yield return null;
}
Debug.Log($"{locator.ToString()}下载完成");
Addressables.Release(downloadHandle);
}
}
Debug.Log("更新完成");
Addressables.Release(updateHandle);
}
else
{
Debug.Log("没有要更新的内容");
}
Addressables.Release(checkHandle);
callback?.Invoke(0, "");
callback = null;
}
public void Repair()
{
Addressables.ClearResourceLocators();
Caching.ClearCache();
}
/// <summary>
/// (手动加载)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<TObject> GetAssetAsync<TObject>(string key)
{
return Addressables.LoadAssetAsync<TObject>(key);
}
/// <summary>
/// (手动加载)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<IList<TObject>> GetAssetsAsync<TObject>(string key)
{
return Addressables.LoadAssetsAsync<TObject>(key, null);
}
/// <summary>
/// (手动释放)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="obj"></param>
public void Release<TObject>(TObject obj)
{
Addressables.Release(obj);
}
/// <summary>
/// (手动释放)
/// </summary>
/// <param name="handle"></param>
public void Release(AsyncOperationHandle handle)
{
Addressables.Release(handle);
}
/// <summary>
/// (手动释放)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="handle"></param>
public void Release<TObject>(AsyncOperationHandle<TObject> handle)
{
Addressables.Release(handle);
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public AsyncOperationHandle<GameObject> InstantiateAsync(string name)
{
string key = name;// "UI/" + name + ".prefab";
var resultT = Addressables.InstantiateAsync(key);
return resultT;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="parent"></param>
/// <returns></returns>
public AsyncOperationHandle<GameObject> InstantiateAsync(string name, Transform parent)
{
string key = name;// "UI/" + name + ".prefab";
var resultT = Addressables.InstantiateAsync(key, parent);
return resultT;
}
/// <summary>
///
/// </summary>
/// <param name="handle"></param>
/// <returns></returns>
public bool ReleaseInstance(AsyncOperationHandle handle)
{
return Addressables.ReleaseInstance(handle);
}
/// <summary>
///
/// </summary>
/// <param name="handle"></param>
/// <returns></returns>
public bool ReleaseInstance(AsyncOperationHandle<GameObject> handle)
{
return Addressables.ReleaseInstance(handle);
}
/// <summary>
///
/// </summary>
/// <param name="instance"></param>
public bool ReleaseInstance(GameObject instance)
{
return Addressables.ReleaseInstance(instance);
}
/// <summary>
/// 使用自动释放池
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<TObject> TryGetAssetAsync<TObject>(string key, string pool)
{
if (TryGetHandleInReleasePool(key, out AsyncOperationHandle result, pool))
{
return result.Convert<TObject>();
}
var resultT = Addressables.LoadAssetAsync<TObject>(key);
AddHandleToReleasePool(key, resultT, pool);
return resultT;
}
/// <summary>
/// 使用自动释放池
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<IList<TObject>> TryGetAssetsAsync<TObject>(string key, string pool)
{
if (TryGetHandleInReleasePool(key, out AsyncOperationHandle result, pool))
{
return result.Convert<IList<TObject>>();
}
var resultT = Addressables.LoadAssetsAsync<TObject>(key, null);
AddHandleToReleasePool(key, resultT, pool);
return resultT;
}
/// <summary>
/// 全局(游戏关闭时释放)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<TObject> TryGetGlobalAssetAsync<TObject>(string key)
{
return TryGetAssetAsync<TObject>(key, GLOBAL_ASSET_POOL_NAME);
}
/// <summary>
/// 全局(游戏关闭时释放)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<IList<TObject>> TryGetGlobalAssetsAsync<TObject>(string key)
{
return TryGetAssetsAsync<TObject>(key, GLOBAL_ASSET_POOL_NAME);
}
/// <summary>
/// 临时(场景切换时释放)
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<TObject> TryGetTemporaryAssetAsync<TObject>(string key)
{
return TryGetAssetAsync<TObject>(key, TEMPORARY_ASSET_POOL_NAME);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public AsyncOperationHandle<IList<TObject>> TryGetTemporaryAssetsAsync<TObject>(string key)
{
return TryGetAssetsAsync<TObject>(key, TEMPORARY_ASSET_POOL_NAME);
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public AsyncOperationHandle<GameObject> TryInstantiateAsync(string name, Transform parent)
{
string key = name;// "UI/" + name + ".prefab";
if (TryGetHandleInReleasePool(key, out AsyncOperationHandle result, INSTANCES_POOL_NAME))
{
return result.Convert<GameObject>();
}
var resultT = Addressables.InstantiateAsync(key, parent);
AddHandleToReleasePool(key, resultT, INSTANCES_POOL_NAME);
return resultT;
}
/// <summary>
/// ui框架
/// </summary>
/// <param name="key"></param>
/// <param name="callback"></param>
public void UIAsyncInstantiater(string name, Transform parent, Action<Object> callback)
{
string key = name;// "UI/" + name + ".prefab";
if (TryGetHandleInReleasePool(key, out AsyncOperationHandle result, INSTANCES_POOL_NAME))
{
var handle = result.Convert<GameObject>();
if (handle.Result)
handle.Result.transform.SetParent(parent);
callback?.Invoke(handle.Result);
return;
}
var resultT = Addressables.InstantiateAsync(key, parent);
resultT.Completed += (handle) =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
var instance = handle.Result;
instance.name = System.IO.Path.GetFileNameWithoutExtension(key);
callback?.Invoke(handle.Result);
}
};
AddHandleToReleasePool(key, resultT, INSTANCES_POOL_NAME);
}
/// <summary>
/// ui框架
/// </summary>
/// <param name="instance"></param>
public void UIReleaser(Object instance)
{
RemoveHandleInReleasePool(instance.name, INSTANCES_POOL_NAME);
Addressables.ReleaseInstance((GameObject)instance);
}
#endregion
#region UNITY
public AssetProxy()
{
_Instance = this;
UnityEngine.SceneManagement.SceneManager.sceneLoaded += this.SceneManager_sceneLoaded;
UnityEngine.SceneManagement.SceneManager.sceneUnloaded += this.SceneManager_sceneUnloaded;
Application.lowMemory += OnLowMemoryCallback;
}
#endregion
#region STATIC
private static AssetProxy _Instance;
public static AssetProxy Instance
{
get { return _Instance; }
}
#endregion
}
}