using System; using System.Collections.Generic; using CustomUtility; using Definition; using GameFramework.Resource; using UnityEngine; using UnityGameFramework.Runtime; namespace CustomComponent { public class SpriteCacheComponent : GameFrameworkComponent { [SerializeField] private float _pixelsPerUnit = 100f; [SerializeField] private Vector2 _defaultPivot = new(0.5f, 0.5f); private Dictionary _spriteCache; private Dictionary>> _pendingCallbacks; private HashSet _loadingSpriteAssets; private ResourceComponent _resource; void Start() { EnsureRuntimeCaches(); } private void EnsureRuntimeCaches() { _spriteCache ??= new Dictionary(); _pendingCallbacks ??= new Dictionary>>(); _loadingSpriteAssets ??= new HashSet(); _resource ??= GameEntry.Resource; } public bool TryGetCachedSprite(string assetName, out Sprite sprite) { EnsureRuntimeCaches(); if (string.IsNullOrWhiteSpace(assetName)) { sprite = null; return false; } return _spriteCache.TryGetValue(assetName, out sprite); } public void GetSprite(string assetName, Action callback) { EnsureRuntimeCaches(); if (string.IsNullOrWhiteSpace(assetName)) { callback?.Invoke(null); return; } if (_spriteCache.TryGetValue(assetName, out var sprite)) { callback?.Invoke(sprite); return; } if (callback != null) { AddPendingCallback(assetName, callback); } if (_loadingSpriteAssets.Contains(assetName)) { return; } _loadingSpriteAssets.Add(assetName); StartLoadSprite(assetName); } public void PreloadSprite(string assetName) { EnsureRuntimeCaches(); if (string.IsNullOrWhiteSpace(assetName) || _spriteCache.ContainsKey(assetName) || _loadingSpriteAssets.Contains(assetName)) { return; } _loadingSpriteAssets.Add(assetName); StartLoadSprite(assetName); } public void PreloadSprites(IEnumerable assetNames) { EnsureRuntimeCaches(); if (assetNames == null) { return; } foreach (string assetName in assetNames) { PreloadSprite(assetName); } } public void RegisterSprite(string assetName, Sprite sprite, bool overwrite = true) { EnsureRuntimeCaches(); if (string.IsNullOrWhiteSpace(assetName) || sprite == null) { return; } if (!overwrite && _spriteCache.ContainsKey(assetName)) { return; } _spriteCache[assetName] = sprite; InvokeAndClearPendingCallbacks(assetName, sprite); _loadingSpriteAssets.Remove(assetName); } private void StartLoadSprite(string assetName) { EnsureRuntimeCaches(); if (_resource == null) { InvokeAndClearPendingCallbacks(assetName, null); _loadingSpriteAssets.Remove(assetName); return; } _resource.LoadAsset ( AssetUtility.GetUISpriteAsset(assetName), Constant.AssetPriority.UIFormAsset, new LoadAssetCallbacks( (resourcePath, asset, duration, userData) => { Texture2D texture = asset as Texture2D; Sprite loadedSprite = null; if (texture != null) { loadedSprite = Sprite.Create( texture, new Rect(0, 0, texture.width, texture.height), _defaultPivot, _pixelsPerUnit); _spriteCache[assetName] = loadedSprite; } else { Log.Warning("Load sprite succeeded but asset is not Texture2D. AssetName='{0}', Path='{1}'.", assetName, resourcePath); } InvokeAndClearPendingCallbacks(assetName, loadedSprite); _loadingSpriteAssets.Remove(assetName); }, (resourcePath, status, errorMessage, userData) => { Log.Error("Can not load icon '{0}' from '{1}' with error message '{2}'.", assetName, resourcePath, errorMessage); InvokeAndClearPendingCallbacks(assetName, null); _loadingSpriteAssets.Remove(assetName); } ) ); } private void AddPendingCallback(string assetName, Action callback) { EnsureRuntimeCaches(); if (!_pendingCallbacks.TryGetValue(assetName, out List> callbackList)) { callbackList = new List>(); _pendingCallbacks.Add(assetName, callbackList); } callbackList.Add(callback); } private void InvokeAndClearPendingCallbacks(string assetName, Sprite sprite) { EnsureRuntimeCaches(); if (!_pendingCallbacks.TryGetValue(assetName, out List> callbackList)) { return; } _pendingCallbacks.Remove(assetName); for (int i = 0; i < callbackList.Count; i++) { callbackList[i]?.Invoke(sprite); } } private void OnDestroy() { _spriteCache?.Clear(); _pendingCallbacks?.Clear(); _loadingSpriteAssets?.Clear(); _resource = null; } } }