Files

93 lines
3.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace HotUpdate.UI
{
/// <summary>
/// 异步加载并持有资源句柄,随 UiManager 销毁统一释放。
/// </summary>
public sealed class UiPrefabLoader : IDisposable
{
public const string PrefabFolder = "Assets/Bundles/UI/Prefab";
readonly ResourcePackage _preferredPackage;
readonly string _folder;
readonly Dictionary<string, GameObject> _cache = new Dictionary<string, GameObject>();
readonly List<AssetHandle> _handles = new List<AssetHandle>();
bool _disposed;
public ResourcePackage PreferredPackage => _preferredPackage;
public UiPrefabLoader(ResourcePackage preferredPackage = null, string folder = PrefabFolder)
{
_preferredPackage = preferredPackage;
_folder = folder;
}
public IEnumerator LoadAsync(string prefabName, Action<GameObject> onLoaded)
{
if (_disposed || string.IsNullOrEmpty(prefabName))
{
onLoaded?.Invoke(null);
yield break;
}
if (_cache.TryGetValue(prefabName, out var cached) && cached != null)
{
onLoaded?.Invoke(cached);
yield break;
}
var packages = new List<ResourcePackage>();
if (_preferredPackage != null) packages.Add(_preferredPackage);
if (YooAssets.IsInitialized)
{
foreach (var name in new[] { "DefaultPackage", "Art" })
if (YooAssets.TryGetPackage(name, out var pkg) && !packages.Contains(pkg))
packages.Add(pkg);
}
foreach (var package in packages)
{
if (package.InitializeStatus != EOperationStatus.Succeeded) continue;
foreach (var address in new[] { prefabName, $"{_folder}/{prefabName}.prefab" })
{
if (!package.IsLocationValid(address)) continue;
var handle = package.LoadAssetAsync<GameObject>(address);
_handles.Add(handle);
yield return handle;
if (_disposed) yield break;
if (handle.Status == EOperationStatus.Succeeded)
{
var prefab = handle.GetAssetObject<GameObject>();
if (prefab != null)
{
_cache[prefabName] = prefab;
onLoaded?.Invoke(prefab);
yield break;
}
}
_handles.Remove(handle);
handle.Release();
}
}
#if UNITY_EDITOR
var editorPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>($"{_folder}/{prefabName}.prefab");
if (editorPrefab != null) _cache[prefabName] = editorPrefab;
onLoaded?.Invoke(editorPrefab);
#else
onLoaded?.Invoke(null);
#endif
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
foreach (var handle in _handles) handle.Release();
_handles.Clear();
_cache.Clear();
}
}
}