614 lines
14 KiB
C#
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
|
|||
|
}
|
|||
|
}
|