using UnityEngine; using System.Collections.Generic; using Spine.Unity; public class BattleCacheManager { /// /// 资源引用信息(战场 + 角色维度) /// private class ResourceReference { public BattleResCache.CachedResource CachedResource; // 记录哪些战场的哪些角色在使用这个资源 // Key: battleGuid, Value: ownerIds public Dictionary> BattlefieldOwners = new Dictionary>(); public int RefCount { get { int count = 0; foreach (var owners in BattlefieldOwners.Values) { count += owners.Count; } return count; } } /// /// 添加战场+角色的引用 /// public void AddBattlefieldOwner(string battleGuid, string ownerId) { if (!BattlefieldOwners.ContainsKey(battleGuid)) { BattlefieldOwners[battleGuid] = new HashSet(); } BattlefieldOwners[battleGuid].Add(ownerId); } /// /// 移除整个战场的所有引用 /// public void RemoveBattlefield(string battleGuid) { BattlefieldOwners.Remove(battleGuid); } } // ===== 全局统一资源池(不再区分红蓝队)===== private static Dictionary globalSpineCache = new Dictionary(); private static Dictionary globalAudioCache = new Dictionary(); /// /// 注册战场资源需求(红队+蓝队一起注册) /// public void RegisterBattlefieldResources(string battleGuid, List spineResources, List audioResources) { // 注册Spine资源 foreach (var res in spineResources) { if (string.IsNullOrEmpty(res.OwnerId)) continue; string key = res.GetKey(); if (!globalSpineCache.ContainsKey(key)) { globalSpineCache[key] = new ResourceReference { CachedResource = new BattleResCache.CachedResource(res, null, false) }; } globalSpineCache[key].AddBattlefieldOwner(battleGuid, res.OwnerId); } // 注册Audio资源 foreach (var res in audioResources) { if (string.IsNullOrEmpty(res.OwnerId)) continue; string key = res.GetKey(); if (!globalAudioCache.ContainsKey(key)) { globalAudioCache[key] = new ResourceReference { CachedResource = new BattleResCache.CachedResource(res, null, false) }; } globalAudioCache[key].AddBattlefieldOwner(battleGuid, res.OwnerId); } Debug.Log($"BattleCacheManager: Registered battlefield {battleGuid} - Spine: {spineResources.Count}, Audio: {audioResources.Count}"); } /// /// 注销战场(卸载该战场的所有资源引用) /// public void UnregisterBattlefield(string battleGuid) { // 处理Spine资源 var spineKeysToRemove = new List(); foreach (var kvp in globalSpineCache) { kvp.Value.RemoveBattlefield(battleGuid); if (kvp.Value.RefCount == 0) { spineKeysToRemove.Add(kvp.Key); } } foreach (var key in spineKeysToRemove) { var res = globalSpineCache[key]; if (res.CachedResource.Asset != null) { ResManager.Instance.UnloadAsset( res.CachedResource.Identifier.Directory, res.CachedResource.Identifier.AssetName ); } globalSpineCache.Remove(key); Debug.Log($"BattleCacheManager: Unloaded spine (refCount=0): {key}"); } // 处理Audio资源 var audioKeysToRemove = new List(); foreach (var kvp in globalAudioCache) { kvp.Value.RemoveBattlefield(battleGuid); if (kvp.Value.RefCount == 0) { audioKeysToRemove.Add(kvp.Key); } } foreach (var key in audioKeysToRemove) { var res = globalAudioCache[key]; if (res.CachedResource.Asset != null) { ResManager.Instance.UnloadAsset( res.CachedResource.Identifier.Directory, res.CachedResource.Identifier.AssetName ); } globalAudioCache.Remove(key); Debug.Log($"BattleCacheManager: Unloaded audio (refCount=0): {key}"); } Debug.Log($"BattleCacheManager: Unregistered battlefield {battleGuid}"); } /// /// 获取或加载Spine资源 /// public SkeletonDataAsset GetSpineResource(string directory, string assetName, string battleGuid = "") { string key = $"{directory}/{assetName}"; if (globalSpineCache.TryGetValue(key, out var refInfo)) { return refInfo.CachedResource.Asset as SkeletonDataAsset; } // 自动加载 Debug.LogWarning($"BattleCacheManager: Spine cache miss for {key}, loading on-demand..."); var asset = ResManager.Instance.LoadAsset(directory, assetName); if (asset != null) { var identifier = new BattleResCache.ResourceIdentifier { Directory = directory, AssetName = assetName, Type = BattleResCache.ResourceType.Spine }; globalSpineCache[key] = new ResourceReference { CachedResource = new BattleResCache.CachedResource(identifier, asset, false) }; } return asset; } /// /// 获取或加载Audio资源 /// public AudioClip GetAudioResource(string directory, string assetName, string battleGuid = "") { string key = $"{directory}/{assetName}"; if (globalAudioCache.TryGetValue(key, out var refInfo)) { return refInfo.CachedResource.Asset as AudioClip; } // 自动加载 Debug.LogWarning($"BattleCacheManager: Audio cache miss for {key}, loading on-demand..."); var asset = ResManager.Instance.LoadAsset(directory, assetName, false); if (asset != null) { var identifier = new BattleResCache.ResourceIdentifier { Directory = directory, AssetName = assetName, Type = BattleResCache.ResourceType.Audio }; globalAudioCache[key] = new ResourceReference { CachedResource = new BattleResCache.CachedResource(identifier, asset, false) }; } return asset; } /// /// 更新已加载资源的引用(由加载器调用) /// public void UpdateResourceReference(string key, BattleResCache.CachedResource resource, string battleGuid, string ownerId) { if (resource.Identifier.Type == BattleResCache.ResourceType.Spine) { if (globalSpineCache.ContainsKey(key)) { globalSpineCache[key].CachedResource = resource; } } else if (resource.Identifier.Type == BattleResCache.ResourceType.Audio) { if (globalAudioCache.ContainsKey(key)) { globalAudioCache[key].CachedResource = resource; } } } public string GetCacheStats(string battleGuid = "") { int spineTotal = globalSpineCache.Count; int audioTotal = globalAudioCache.Count; return $"Spine: {spineTotal}, Audio: {audioTotal}"; } }