Implement MVP for the statue decoration minigame (#65)
MVP implemented with: - placing, removing etc. decorations - saving the state, displaying it on the map, restoring when game restarts - saving screenshots to folder on device Co-authored-by: Michal Pikulski <michal@foolhardyhorizons.com> Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #65
This commit is contained in:
104
Assets/Scripts/Utils/AddressablesUtility.cs
Normal file
104
Assets/Scripts/Utils/AddressablesUtility.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user