yyl
2025-12-03 b1b9a387a63e1ce77cf387b90ec170c7a05bb53b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
using UnityEngine;
using System.Collections.Generic;
using Spine.Unity;
 
public class BattleCacheManager
{
    /// <summary>
    /// 资源引用信息(战场 + 角色维度)
    /// </summary>
    private class ResourceReference
    {
        public BattleResCache.CachedResource CachedResource;
        // 记录哪些战场的哪些角色在使用这个资源
        // Key: battleGuid, Value: ownerIds
        public Dictionary<string, HashSet<string>> BattlefieldOwners = new Dictionary<string, HashSet<string>>();
        
        public int RefCount
        {
            get
            {
                int count = 0;
                foreach (var owners in BattlefieldOwners.Values)
                {
                    count += owners.Count;
                }
                return count;
            }
        }
        
        /// <summary>
        /// 添加战场+角色的引用
        /// </summary>
        public void AddBattlefieldOwner(string battleGuid, string ownerId)
        {
            if (!BattlefieldOwners.ContainsKey(battleGuid))
            {
                BattlefieldOwners[battleGuid] = new HashSet<string>();
            }
            BattlefieldOwners[battleGuid].Add(ownerId);
        }
        
        /// <summary>
        /// 移除整个战场的所有引用
        /// </summary>
        public void RemoveBattlefield(string battleGuid)
        {
            BattlefieldOwners.Remove(battleGuid);
        }
    }
    
    // ===== 全局统一资源池(不再区分红蓝队)=====
    private static Dictionary<string, ResourceReference> globalSpineCache = 
        new Dictionary<string, ResourceReference>();
    
    private static Dictionary<string, ResourceReference> globalAudioCache = 
        new Dictionary<string, ResourceReference>();
    
    /// <summary>
    /// 注册战场资源需求(红队+蓝队一起注册)
    /// </summary>
    public void RegisterBattlefieldResources(string battleGuid, 
        List<BattleResCache.ResourceIdentifier> spineResources, 
        List<BattleResCache.ResourceIdentifier> 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}");
    }
    
    /// <summary>
    /// 注销战场(卸载该战场的所有资源引用)
    /// </summary>
    public void UnregisterBattlefield(string battleGuid)
    {
        // 处理Spine资源
        var spineKeysToRemove = new List<string>();
        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<string>();
        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}");
    }
    
    /// <summary>
    /// 获取或加载Spine资源
    /// </summary>
    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<SkeletonDataAsset>(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;
    }
    
    /// <summary>
    /// 获取或加载Audio资源
    /// </summary>
    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<AudioClip>(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;
    }
    
    /// <summary>
    /// 更新已加载资源的引用(由加载器调用)
    /// </summary>
    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}";
    }
}