using UnityEngine;
|
using System.Collections.Generic;
|
using Spine.Unity;
|
|
public class BattleCacheManager
|
{
|
/// <summary>
|
/// 资源引用信息
|
/// </summary>
|
private class ResourceReference
|
{
|
public BattleResCache.CachedResource CachedResource;
|
public HashSet<string> OwnerIds = new HashSet<string>(); // 使用该资源的角色ID集合
|
|
public int RefCount => OwnerIds.Count;
|
|
public void AddOwner(string ownerId)
|
{
|
OwnerIds.Add(ownerId);
|
}
|
|
public void RemoveOwner(string ownerId)
|
{
|
OwnerIds.Remove(ownerId);
|
}
|
}
|
|
// ===== 红队资源:全局共享,按引用计数管理 =====
|
private static Dictionary<string, ResourceReference> globalRedTeamSpineCache =
|
new Dictionary<string, ResourceReference>();
|
|
private static Dictionary<string, ResourceReference> globalRedTeamAudioCache =
|
new Dictionary<string, ResourceReference>();
|
|
// ===== 蓝队资源:按战场GUID隔离 =====
|
private static Dictionary<string, Dictionary<string, BattleResCache.CachedResource>> blueTeamSpineCacheDict =
|
new Dictionary<string, Dictionary<string, BattleResCache.CachedResource>>();
|
|
private static Dictionary<string, Dictionary<string, BattleResCache.CachedResource>> blueTeamAudioCacheDict =
|
new Dictionary<string, Dictionary<string, BattleResCache.CachedResource>>();
|
|
// 需要添加的字段
|
private static Dictionary<string, HashSet<string>> battlefieldRedTeamOwners =
|
new Dictionary<string, HashSet<string>>(); // <battleGuid, ownerIds>
|
|
/// <summary>
|
/// 获取Spine缓存(红队全局,蓝队按战场隔离)
|
/// </summary>
|
public Dictionary<string, BattleResCache.CachedResource> GetSpineCache(bool isPersistent, string battleGuid = "")
|
{
|
if (isPersistent)
|
{
|
// 红队:将引用字典转换为普通缓存字典(兼容加载器)
|
var cache = new Dictionary<string, BattleResCache.CachedResource>();
|
foreach (var kvp in globalRedTeamSpineCache)
|
{
|
cache[kvp.Key] = kvp.Value.CachedResource;
|
}
|
return cache;
|
}
|
else
|
{
|
// 蓝队:返回战场专属缓存
|
if (!blueTeamSpineCacheDict.ContainsKey(battleGuid))
|
{
|
blueTeamSpineCacheDict[battleGuid] = new Dictionary<string, BattleResCache.CachedResource>();
|
}
|
return blueTeamSpineCacheDict[battleGuid];
|
}
|
}
|
|
/// <summary>
|
/// 获取音频缓存(红队全局,蓝队按战场隔离)
|
/// </summary>
|
public Dictionary<string, BattleResCache.CachedResource> GetAudioCache(bool isPersistent, string battleGuid = "")
|
{
|
if (isPersistent)
|
{
|
// 红队:将引用字典转换为普通缓存字典
|
var cache = new Dictionary<string, BattleResCache.CachedResource>();
|
foreach (var kvp in globalRedTeamAudioCache)
|
{
|
cache[kvp.Key] = kvp.Value.CachedResource;
|
}
|
return cache;
|
}
|
else
|
{
|
// 蓝队:返回战场专属缓存
|
if (!blueTeamAudioCacheDict.ContainsKey(battleGuid))
|
{
|
blueTeamAudioCacheDict[battleGuid] = new Dictionary<string, BattleResCache.CachedResource>();
|
}
|
return blueTeamAudioCacheDict[battleGuid];
|
}
|
}
|
|
/// <summary>
|
/// 添加红队资源引用(由加载器调用)
|
/// </summary>
|
public void AddRedTeamSpineReference(string key, BattleResCache.CachedResource resource, string ownerId)
|
{
|
if (!globalRedTeamSpineCache.ContainsKey(key))
|
{
|
globalRedTeamSpineCache[key] = new ResourceReference
|
{
|
CachedResource = resource
|
};
|
}
|
globalRedTeamSpineCache[key].AddOwner(ownerId);
|
}
|
|
/// <summary>
|
/// 添加红队音频引用
|
/// </summary>
|
public void AddRedTeamAudioReference(string key, BattleResCache.CachedResource resource, string ownerId)
|
{
|
if (!globalRedTeamAudioCache.ContainsKey(key))
|
{
|
globalRedTeamAudioCache[key] = new ResourceReference
|
{
|
CachedResource = resource
|
};
|
}
|
globalRedTeamAudioCache[key].AddOwner(ownerId);
|
}
|
|
/// <summary>
|
/// 获取Spine资源(未命中时自动加载并缓存)
|
/// </summary>
|
public SkeletonDataAsset GetSpineResource(string directory, string assetName, string battleGuid = "", bool autoLoadIfMissing = true)
|
{
|
string key = $"{directory}/{assetName}";
|
|
// 优先从红队全局缓存查找
|
if (globalRedTeamSpineCache.TryGetValue(key, out var redRef))
|
{
|
return redRef.CachedResource.Asset as SkeletonDataAsset;
|
}
|
|
// 再从蓝队战场专属缓存查找
|
if (!string.IsNullOrEmpty(battleGuid) && blueTeamSpineCacheDict.TryGetValue(battleGuid, out var blueCache))
|
{
|
if (blueCache.TryGetValue(key, out var blueRes))
|
{
|
return blueRes.Asset as SkeletonDataAsset;
|
}
|
}
|
|
// ===== 缓存未命中时自动加载 =====
|
if (autoLoadIfMissing)
|
{
|
Debug.LogWarning($"BattleCacheManager: Spine cache miss for {key}, loading on-demand...");
|
|
SkeletonDataAsset asset = ResManager.Instance.LoadAsset<SkeletonDataAsset>(directory, assetName);
|
|
if (asset != null)
|
{
|
var identifier = new BattleResCache.ResourceIdentifier
|
{
|
Directory = directory,
|
AssetName = assetName,
|
Type = BattleResCache.ResourceType.Spine,
|
IsPersistent = string.IsNullOrEmpty(battleGuid)
|
};
|
|
var cachedRes = new BattleResCache.CachedResource(identifier, asset, identifier.IsPersistent);
|
|
if (string.IsNullOrEmpty(battleGuid))
|
{
|
// 红队:添加引用(未知所有者,用特殊标识)
|
AddRedTeamSpineReference(key, cachedRes, "OnDemand");
|
Debug.Log($"BattleCacheManager: Added to global red cache: {key}");
|
}
|
else
|
{
|
// 蓝队:直接加入战场缓存
|
if (!blueTeamSpineCacheDict.ContainsKey(battleGuid))
|
{
|
blueTeamSpineCacheDict[battleGuid] = new Dictionary<string, BattleResCache.CachedResource>();
|
}
|
blueTeamSpineCacheDict[battleGuid][key] = cachedRes;
|
Debug.Log($"BattleCacheManager: Added to blue cache (BF={battleGuid}): {key}");
|
}
|
|
return asset;
|
}
|
}
|
|
return null;
|
}
|
|
/// <summary>
|
/// 获取音频资源(未命中时自动加载并缓存)
|
/// </summary>
|
public AudioClip GetAudioResource(string directory, string assetName, string battleGuid = "", bool autoLoadIfMissing = true)
|
{
|
string key = $"{directory}/{assetName}";
|
|
// 优先从红队全局缓存查找
|
if (globalRedTeamAudioCache.TryGetValue(key, out var redRef))
|
{
|
return redRef.CachedResource.Asset as AudioClip;
|
}
|
|
// 再从蓝队战场专属缓存查找
|
if (!string.IsNullOrEmpty(battleGuid) && blueTeamAudioCacheDict.TryGetValue(battleGuid, out var blueCache))
|
{
|
if (blueCache.TryGetValue(key, out var blueRes))
|
{
|
return blueRes.Asset as AudioClip;
|
}
|
}
|
|
// ===== 缓存未命中时自动加载 =====
|
if (autoLoadIfMissing)
|
{
|
Debug.LogWarning($"BattleCacheManager: Audio cache miss for {key}, loading on-demand...");
|
|
AudioClip asset = ResManager.Instance.LoadAsset<AudioClip>(directory, assetName, false);
|
|
if (asset != null)
|
{
|
var identifier = new BattleResCache.ResourceIdentifier
|
{
|
Directory = directory,
|
AssetName = assetName,
|
Type = BattleResCache.ResourceType.Audio,
|
IsPersistent = string.IsNullOrEmpty(battleGuid)
|
};
|
|
var cachedRes = new BattleResCache.CachedResource(identifier, asset, identifier.IsPersistent);
|
|
if (string.IsNullOrEmpty(battleGuid))
|
{
|
// 红队:添加引用
|
AddRedTeamAudioReference(key, cachedRes, "OnDemand");
|
Debug.Log($"BattleCacheManager: Added to global red audio cache: {key}");
|
}
|
else
|
{
|
// 蓝队:直接加入战场缓存
|
if (!blueTeamAudioCacheDict.ContainsKey(battleGuid))
|
{
|
blueTeamAudioCacheDict[battleGuid] = new Dictionary<string, BattleResCache.CachedResource>();
|
}
|
blueTeamAudioCacheDict[battleGuid][key] = cachedRes;
|
Debug.Log($"BattleCacheManager: Added to blue audio cache (BF={battleGuid}): {key}");
|
}
|
|
return asset;
|
}
|
}
|
|
return null;
|
}
|
|
/// <summary>
|
/// 移除指定角色的红队资源引用
|
/// </summary>
|
public void RemoveRedTeamReferences(List<string> ownerIds)
|
{
|
if (ownerIds == null || ownerIds.Count == 0)
|
return;
|
|
int removedSpineCount = 0;
|
int removedAudioCount = 0;
|
|
// 处理Spine资源
|
var spineKeysToRemove = new List<string>();
|
foreach (var kvp in globalRedTeamSpineCache)
|
{
|
foreach (var ownerId in ownerIds)
|
{
|
kvp.Value.RemoveOwner(ownerId);
|
}
|
|
// 如果没有引用了,标记删除
|
if (kvp.Value.RefCount == 0)
|
{
|
spineKeysToRemove.Add(kvp.Key);
|
}
|
}
|
|
foreach (var key in spineKeysToRemove)
|
{
|
var resource = globalRedTeamSpineCache[key].CachedResource;
|
ResManager.Instance.UnloadAsset(
|
resource.Identifier.Directory.ToLower(),
|
resource.Identifier.AssetName.ToLower()
|
);
|
globalRedTeamSpineCache.Remove(key);
|
removedSpineCount++;
|
}
|
|
// 处理音频资源
|
var audioKeysToRemove = new List<string>();
|
foreach (var kvp in globalRedTeamAudioCache)
|
{
|
foreach (var ownerId in ownerIds)
|
{
|
kvp.Value.RemoveOwner(ownerId);
|
}
|
|
if (kvp.Value.RefCount == 0)
|
{
|
audioKeysToRemove.Add(kvp.Key);
|
}
|
}
|
|
foreach (var key in audioKeysToRemove)
|
{
|
var resource = globalRedTeamAudioCache[key].CachedResource;
|
ResManager.Instance.UnloadAsset(
|
resource.Identifier.Directory.ToLower(),
|
resource.Identifier.AssetName.ToLower()
|
);
|
globalRedTeamAudioCache.Remove(key);
|
removedAudioCount++;
|
}
|
|
Debug.Log($"BattleCacheManager: Removed {ownerIds.Count} owner(s), freed {removedSpineCount} spine + {removedAudioCount} audio resources");
|
}
|
|
/// <summary>
|
/// 清空指定战场的蓝队缓存
|
/// </summary>
|
public void ClearBlueTeamCache(string battleGuid)
|
{
|
if (blueTeamSpineCacheDict.ContainsKey(battleGuid))
|
{
|
blueTeamSpineCacheDict.Remove(battleGuid);
|
}
|
|
if (blueTeamAudioCacheDict.ContainsKey(battleGuid))
|
{
|
blueTeamAudioCacheDict.Remove(battleGuid);
|
}
|
|
Debug.Log($"BattleCacheManager: Cleared blue team cache for battlefield {battleGuid}");
|
}
|
|
/// <summary>
|
/// 清空红队全局缓存(玩家重置阵容时调用)
|
/// </summary>
|
public void ClearRedTeamCache()
|
{
|
globalRedTeamSpineCache.Clear();
|
globalRedTeamAudioCache.Clear();
|
Debug.Log("BattleCacheManager: Cleared red team global cache");
|
}
|
|
/// <summary>
|
/// 获取缓存统计信息
|
/// </summary>
|
public string GetCacheStats(string battleGuid = "")
|
{
|
int blueSpineCount = blueTeamSpineCacheDict.ContainsKey(battleGuid) ? blueTeamSpineCacheDict[battleGuid].Count : 0;
|
int blueAudioCount = blueTeamAudioCacheDict.ContainsKey(battleGuid) ? blueTeamAudioCacheDict[battleGuid].Count : 0;
|
|
return $"Red Spine: {globalRedTeamSpineCache.Count}, Red Audio: {globalRedTeamAudioCache.Count}, " +
|
$"Blue Spine (BF={battleGuid}): {blueSpineCount}, Blue Audio (BF={battleGuid}): {blueAudioCount}";
|
}
|
|
// ========== BattleCacheManager.cs 新增方法 ==========
|
|
/// <summary>
|
/// 记录战场的红队资源需求(增加引用)
|
/// </summary>
|
public void RegisterBattlefieldRedTeam(string battleGuid, List<BattleResCache.ResourceIdentifier> spineResources, List<BattleResCache.ResourceIdentifier> audioResources)
|
{
|
// 记录这个战场使用的红队资源的OwnerIds
|
var ownerIds = new HashSet<string>();
|
|
foreach (var res in spineResources)
|
{
|
if (!string.IsNullOrEmpty(res.OwnerId))
|
{
|
ownerIds.Add(res.OwnerId);
|
}
|
}
|
|
foreach (var res in audioResources)
|
{
|
if (!string.IsNullOrEmpty(res.OwnerId))
|
{
|
ownerIds.Add(res.OwnerId);
|
}
|
}
|
|
if (!battlefieldRedTeamOwners.ContainsKey(battleGuid))
|
{
|
battlefieldRedTeamOwners[battleGuid] = ownerIds;
|
}
|
}
|
|
/// <summary>
|
/// 注销战场的红队资源需求(减少引用)
|
/// </summary>
|
public void UnregisterBattlefieldRedTeam(string battleGuid)
|
{
|
if (!battlefieldRedTeamOwners.ContainsKey(battleGuid))
|
return;
|
|
var ownerIds = battlefieldRedTeamOwners[battleGuid];
|
|
// 从所有红队资源中移除这些OwnerIds的引用
|
RemoveOwnersFromRedTeamCache(ownerIds);
|
|
battlefieldRedTeamOwners.Remove(battleGuid);
|
}
|
|
private void RemoveOwnersFromRedTeamCache(HashSet<string> ownerIds)
|
{
|
// 处理Spine资源
|
var spineKeysToRemove = new List<string>();
|
foreach (var kvp in globalRedTeamSpineCache)
|
{
|
foreach (var ownerId in ownerIds)
|
{
|
kvp.Value.RemoveOwner(ownerId);
|
}
|
|
// 引用计数为0时真正卸载
|
if (kvp.Value.RefCount == 0)
|
{
|
spineKeysToRemove.Add(kvp.Key);
|
}
|
}
|
|
foreach (var key in spineKeysToRemove)
|
{
|
var res = globalRedTeamSpineCache[key];
|
ResManager.Instance.UnloadAsset(res.CachedResource.Identifier.Directory, res.CachedResource.Identifier.AssetName);
|
globalRedTeamSpineCache.Remove(key);
|
Debug.Log($"BattleCacheManager: Unloaded red team spine (refCount=0): {key}");
|
}
|
|
// 处理Audio资源
|
var audioKeysToRemove = new List<string>();
|
foreach (var kvp in globalRedTeamAudioCache)
|
{
|
foreach (var ownerId in ownerIds)
|
{
|
kvp.Value.RemoveOwner(ownerId);
|
}
|
|
if (kvp.Value.RefCount == 0)
|
{
|
audioKeysToRemove.Add(kvp.Key);
|
}
|
}
|
|
foreach (var key in audioKeysToRemove)
|
{
|
var res = globalRedTeamAudioCache[key];
|
ResManager.Instance.UnloadAsset(res.CachedResource.Identifier.Directory, res.CachedResource.Identifier.AssetName);
|
globalRedTeamAudioCache.Remove(key);
|
Debug.Log($"BattleCacheManager: Unloaded red team audio (refCount=0): {key}");
|
}
|
}
|
}
|