Files
AppleHillsProduction/Assets/Scripts/Utils/AddressablesUtility.cs
Michal Pikulski 5bab6d9596 stash work
2025-11-27 11:29:45 +01:00

105 lines
4.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Core;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace Utils
{
/// <summary>
/// Utility class for common Addressables operations.
/// Provides generic methods for loading assets by label and creating lookup dictionaries.
/// </summary>
public static class AddressablesUtility
{
/// <summary>
/// Load all assets with a specific label and create a dictionary indexed by a key selector.
/// </summary>
/// <typeparam name="TAsset">Type of asset to load</typeparam>
/// <typeparam name="TKey">Type of key for dictionary</typeparam>
/// <param name="label">Addressables label to filter by</param>
/// <param name="keySelector">Function to extract key from asset (e.g., asset => asset.Id)</param>
/// <param name="onProgress">Optional callback for progress updates (0-1)</param>
/// <returns>Dictionary of assets indexed by key, and operation handle for cleanup</returns>
public static async Task<(Dictionary<TKey, TAsset> dictionary, AsyncOperationHandle<IList<TAsset>> handle)>
LoadAssetsByLabelAsync<TAsset, TKey>(
string label,
Func<TAsset, TKey> keySelector,
Action<float> onProgress = null)
{
Dictionary<TKey, TAsset> dictionary = new Dictionary<TKey, TAsset>();
// Load all assets with the specified label
AsyncOperationHandle<IList<TAsset>> handle = Addressables.LoadAssetsAsync<TAsset>(
label,
asset =>
{
// This callback is invoked for each asset as it loads
if (asset != null)
{
TKey key = keySelector(asset);
if (key != null && !dictionary.ContainsKey(key))
{
dictionary[key] = asset;
}
}
});
// Report progress if callback provided
while (!handle.IsDone)
{
onProgress?.Invoke(handle.PercentComplete);
await Task.Yield();
}
// Final progress update
onProgress?.Invoke(1f);
// Check if load was successful
if (handle.Status != AsyncOperationStatus.Succeeded)
{
Logging.Error($"[AddressablesUtility] Failed to load assets with label '{label}': {handle.OperationException?.Message}");
return (dictionary, handle);
}
Logging.Debug($"[AddressablesUtility] Loaded {dictionary.Count} assets with label '{label}'");
return (dictionary, handle);
}
/// <summary>
/// Load a single asset by address
/// </summary>
/// <typeparam name="TAsset">Type of asset to load</typeparam>
/// <param name="address">Addressable address/key</param>
/// <returns>Loaded asset and operation handle for cleanup</returns>
public static async Task<(TAsset asset, AsyncOperationHandle<TAsset> handle)> LoadAssetAsync<TAsset>(string address)
{
AsyncOperationHandle<TAsset> handle = Addressables.LoadAssetAsync<TAsset>(address);
await handle.Task;
if (handle.Status != AsyncOperationStatus.Succeeded)
{
Logging.Warning($"[AddressablesUtility] Failed to load asset '{address}': {handle.OperationException?.Message}");
return (default(TAsset), handle);
}
return (handle.Result, handle);
}
/// <summary>
/// Safely release an Addressables handle
/// </summary>
public static void ReleaseHandle<T>(AsyncOperationHandle<T> handle)
{
if (handle.IsValid())
{
Addressables.Release(handle);
}
}
}
}