yyl
2025-12-26 5e4c574228c7cfadab0931a798d43b085bfb8844
Main/System/Battle/BattleResources/BattleCacheManager.cs
@@ -72,9 +72,10 @@
            
            if (!globalSpineCache.ContainsKey(key))
            {
                // 把 ResourceIdentifier 的 IsPersistent 传递给 CachedResource
                globalSpineCache[key] = new ResourceReference
                {
                    CachedResource = new BattleResCache.CachedResource(res, null, false)
                    CachedResource = new BattleResCache.CachedResource(res, null, res.IsPersistent)
                };
            }
            
@@ -91,9 +92,10 @@
            
            if (!globalAudioCache.ContainsKey(key))
            {
                // 把 ResourceIdentifier 的 IsPersistent 传递给 CachedResource
                globalAudioCache[key] = new ResourceReference
                {
                    CachedResource = new BattleResCache.CachedResource(res, null, false)
                    CachedResource = new BattleResCache.CachedResource(res, null, res.IsPersistent)
                };
            }
            
@@ -106,7 +108,9 @@
    /// <summary>
    /// 注销战场(卸载该战场的所有资源引用)
    /// </summary>
    public void UnregisterBattlefield(string battleGuid)
    /// <param name="battleGuid">战场GUID</param>
    /// <param name="forceUnloadPersistent">是否强制卸载常驻(红队)资源,默认为 false</param>
    public void UnregisterBattlefield(string battleGuid, bool forceUnloadPersistent = false)
    {
        // 处理Spine资源
        var spineKeysToRemove = new List<string>();
@@ -116,7 +120,15 @@
            
            if (kvp.Value.RefCount == 0)
            {
                spineKeysToRemove.Add(kvp.Key);
                // 仅在非常驻或被强制卸载时才真正移除资源
                if (forceUnloadPersistent || kvp.Value.CachedResource.CanUnload())
                {
                    spineKeysToRemove.Add(kvp.Key);
                }
                else
                {
                    Debug.Log($"BattleCacheManager: Skipped unloading persistent spine resource: {kvp.Key}");
                }
            }
        }
        
@@ -142,7 +154,15 @@
            
            if (kvp.Value.RefCount == 0)
            {
                audioKeysToRemove.Add(kvp.Key);
                // 仅在非常驻或被强制卸载时才真正移除资源
                if (forceUnloadPersistent || kvp.Value.CachedResource.CanUnload())
                {
                    audioKeysToRemove.Add(kvp.Key);
                }
                else
                {
                    Debug.Log($"BattleCacheManager: Skipped unloading persistent audio resource: {kvp.Key}");
                }
            }
        }
        
@@ -185,12 +205,13 @@
            {
                Directory = directory,
                AssetName = assetName,
                Type = BattleResCache.ResourceType.Spine
                Type = BattleResCache.ResourceType.Spine,
                IsPersistent = false // on-demand 加载的默认非常驻
            };
            
            globalSpineCache[key] = new ResourceReference
            {
                CachedResource = new BattleResCache.CachedResource(identifier, asset, false)
                CachedResource = new BattleResCache.CachedResource(identifier, asset, identifier.IsPersistent)
            };
        }
        
@@ -219,12 +240,13 @@
            {
                Directory = directory,
                AssetName = assetName,
                Type = BattleResCache.ResourceType.Audio
                Type = BattleResCache.ResourceType.Audio,
                IsPersistent = false // on-demand 加载的默认非常驻
            };
            
            globalAudioCache[key] = new ResourceReference
            {
                CachedResource = new BattleResCache.CachedResource(identifier, asset, false)
                CachedResource = new BattleResCache.CachedResource(identifier, asset, identifier.IsPersistent)
            };
        }
        
@@ -236,6 +258,9 @@
    /// </summary>
    public void UpdateResourceReference(string key, BattleResCache.CachedResource resource, string battleGuid, string ownerId)
    {
        // 确保 CachedResource 的 IsPersistent 与 Identifier 一致
        resource.IsPersistent = resource.Identifier.IsPersistent;
        if (resource.Identifier.Type == BattleResCache.ResourceType.Spine)
        {
            if (globalSpineCache.ContainsKey(key))
@@ -259,6 +284,161 @@
        
        return $"Spine: {spineTotal}, Audio: {audioTotal}";
    }
    /// <summary>
    /// 获取已注册到某个战场的所有 OwnerId(可选择只返回常驻资源的 owner)
    /// </summary>
    public HashSet<string> GetRegisteredOwners(string battleGuid, bool onlyPersistent = false)
    {
        var owners = new HashSet<string>();
        foreach (var kvp in globalSpineCache)
        {
            if (!kvp.Value.BattlefieldOwners.ContainsKey(battleGuid))
                continue;
            if (onlyPersistent && kvp.Value.CachedResource.IsPersistent == false)
                continue;
            foreach (var owner in kvp.Value.BattlefieldOwners[battleGuid])
                owners.Add(owner);
        }
        foreach (var kvp in globalAudioCache)
        {
            if (!kvp.Value.BattlefieldOwners.ContainsKey(battleGuid))
                continue;
            if (onlyPersistent && kvp.Value.CachedResource.IsPersistent == false)
                continue;
            foreach (var owner in kvp.Value.BattlefieldOwners[battleGuid])
                owners.Add(owner);
        }
        return owners;
    }
    /// <summary>
    /// 仅注销战场中指定的 owner(按 owner granularity 移除),仅卸载因此变为无人引用的资源
    /// </summary>
    /// <param name="battleGuid">战场 GUID</param>
    /// <param name="ownersToRemove">要移除的 OwnerId 集合</param>
    public void UnregisterBattlefieldOwners(string battleGuid, HashSet<string> ownersToRemove)
    {
        if (ownersToRemove == null || ownersToRemove.Count == 0)
        {
            Debug.Log($"BattleCacheManager: UnregisterBattlefieldOwners called with empty owners for {battleGuid}");
            return;
        }
        var spineKeysToRemove = new List<string>();
        foreach (var kvp in globalSpineCache)
        {
            if (!kvp.Value.BattlefieldOwners.ContainsKey(battleGuid))
                continue;
            var owners = kvp.Value.BattlefieldOwners[battleGuid];
            bool changed = false;
            foreach (var owner in ownersToRemove)
            {
                if (owners.Contains(owner))
                {
                    owners.Remove(owner);
                    changed = true;
                }
            }
            if (owners.Count == 0)
                kvp.Value.BattlefieldOwners.Remove(battleGuid);
            // 如果全局引用数为0,说明没有任何战场/角色在使用这个资源,安全卸载
            if (kvp.Value.RefCount == 0)
            {
                spineKeysToRemove.Add(kvp.Key);
            }
            else if (changed)
            {
                Debug.Log($"BattleCacheManager: Updated spine owners for {kvp.Key} after removing owners for {battleGuid}");
            }
        }
        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 (no owners left): {key}");
        }
        var audioKeysToRemove = new List<string>();
        foreach (var kvp in globalAudioCache)
        {
            if (!kvp.Value.BattlefieldOwners.ContainsKey(battleGuid))
                continue;
            var owners = kvp.Value.BattlefieldOwners[battleGuid];
            bool changed = false;
            foreach (var owner in ownersToRemove)
            {
                if (owners.Contains(owner))
                {
                    owners.Remove(owner);
                    changed = true;
                }
            }
            if (owners.Count == 0)
                kvp.Value.BattlefieldOwners.Remove(battleGuid);
            if (kvp.Value.RefCount == 0)
            {
                audioKeysToRemove.Add(kvp.Key);
            }
            else if (changed)
            {
                Debug.Log($"BattleCacheManager: Updated audio owners for {kvp.Key} after removing owners for {battleGuid}");
            }
        }
        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 (no owners left): {key}");
        }
        Debug.Log($"BattleCacheManager: Unregistered specific owners for battlefield {battleGuid}. Removed owners: {ownersToRemove.Count}");
    }
    /// <summary>
    /// 判断该战场是否已注册(有任意资源引用)
    /// </summary>
    public bool HasBattleRegistered(string battleGuid)
    {
        foreach (var kvp in globalSpineCache)
        {
            if (kvp.Value.BattlefieldOwners.ContainsKey(battleGuid)) return true;
        }
        foreach (var kvp in globalAudioCache)
        {
            if (kvp.Value.BattlefieldOwners.ContainsKey(battleGuid)) return true;
        }
        return false;
    }
    
    // ===== 编辑器调试接口 =====
#if UNITY_EDITOR