using System; using AlicizaX; using UnityEngine; using UnityEngine.Serialization; using YooAsset; namespace AlicizaX.Resource.Runtime { /// /// 资源组件。 /// [DisallowMultipleComponent] public class ResourceComponent : MonoBehaviour { #region Propreties private const int DEFAULT_PRIORITY = 0; private IResourceModule _resourceModule; private bool _forceUnloadUnusedAssets = false; private bool _preorderUnloadUnusedAssets = false; private bool _performGCCollect = false; private AsyncOperation _asyncOperation = null; private float _lastUnloadUnusedAssetsOperationElapseSeconds = 0f; [SerializeField] private float minUnloadUnusedAssetsInterval = 60f; [SerializeField] private float maxUnloadUnusedAssetsInterval = 300f; [SerializeField] private bool useSystemUnloadUnusedAssets = true; [SerializeField] private string _decryptionServices = ""; /// /// 当前最新的包裹版本。 /// public string PackageVersion { set; get; } /// /// 资源包名称。 /// [SerializeField] private string packageName = "DefaultPackage"; /// /// 资源包名称。 /// public string PackageName { get => packageName; set => packageName = value; } /// /// 设置异步系统参数,每帧执行消耗的最大时间切片(单位:毫秒) /// [SerializeField] public long milliseconds = 30; public int downloadingMaxNum = 10; /// /// 获取或设置同时最大下载数目。 /// public int DownloadingMaxNum { get => downloadingMaxNum; set => downloadingMaxNum = value; } [SerializeField] public int failedTryAgain = 3; public int FailedTryAgain { get => failedTryAgain; set => failedTryAgain = value; } /// /// 获取当前资源适用的游戏版本号。 /// public string ApplicableGameVersion => _resourceModule.ApplicableGameVersion; /// /// 获取当前内部资源版本号。 /// public int InternalResourceVersion => _resourceModule.InternalResourceVersion; /// /// 获取或设置无用资源释放的最小间隔时间,以秒为单位。 /// public float MinUnloadUnusedAssetsInterval { get => minUnloadUnusedAssetsInterval; set => minUnloadUnusedAssetsInterval = value; } /// /// 获取或设置无用资源释放的最大间隔时间,以秒为单位。 /// public float MaxUnloadUnusedAssetsInterval { get => maxUnloadUnusedAssetsInterval; set => maxUnloadUnusedAssetsInterval = value; } /// /// 使用系统释放无用资源策略。 /// public bool UseSystemUnloadUnusedAssets { get => useSystemUnloadUnusedAssets; set => useSystemUnloadUnusedAssets = value; } /// /// 获取无用资源释放的等待时长,以秒为单位。 /// public float LastUnloadUnusedAssetsOperationElapseSeconds => _lastUnloadUnusedAssetsOperationElapseSeconds; [SerializeField] private float assetAutoReleaseInterval = 60f; [SerializeField] private int assetCapacity = 64; [SerializeField] private float assetExpireTime = 60f; [SerializeField] private int assetPriority = 0; /// /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 /// public float AssetAutoReleaseInterval { get => _resourceModule.AssetAutoReleaseInterval; set => _resourceModule.AssetAutoReleaseInterval = assetAutoReleaseInterval = value; } /// /// 获取或设置资源对象池的容量。 /// public int AssetCapacity { get => _resourceModule.AssetCapacity; set => _resourceModule.AssetCapacity = assetCapacity = value; } /// /// 获取或设置资源对象池对象过期秒数。 /// public float AssetExpireTime { get => _resourceModule.AssetExpireTime; set => _resourceModule.AssetExpireTime = assetExpireTime = value; } /// /// 获取或设置资源对象池的优先级。 /// public int AssetPriority { get => _resourceModule.AssetPriority; set => _resourceModule.AssetPriority = assetPriority = value; } #endregion private void Awake() { _resourceModule = ModuleSystem.RegisterModule(); if (_resourceModule == null) { Log.Error("Resource module is invalid."); return; } Application.lowMemory += OnLowMemory; } public static string PrefsKey = Application.dataPath.GetHashCode() + "GamePlayMode"; private void Start() { EPlayMode playMode = EPlayMode.EditorSimulateMode; #if UNITY_EDITOR playMode = (EPlayMode)UnityEditor.EditorPrefs.GetInt(PrefsKey, 0); #else playMode = (EPlayMode)AppBuilderSetting.Instance.ResMode; #endif _resourceModule.DefaultPackageName = PackageName; _resourceModule.DecryptionServices = _decryptionServices; _resourceModule.PlayMode = playMode; _resourceModule.Milliseconds = milliseconds; _resourceModule.DownloadingMaxNum = DownloadingMaxNum; _resourceModule.FailedTryAgain = FailedTryAgain; _resourceModule.Initialize(); _resourceModule.AssetAutoReleaseInterval = assetAutoReleaseInterval; _resourceModule.AssetCapacity = assetCapacity; _resourceModule.AssetExpireTime = assetExpireTime; _resourceModule.AssetPriority = assetPriority; _resourceModule.SetForceUnloadUnusedAssetsAction(ForceUnloadUnusedAssets); Log.Info($"ResourceModule Run Mode:{playMode}"); } private void OnApplicationQuit() { Application.lowMemory -= OnLowMemory; } #region 释放资源 /// /// 强制执行释放未被使用的资源。 /// /// 是否使用垃圾回收。 public void ForceUnloadUnusedAssets(bool performGCCollect) { _forceUnloadUnusedAssets = true; if (performGCCollect) { _performGCCollect = true; } } private void Update() { _lastUnloadUnusedAssetsOperationElapseSeconds += Time.unscaledDeltaTime; if (_asyncOperation == null && (_forceUnloadUnusedAssets || _lastUnloadUnusedAssetsOperationElapseSeconds >= maxUnloadUnusedAssetsInterval || _preorderUnloadUnusedAssets && _lastUnloadUnusedAssetsOperationElapseSeconds >= minUnloadUnusedAssetsInterval)) { Log.Info("Unload unused assets..."); _forceUnloadUnusedAssets = false; _preorderUnloadUnusedAssets = false; _lastUnloadUnusedAssetsOperationElapseSeconds = 0f; _asyncOperation = Resources.UnloadUnusedAssets(); if (useSystemUnloadUnusedAssets) { _resourceModule.UnloadUnusedAssets(); } } if (_asyncOperation is { isDone: true }) { _asyncOperation = null; if (_performGCCollect) { Log.Info("GC.Collect..."); _performGCCollect = false; GC.Collect(); } } } private void OnLowMemory() { Log.Warning("Low memory reported..."); if (_resourceModule != null) { _resourceModule.OnLowMemory(); } } #endregion } }