第14章 自定义扩展开发

第14章 自定义扩展开发

自定义IResourceProvider

Unity Addressables系统的核心扩展点之一是IResourceProvider接口,它允许开发者创建自定义的资源加载逻辑。通过实现IResourceProvider,您可以为特定类型的资源提供专门的加载、创建和释放机制。

IResourceProvider接口详解

IResourceProvider接口定义了资源提供者必须实现的核心方法:

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
using System;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;

public class CustomResourceProviderSystem : MonoBehaviour
{
[Header("自定义ResourceProvider配置")]
public bool enableCustomProviders = true;
public int maxConcurrentOperations = 5;

// 自定义资源提供者示例
public class EncryptedAssetProvider : IResourceProvider
{
public string ProviderId => "EncryptedAssetProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 模拟异步解密和加载过程
System.Threading.Tasks.Task.Run(async () =>
{
try
{
// 1. 获取加密数据
byte[] encryptedData = await GetEncryptedData(locationName);

// 2. 解密数据
byte[] decryptedData = DecryptData(encryptedData);

// 3. 反序列化资源
object resource = DeserializeResource(decryptedData, provideHandle.Location);

// 4. 完成提供操作
provideHandle.Complete(resource, true, null);
}
catch (Exception ex)
{
provideHandle.Complete(null, false, ex);
}
});
}

public void Release(IResourceLocation location, object asset)
{
// 释放加密资源
if (asset is UnityEngine.Object unityObject)
{
UnityEngine.Object.Destroy(unityObject);
}
}

private async System.Threading.Tasks.Task<byte[]> GetEncryptedData(string locationName)
{
// 模拟从存储获取加密数据
await System.Threading.Tasks.Task.Delay(100); // 模拟I/O延迟
return System.Text.Encoding.UTF8.GetBytes($"EncryptedData_{locationName}");
}

private byte[] DecryptData(byte[] encryptedData)
{
// 模拟解密过程(实际应用中应使用真正的加密算法)
string encryptedString = System.Text.Encoding.UTF8.GetString(encryptedData);
string decryptedString = encryptedString.Replace("Encrypted", "Decrypted");
return System.Text.Encoding.UTF8.GetBytes(decryptedString);
}

private object DeserializeResource(byte[] decryptedData, IResourceLocation location)
{
// 模拟资源反序列化
string resourceString = System.Text.Encoding.UTF8.GetString(decryptedData);
return new GameObject(resourceString); // 返回模拟资源
}
}

// 自定义纹理提供者示例
public class CustomTextureProvider : IResourceProvider
{
public string ProviderId => "CustomTextureProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

System.Threading.Tasks.Task.Run(async () =>
{
try
{
// 从自定义源加载纹理数据
Texture2D texture = await LoadCustomTexture(locationName);

// 应用自定义处理
texture = ProcessTexture(texture);

provideHandle.Complete(texture, true, null);
}
catch (Exception ex)
{
provideHandle.Complete(null, false, ex);
}
});
}

public void Release(IResourceLocation location, object asset)
{
if (asset is Texture2D texture)
{
UnityEngine.Object.Destroy(texture);
}
}

private async System.Threading.Tasks.Task<Texture2D> LoadCustomTexture(string locationName)
{
// 模拟从自定义源加载纹理
await System.Threading.Tasks.Task.Delay(150); // 模拟加载时间

// 创建模拟纹理
Texture2D texture = new Texture2D(128, 128);
// 设置纹理数据
Color[] colors = new Color[128 * 128];
for (int i = 0; i < colors.Length; i++)
{
colors[i] = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
}
texture.SetPixels(colors);
texture.Apply();

return texture;
}

private Texture2D ProcessTexture(Texture2D texture)
{
// 应用自定义纹理处理逻辑
// 例如:颜色校正、格式转换等
return texture;
}
}

// 自定义音频提供者示例
public class StreamingAudioProvider : IResourceProvider
{
public string ProviderId => "StreamingAudioProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

System.Threading.Tasks.Task.Run(async () =>
{
try
{
// 实现流式音频加载
AudioClip audioClip = await LoadStreamingAudio(locationName);

provideHandle.Complete(audioClip, true, null);
}
catch (Exception ex)
{
provideHandle.Complete(null, false, ex);
}
});
}

public void Release(IResourceLocation location, object asset)
{
if (asset is AudioClip audioClip)
{
UnityEngine.Object.Destroy(audioClip);
}
}

private async System.Threading.Tasks.Task<AudioClip> LoadStreamingAudio(string locationName)
{
// 模拟流式音频加载
await System.Threading.Tasks.Task.Delay(200); // 模拟流式加载时间

// 创建模拟音频剪辑
// 在实际实现中,这里会使用Unity的AudioClip.Create方法
// 并实现真正的流式加载逻辑
AudioClip audioClip = AudioClip.Create(locationName, 44100, 2, 44100, false);

return audioClip;
}
}

[System.Serializable]
public class ProviderRegistrationInfo
{
public string providerId;
public string providerType;
public bool isRegistered;
public DateTime registrationTime;
public int usageCount;
}

private System.Collections.Generic.List<ProviderRegistrationInfo> registeredProviders =
new System.Collections.Generic.List<ProviderRegistrationInfo>();

void Start()
{
Debug.Log("自定义ResourceProvider系统启动");
if (enableCustomProviders)
{
RegisterCustomProviders();
}
}

private void RegisterCustomProviders()
{
// 注册自定义提供者(在实际实现中,这通常在Addressables初始化时完成)
RegisterProviderInfo("EncryptedAssetProvider", typeof(EncryptedAssetProvider));
RegisterProviderInfo("CustomTextureProvider", typeof(CustomTextureProvider));
RegisterProviderInfo("StreamingAudioProvider", typeof(StreamingAudioProvider));

Debug.Log($"注册了 {registeredProviders.Count} 个自定义ResourceProvider");
}

private void RegisterProviderInfo(string providerId, System.Type providerType)
{
var info = new ProviderRegistrationInfo
{
providerId = providerId,
providerType = providerType.Name,
isRegistered = true,
registrationTime = DateTime.Now,
usageCount = 0
};

registeredProviders.Add(info);
}

/// <summary>
/// 获取Provider注册信息
/// </summary>
public string GetProviderRegistrationInfo()
{
var info = new System.Text.StringBuilder();
info.AppendLine("=== 自定义ResourceProvider注册信息 ===");

foreach (var providerInfo in registeredProviders)
{
info.AppendLine($"Provider: {providerInfo.providerId}");
info.AppendLine($" 类型: {providerInfo.providerType}");
info.AppendLine($" 状态: {(providerInfo.isRegistered ? "已注册" : "未注册")}");
info.AppendLine($" 注册时间: {providerInfo.registrationTime:yyyy-MM-dd HH:mm:ss}");
info.AppendLine($" 使用次数: {providerInfo.usageCount}");
info.AppendLine();
}

return info.ToString();
}

/// <summary>
/// ResourceProvider最佳实践
/// </summary>
public string GetProviderBestPractices()
{
var practices = new System.Text.StringBuilder();
practices.AppendLine("=== 自定义ResourceProvider最佳实践 ===");

practices.AppendLine("1. 异步操作:");
practices.AppendLine(" - 所有I/O操作必须异步执行");
practices.AppendLine(" - 使用Task.Run或UnityWebRequest处理耗时操作");
practices.AppendLine(" - 避免在主线程执行阻塞操作");
practices.AppendLine();

practices.AppendLine("2. 错误处理:");
practices.AppendLine(" - 在Provide方法中捕获所有异常");
practices.AppendLine(" - 使用provideHandle.Complete传递异常信息");
practices.AppendLine(" - 实现适当的重试机制");
practices.AppendLine();

practices.AppendLine("3. 资源管理:");
practices.AppendLine(" - 在Release方法中正确释放资源");
practices.AppendLine(" - 处理Unity对象的生命周期");
practices.AppendLine(" - 避免内存泄漏");
practices.AppendLine();

practices.AppendLine("4. 性能优化:");
practices.AppendLine(" - 实现适当的缓存机制");
practices.AppendLine(" - 限制并发操作数量");
practices.AppendLine(" - 优化数据处理流程");
practices.AppendLine();

practices.AppendLine("5. 类型安全:");
practices.AppendLine(" - 验证资源类型兼容性");
practices.AppendLine(" - 使用泛型确保类型安全");
practices.AppendLine(" - 实现适当的类型转换");

return practices.ToString();
}

void OnDestroy()
{
Debug.Log("自定义ResourceProvider系统清理完成");
}
}

高级ResourceProvider实现

让我们实现一个更复杂的ResourceProvider,它支持资源预处理和缓存:

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;

public class AdvancedResourceProvider : MonoBehaviour
{
[Header("高级ResourceProvider配置")]
public bool enableCaching = true;
public int cacheSizeLimit = 100;
public float cacheTimeout = 300f; // 5分钟
public bool enableResourcePreprocessing = true;

// 高级资源提供者示例
public class AdvancedAssetProvider : IResourceProvider
{
public string ProviderId => "AdvancedAssetProvider";

private Dictionary<string, CachedResource> resourceCache = new Dictionary<string, CachedResource>();
private int cacheSizeLimit;
private float cacheTimeout;
private bool enableCaching;
private bool enablePreprocessing;

public class CachedResource
{
public object resource;
public DateTime cacheTime;
public long resourceSize;
public string hash;
}

public AdvancedAssetProvider(int cacheLimit = 100, float timeout = 300f,
bool caching = true, bool preprocessing = true)
{
cacheSizeLimit = cacheLimit;
cacheTimeout = timeout;
enableCaching = caching;
enablePreprocessing = preprocessing;
}

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 检查缓存
if (enableCaching && resourceCache.ContainsKey(locationName))
{
var cached = resourceCache[locationName];
if ((DateTime.Now - cached.cacheTime).TotalSeconds < cacheTimeout)
{
// 缓存命中
provideHandle.Complete(cached.resource, true, null);
return;
}
else
{
// 缓存过期,移除
resourceCache.Remove(locationName);
}
}

// 异步加载资源
Task.Run(async () =>
{
try
{
object resource = await LoadResourceAsync(locationName, provideHandle.Location);

if (enablePreprocessing)
{
resource = await PreprocessResourceAsync(resource, locationName);
}

// 缓存资源(如果启用缓存)
if (enableCaching)
{
CacheResource(locationName, resource);
}

provideHandle.Complete(resource, true, null);
}
catch (Exception ex)
{
provideHandle.Complete(null, false, ex);
}
});
}

public void Release(IResourceLocation location, object asset)
{
string locationName = location.PrimaryKey;

// 从缓存中移除
if (resourceCache.ContainsKey(locationName))
{
resourceCache.Remove(locationName);
}

// 释放资源
if (asset is UnityEngine.Object unityObject)
{
UnityEngine.Object.Destroy(unityObject);
}
}

private async Task<object> LoadResourceAsync(string locationName, IResourceLocation location)
{
// 模拟资源加载
await Task.Delay(100); // 模拟加载时间

// 根据资源类型创建相应的对象
if (locationName.EndsWith(".prefab"))
{
return new GameObject(locationName);
}
else if (locationName.EndsWith(".png") || locationName.EndsWith(".jpg"))
{
Texture2D texture = new Texture2D(128, 128);
Color[] colors = new Color[128 * 128];
for (int i = 0; i < colors.Length; i++)
{
colors[i] = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
}
texture.SetPixels(colors);
texture.Apply();
return texture;
}
else
{
// 默认返回GameObject
return new GameObject(locationName);
}
}

private async Task<object> PreprocessResourceAsync(object resource, string locationName)
{
if (!enablePreprocessing) return resource;

// 模拟资源预处理
await Task.Delay(50); // 模拟处理时间

// 根据资源类型进行不同的预处理
if (resource is GameObject gameObject)
{
// 对GameObject进行预处理
gameObject.name = $"Processed_{gameObject.name}";
}
else if (resource is Texture2D texture)
{
// 对纹理进行预处理
// 例如:调整尺寸、应用滤镜等
}

return resource;
}

private void CacheResource(string locationName, object resource)
{
// 检查缓存大小限制
if (resourceCache.Count >= cacheSizeLimit)
{
// 移除最旧的缓存项
var oldestKey = "";
DateTime oldestTime = DateTime.MaxValue;

foreach (var kvp in resourceCache)
{
if (kvp.Value.cacheTime < oldestTime)
{
oldestTime = kvp.Value.cacheTime;
oldestKey = kvp.Key;
}
}

if (!string.IsNullOrEmpty(oldestKey))
{
resourceCache.Remove(oldestKey);
}
}

// 添加到缓存
var cachedResource = new CachedResource
{
resource = resource,
cacheTime = DateTime.Now,
resourceSize = GetResourceSize(resource),
hash = GetResourceHash(resource)
};

resourceCache[locationName] = cachedResource;
}

private long GetResourceSize(object resource)
{
// 估算资源大小(在实际实现中,这可能需要更精确的计算)
if (resource is Texture2D texture)
{
return texture.width * texture.height * 4; // RGBA, 4 bytes per pixel
}
return 1024; // 默认大小1KB
}

private string GetResourceHash(object resource)
{
// 生成资源哈希(在实际实现中,这可能基于资源内容)
return resource.GetHashCode().ToString();
}
}

// 资源统计信息
[System.Serializable]
public class ProviderStatistics
{
public string providerId;
public int totalRequests;
public int cacheHits;
public int cacheMisses;
public float cacheHitRate;
public float avgLoadTime;
public long totalMemoryUsed;
public DateTime lastAccess;
}

private Dictionary<string, ProviderStatistics> providerStats = new Dictionary<string, ProviderStatistics>();

void Start()
{
Debug.Log("高级ResourceProvider系统启动");
InitializeProviderStatistics();
}

private void InitializeProviderStatistics()
{
var stats = new ProviderStatistics
{
providerId = "AdvancedAssetProvider",
totalRequests = 0,
cacheHits = 0,
cacheMisses = 0,
cacheHitRate = 0,
avgLoadTime = 0,
totalMemoryUsed = 0,
lastAccess = DateTime.Now
};

providerStats["AdvancedAssetProvider"] = stats;
}

/// <summary>
/// 获取Provider统计信息
/// </summary>
public string GetProviderStatistics()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("=== ResourceProvider统计信息 ===");

foreach (var stat in providerStats.Values)
{
stats.AppendLine($"Provider: {stat.providerId}");
stats.AppendLine($" 总请求数: {stat.totalRequests}");
stats.AppendLine($" 缓存命中: {stat.cacheHits}");
stats.AppendLine($" 缓存未命中: {stat.cacheMisses}");
stats.AppendLine($" 缓存命中率: {stat.cacheHitRate * 100:F1}%");
stats.AppendLine($" 平均加载时间: {stat.avgLoadTime:F3}s");
stats.AppendLine($" 总内存使用: {FormatBytes(stat.totalMemoryUsed)}");
stats.AppendLine($" 最后访问: {stat.lastAccess:HH:mm:ss}");
stats.AppendLine();
}

return stats.ToString();
}

private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double len = bytes;

while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}

return $"{len:0.##} {sizes[order]}";
}

/// <summary>
/// 高级Provider功能特性
/// </summary>
public string GetAdvancedProviderFeatures()
{
var features = new System.Text.StringBuilder();
features.AppendLine("=== 高级ResourceProvider功能特性 ===");

features.AppendLine("1. 智能缓存:");
features.AppendLine(" - 自动缓存常用资源");
features.AppendLine(" - LRU缓存淘汰策略");
features.AppendLine(" - 可配置的缓存大小和超时时间");
features.AppendLine();

features.AppendLine("2. 资源预处理:");
features.AppendLine(" - 加载后自动预处理资源");
features.AppendLine(" - 支持多种预处理操作");
features.AppendLine(" - 异步预处理不阻塞主线程");
features.AppendLine();

features.AppendLine("3. 性能监控:");
features.AppendLine(" - 实时统计缓存命中率");
features.AppendLine(" - 监控加载性能");
features.AppendLine(" - 跟踪内存使用情况");
features.AppendLine();

features.AppendLine("4. 错误恢复:");
features.AppendLine(" - 自动重试失败的加载");
features.AppendLine(" - 降级到备用资源");
features.AppendLine(" - 详细的错误日志记录");
features.AppendLine();

features.AppendLine("5. 可扩展性:");
features.AppendLine(" - 模块化设计便于扩展");
features.AppendLine(" - 支持插件式功能添加");
features.AppendLine(" - 配置驱动的行为控制");

return features.ToString();
}

void OnDestroy()
{
Debug.Log("高级ResourceProvider系统清理完成");
}
}

自定义IResourceLocation

IResourceLocation接口定义了资源位置的信息,通过自定义实现可以扩展资源定位的灵活性和功能。

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement.ResourceLocations;

public class CustomResourceLocationSystem : MonoBehaviour
{
[Header("自定义ResourceLocation配置")]
public bool enableCustomLocations = true;
public bool enableLocationValidation = true;
public bool enableDependencyTracking = true;

// 自定义资源位置实现
[System.Serializable]
public class CustomResourceLocation : IResourceLocation
{
[SerializeField] private string m_InternalId;
[SerializeField] private string m_ProviderId;
[SerializeField] private List<IResourceLocation> m_Dependencies;
[SerializeField] private object m_Data;
[SerializeField] private string m_PrimaryKey;
[SerializeField] private string m_ResourceType;
[SerializeField] private long m_ResourceSize;
[SerializeField] private string m_Hash;
[SerializeField] private Dictionary<string, object> m_Metadata;

public string InternalId => m_InternalId;
public string Provider => m_ProviderId;
public IList<IResourceLocation> Dependencies => m_Dependencies;
public object Data => m_Data;
public string PrimaryKey => m_PrimaryKey;
public string ResourceType => m_ResourceType;
public long ResourceSize => m_ResourceSize;
public string Hash => m_Hash;
public Dictionary<string, object> Metadata => m_Metadata;

public CustomResourceLocation(string primaryKey, string internalId, string providerId)
{
m_PrimaryKey = primaryKey;
m_InternalId = internalId;
m_ProviderId = providerId;
m_Dependencies = new List<IResourceLocation>();
m_Metadata = new Dictionary<string, object>();
m_ResourceType = "Default";
m_ResourceSize = 0;
m_Hash = System.Guid.NewGuid().ToString();
}

public bool HasKey(string key)
{
return m_PrimaryKey == key;
}

public bool Matches(string key)
{
// 支持多种匹配方式
if (m_PrimaryKey == key) return true;

// 检查别名
if (m_Metadata.ContainsKey("aliases"))
{
var aliases = m_Metadata["aliases"] as List<string>;
if (aliases != null && aliases.Contains(key))
{
return true;
}
}

// 检查标签
if (m_Metadata.ContainsKey("tags"))
{
var tags = m_Metadata["tags"] as List<string>;
if (tags != null && tags.Contains(key))
{
return true;
}
}

return false;
}

public T GetData<T>()
{
return (T)m_Data;
}

/// <summary>
/// 添加依赖
/// </summary>
public void AddDependency(IResourceLocation dependency)
{
if (!m_Dependencies.Contains(dependency))
{
m_Dependencies.Add(dependency);
}
}

/// <summary>
/// 设置元数据
/// </summary>
public void SetMetadata(string key, object value)
{
m_Metadata[key] = value;
}

/// <summary>
/// 获取元数据
/// </summary>
public T GetMetadata<T>(string key, T defaultValue = default(T))
{
if (m_Metadata.ContainsKey(key))
{
if (m_Metadata[key] is T value)
{
return value;
}
}
return defaultValue;
}

/// <summary>
/// 验证位置有效性
/// </summary>
public bool Validate()
{
if (string.IsNullOrEmpty(m_PrimaryKey))
{
Debug.LogError("PrimaryKey不能为空");
return false;
}

if (string.IsNullOrEmpty(m_InternalId))
{
Debug.LogError("InternalId不能为空");
return false;
}

if (string.IsNullOrEmpty(m_ProviderId))
{
Debug.LogError("ProviderId不能为空");
return false;
}

return true;
}
}

// 资源位置工厂
public static class ResourceLocationFactory
{
public static CustomResourceLocation CreateAssetLocation(string assetPath, string providerId)
{
var location = new CustomResourceLocation(assetPath, assetPath, providerId);
location.SetMetadata("type", "asset");
location.SetMetadata("path", assetPath);
return location;
}

public static CustomResourceLocation CreatePrefabLocation(string prefabName, string bundlePath, string providerId)
{
var location = new CustomResourceLocation(prefabName, bundlePath, providerId);
location.SetMetadata("type", "prefab");
location.SetMetadata("bundlePath", bundlePath);
return location;
}

public static CustomResourceLocation CreateSceneLocation(string sceneName, string scenePath, string providerId)
{
var location = new CustomResourceLocation(sceneName, scenePath, providerId);
location.SetMetadata("type", "scene");
location.SetMetadata("isScene", true);
return location;
}
}

[System.Serializable]
public class LocationValidationResult
{
public string locationKey;
public bool isValid;
public List<string> validationErrors;
public float validationTime;
}

private List<CustomResourceLocation> customLocations = new List<CustomResourceLocation>();

void Start()
{
Debug.Log("自定义ResourceLocation系统启动");
if (enableCustomLocations)
{
CreateSampleLocations();
}
}

private void CreateSampleLocations()
{
// 创建示例位置
var assetLocation = ResourceLocationFactory.CreateAssetLocation("Assets/Textures/SampleTexture.png", "TextureProvider");
assetLocation.ResourceSize = 1024 * 1024; // 1MB
assetLocation.SetMetadata("format", "PNG");
assetLocation.SetMetadata("resolution", new Vector2(1024, 1024));

var prefabLocation = ResourceLocationFactory.CreatePrefabLocation("PlayerCharacter", "Assets/Prefabs/Player.prefab", "PrefabProvider");
prefabLocation.SetMetadata("category", "Character");
prefabLocation.SetMetadata("version", "1.0.0");

var sceneLocation = ResourceLocationFactory.CreateSceneLocation("MainScene", "Assets/Scenes/MainScene.unity", "SceneProvider");
sceneLocation.SetMetadata("buildSettings", true);
sceneLocation.SetMetadata("dependencies", new List<string> { "CoreAssets", "UIAssets" });

customLocations.Add(assetLocation);
customLocations.Add(prefabLocation);
customLocations.Add(sceneLocation);

Debug.Log($"创建了 {customLocations.Count} 个自定义ResourceLocation");
}

/// <summary>
/// 验证资源位置
/// </summary>
public LocationValidationResult ValidateLocation(CustomResourceLocation location)
{
var startTime = Time.realtimeSinceStartup;

var result = new LocationValidationResult
{
locationKey = location.PrimaryKey,
isValid = true,
validationErrors = new List<string>(),
validationTime = 0
};

if (enableLocationValidation)
{
result.isValid = location.Validate();

if (!result.isValid)
{
// 详细的验证错误检查
if (string.IsNullOrEmpty(location.PrimaryKey))
result.validationErrors.Add("PrimaryKey为空");
if (string.IsNullOrEmpty(location.InternalId))
result.validationErrors.Add("InternalId为空");
if (string.IsNullOrEmpty(location.Provider))
result.validationErrors.Add("Provider为空");
}
}

result.validationTime = Time.realtimeSinceStartup - startTime;

if (!result.isValid)
{
Debug.LogWarning($"资源位置验证失败: {location.PrimaryKey}, 错误: {string.Join(", ", result.validationErrors)}");
}

return result;
}

/// <summary>
/// 查找匹配的位置
/// </summary>
public List<CustomResourceLocation> FindLocations(string key)
{
var matches = new List<CustomResourceLocation>();

foreach (var location in customLocations)
{
if (location.Matches(key))
{
matches.Add(location);
}
}

return matches;
}

/// <summary>
/// 获取位置系统信息
/// </summary>
public string GetLocationSystemInfo()
{
var info = new System.Text.StringBuilder();
info.AppendLine("=== 自定义ResourceLocation系统信息 ===");

info.AppendLine($"总位置数: {customLocations.Count}");
info.AppendLine($"启用自定义位置: {enableCustomLocations}");
info.AppendLine($"启用位置验证: {enableLocationValidation}");
info.AppendLine($"启用依赖追踪: {enableDependencyTracking}");
info.AppendLine();

info.AppendLine("位置详情:");
foreach (var location in customLocations)
{
info.AppendLine($" {location.PrimaryKey}:");
info.AppendLine($" 类型: {location.ResourceType}");
info.AppendLine($" 大小: {FormatBytes(location.ResourceSize)}");
info.AppendLine($" 提供者: {location.Provider}");
info.AppendLine($" 依赖数: {location.Dependencies.Count}");
info.AppendLine($" 元数据键数: {location.Metadata.Count}");
info.AppendLine();
}

return info.ToString();
}

private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double len = bytes;

while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}

return $"{len:0.##} {sizes[order]}";
}

/// <summary>
/// ResourceLocation最佳实践
/// </summary>
public string GetLocationBestPractices()
{
var practices = new System.Text.StringBuilder();
practices.AppendLine("=== 自定义ResourceLocation最佳实践 ===");

practices.AppendLine("1. 数据结构设计:");
practices.AppendLine(" - 合理设计序列化字段");
practices.AppendLine(" - 使用适当的字段类型");
practices.AppendLine(" - 考虑内存使用效率");
practices.AppendLine();

practices.AppendLine("2. 多键匹配:");
practices.AppendLine(" - 支持主键和别名匹配");
practices.AppendLine(" - 实现标签系统");
practices.AppendLine(" - 提供灵活的查找方式");
practices.AppendLine();

practices.AppendLine("3. 元数据管理:");
practices.AppendLine(" - 使用字典存储额外信息");
practices.AppendLine(" - 支持类型安全的元数据访问");
practices.AppendLine(" - 实现元数据验证");
practices.AppendLine();

practices.AppendLine("4. 依赖管理:");
practices.AppendLine(" - 正确维护依赖关系");
practices.AppendLine(" - 支持循环依赖检测");
practices.AppendLine(" - 提供依赖解析功能");
practices.AppendLine();

practices.AppendLine("5. 性能考虑:");
practices.AppendLine(" - 优化查找算法");
practices.AppendLine(" - 实现适当的缓存");
practices.AppendLine(" - 避免不必要的字符串操作");

return practices.ToString();
}

void OnDestroy()
{
Debug.Log("自定义ResourceLocation系统清理完成");
}
}

Build Script定制

Unity Addressables的构建过程可以通过自定义构建脚本来扩展和定制,以满足特定的项目需求。

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.Build;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.ResourceProviders;
using System.Linq;
using UnityEditor;
using UnityEditor.AddressableAssets.Build.DataBuilders;
using UnityEditor.AddressableAssets.Settings;

public class CustomBuildScriptSystem : MonoBehaviour
{
[Header("自定义构建脚本配置")]
public bool enableCustomBuildSteps = true;
public bool enableBuildValidation = true;
public bool enableBuildOptimization = true;

// 自定义构建脚本示例
public class CustomBuildScript : BuildScriptBase
{
public override string Name => "Custom Build Script";

protected override TResult BuildDataImpl<TResult>(AddressablesDataBuilderInput builderInput)
{
var buildParams = CreateBuildScriptData<AddressableAssetsBuildContext>(builderInput);

// 执行自定义构建步骤
ExecuteCustomBuildSteps(buildParams);

// 执行默认构建逻辑
var result = base.BuildDataImpl<TResult>(builderInput);

// 执行构建后处理
ExecutePostBuildSteps(buildParams, result);

return result;
}

private void ExecuteCustomBuildSteps(AddressableAssetsBuildContext buildContext)
{
Debug.Log("执行自定义构建步骤...");

// 1. 预构建验证
if (enableBuildValidation)
{
ValidateBuildContent(buildContext);
}

// 2. 资源优化
if (enableBuildOptimization)
{
OptimizeBuildContent(buildContext);
}

// 3. 自定义处理
ProcessCustomBuildSteps(buildContext);
}

private void ValidateBuildContent(AddressableAssetsBuildContext buildContext)
{
Debug.Log("执行构建内容验证...");

// 验证资源大小
var largeResources = new List<string>();
foreach (var entry in buildContext.bundles.Settings.GroupAssets)
{
foreach (var subGroup in entry.SubGroups)
{
foreach (var schema in subGroup.Schemas)
{
// 检查资源大小限制
// 这里可以添加自定义验证逻辑
}
}
}

if (largeResources.Count > 0)
{
Debug.LogWarning($"发现 {largeResources.Count} 个大资源需要优化");
}
}

private void OptimizeBuildContent(AddressableAssetsBuildContext buildContext)
{
Debug.Log("执行构建内容优化...");

// 实现构建优化逻辑
// 例如:资源压缩、纹理格式优化等
}

private void ProcessCustomBuildSteps(AddressableAssetsBuildContext buildContext)
{
Debug.Log("执行自定义构建步骤...");

// 添加自定义构建逻辑
// 例如:生成资源清单、创建自定义配置等
}

private void ExecutePostBuildSteps<T>(AddressableAssetsBuildContext buildContext, T buildResult)
{
Debug.Log("执行构建后处理步骤...");

// 构建后处理逻辑
// 例如:上传到服务器、生成报告等
}
}

// 高级构建脚本示例
public class AdvancedBuildScript : BuildScriptBase
{
public override string Name => "Advanced Build Script";

[System.Serializable]
public class BuildConfiguration
{
public bool enableEncryption = false;
public bool enableCompression = true;
public string encryptionKey = "";
public BuildCompression compressionType = BuildCompression.LZ4;
public int maxBundleSize = 32 * 1024 * 1024; // 32MB
public bool generateHashes = true;
public bool validateDependencies = true;
}

public BuildConfiguration config = new BuildConfiguration();

protected override TResult BuildDataImpl<TResult>(AddressablesDataBuilderInput builderInput)
{
var buildContext = CreateBuildScriptData<AddressableAssetsBuildContext>(builderInput);

// 应用构建配置
ApplyBuildConfiguration(buildContext);

// 执行增强的构建流程
var result = EnhancedBuildProcess(buildContext);

return (TResult)(object)result;
}

private AddressableAssetsBuildContext ApplyBuildConfiguration(AddressableAssetsBuildContext context)
{
// 应用压缩设置
foreach (var group in context.settings.groups)
{
if (group.HasSchema<BundledAssetGroupSchema>())
{
var schema = group.GetSchema<BundledAssetGroupSchema>();
schema.Compression = config.compressionType;
}
}

return context;
}

private AddressableAssetsBuildContext EnhancedBuildProcess(AddressableAssetsBuildContext context)
{
Debug.Log("执行增强构建流程...");

// 1. 预处理阶段
PreProcessBuildContent(context);

// 2. 依赖分析
AnalyzeDependencies(context);

// 3. 资源分组优化
OptimizeResourceGrouping(context);

// 4. 构建执行
ExecuteBuild(context);

// 5. 后处理阶段
PostProcessBuildContent(context);

return context;
}

private void PreProcessBuildContent(AddressableAssetsBuildContext context)
{
Debug.Log("预处理构建内容...");

// 在构建前对资源进行预处理
// 例如:验证资源完整性、优化资源格式等
}

private void AnalyzeDependencies(AddressableAssetsBuildContext context)
{
Debug.Log("分析资源依赖...");

if (config.validateDependencies)
{
// 实现依赖分析逻辑
// 检测循环依赖、无效依赖等
}
}

private void OptimizeResourceGrouping(AddressableAssetsBuildContext context)
{
Debug.Log("优化资源分组...");

// 实现智能资源分组逻辑
// 根据使用模式、更新频率等优化分组
}

private void ExecuteBuild(AddressableAssetsBuildContext context)
{
Debug.Log("执行构建...");

// 执行实际的构建过程
// 这里会调用Unity的默认构建逻辑
}

private void PostProcessBuildContent(AddressableAssetsBuildContext context)
{
Debug.Log("后处理构建内容...");

if (config.generateHashes)
{
GenerateContentHashes(context);
}

if (config.enableEncryption)
{
EncryptBuildOutput(context);
}
}

private void GenerateContentHashes(AddressableAssetsBuildContext context)
{
Debug.Log("生成内容哈希...");

// 为构建输出生成哈希值
// 用于内容验证和更新检测
}

private void EncryptBuildOutput(AddressableAssetsBuildContext context)
{
Debug.Log("加密构建输出...");

// 实现构建输出加密
// 注意:这需要安全的密钥管理
}
}

// 构建分析器
[System.Serializable]
public class BuildAnalysisResult
{
public string buildId;
public DateTime buildTime;
public int totalAssets;
public int totalBundles;
public long totalSize;
public float buildDuration;
public List<string> warnings;
public List<string> errors;
public Dictionary<string, object> customMetrics;
}

private List<BuildAnalysisResult> buildHistory = new List<BuildAnalysisResult>();

void Start()
{
Debug.Log("自定义构建脚本系统启动");
InitializeBuildSystem();
}

private void InitializeBuildSystem()
{
Debug.Log("初始化构建系统...");

// 注册构建事件监听器
// 在实际实现中,这里会监听构建事件

Debug.Log("构建系统初始化完成");
}

/// <summary>
/// 分析构建结果
/// </summary>
public BuildAnalysisResult AnalyzeBuildResult(string buildPath)
{
var result = new BuildAnalysisResult
{
buildId = System.Guid.NewGuid().ToString(),
buildTime = DateTime.Now,
warnings = new List<string>(),
errors = new List<string>(),
customMetrics = new Dictionary<string, object>()
};

if (Directory.Exists(buildPath))
{
var files = Directory.GetFiles(buildPath, "*", SearchOption.AllDirectories);
result.totalAssets = files.Length;

var bundleFiles = files.Where(f => f.EndsWith(".bundle")).ToArray();
result.totalBundles = bundleFiles.Length;

long totalSize = 0;
foreach (var file in files)
{
var info = new FileInfo(file);
totalSize += info.Length;
}
result.totalSize = totalSize;
}

// 添加一些模拟的构建指标
result.customMetrics["averageBundleSize"] = result.totalBundles > 0 ?
(double)result.totalSize / result.totalBundles : 0;
result.customMetrics["compressionRatio"] = 0.75; // 75%压缩率
result.customMetrics["buildSuccessRate"] = 1.0; // 100%成功

buildHistory.Add(result);

return result;
}

/// <summary>
/// 获取构建历史
/// </summary>
public string GetBuildHistory()
{
var history = new System.Text.StringBuilder();
history.AppendLine("=== 构建历史 ===");

foreach (var build in buildHistory)
{
history.AppendLine($"构建ID: {build.buildId}");
history.AppendLine($"时间: {build.buildTime:yyyy-MM-dd HH:mm:ss}");
history.AppendLine($"资产数: {build.totalAssets}");
history.AppendLine($"Bundle数: {build.totalBundles}");
history.AppendLine($"总大小: {FormatBytes(build.totalSize)}");

if (build.warnings.Count > 0)
{
history.AppendLine("警告:");
foreach (var warning in build.warnings)
{
history.AppendLine($" {warning}");
}
}

if (build.errors.Count > 0)
{
history.AppendLine("错误:");
foreach (var error in build.errors)
{
history.AppendLine($" {error}");
}
}

history.AppendLine();
}

return history.ToString();
}

private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double len = bytes;

while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}

return $"{len:0.##} {sizes[order]}";
}

/// <summary>
/// 构建脚本最佳实践
/// </summary>
public string GetBuildScriptBestPractices()
{
var practices = new System.Text.StringBuilder();
practices.AppendLine("=== 自定义构建脚本最佳实践 ===");

practices.AppendLine("1. 构建流程设计:");
practices.AppendLine(" - 实现清晰的构建阶段划分");
practices.AppendLine(" - 支持构建中断和恢复");
practices.AppendLine(" - 提供详细的构建日志");
practices.AppendLine();

practices.AppendLine("2. 配置管理:");
practices.AppendLine(" - 支持多种构建配置");
practices.AppendLine(" - 实现配置验证机制");
practices.AppendLine(" - 提供配置模板系统");
practices.AppendLine();

practices.AppendLine("3. 错误处理:");
practices.AppendLine(" - 实现全面的错误检测");
practices.AppendLine(" - 提供详细的错误信息");
practices.AppendLine(" - 支持构建回滚机制");
practices.AppendLine();

practices.AppendLine("4. 性能优化:");
practices.AppendLine(" - 并行处理构建任务");
practices.AppendLine(" - 实现增量构建支持");
practices.AppendLine(" - 优化I/O操作");
practices.AppendLine();

practices.AppendLine("5. 安全考虑:");
practices.AppendLine(" - 验证构建输入的安全性");
practices.AppendLine(" - 实现安全的加密机制");
practices.AppendLine(" - 保护敏感配置信息");

return practices.ToString();
}

void OnDestroy()
{
Debug.Log("自定义构建脚本系统清理完成");
}
}

资源加密与解密实现

在某些场景下,需要对资源进行加密以保护内容安全。以下是实现资源加密与解密的完整方案。

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

public class ResourceEncryptionSystem : MonoBehaviour
{
[Header("资源加密系统配置")]
public bool enableEncryption = true;
public EncryptionMethod encryptionMethod = EncryptionMethod.AES;
public string encryptionKey = "DefaultKey123456"; // 注意:实际使用时应使用更安全的密钥管理
public string initializationVector = "DefaultIV123456";
public bool enableIntegrityCheck = true;

public enum EncryptionMethod
{
AES,
XOR,
Custom
}

// 加密资源加载器
public class EncryptedResourceLoader
{
private string key;
private string iv;
private EncryptionMethod method;

public EncryptedResourceLoader(string encryptionKey, string encryptionIV, EncryptionMethod encMethod)
{
key = encryptionKey;
iv = encryptionIV;
method = encMethod;
}

/// <summary>
/// 加载并解密资源
/// </summary>
public byte[] LoadAndDecryptResource(string encryptedFilePath)
{
if (!File.Exists(encryptedFilePath))
{
throw new FileNotFoundException($"加密资源文件不存在: {encryptedFilePath}");
}

byte[] encryptedData = File.ReadAllBytes(encryptedFilePath);

if (enableIntegrityCheck)
{
// 验证数据完整性(这里简化实现,实际应使用更安全的哈希验证)
if (!ValidateIntegrity(encryptedData))
{
throw new InvalidDataException("加密数据完整性验证失败");
}
}

return DecryptData(encryptedData);
}

/// <summary>
/// 保存并加密资源
/// </summary>
public void SaveAndEncryptResource(byte[] rawData, string encryptedFilePath)
{
byte[] encryptedData = EncryptData(rawData);

if (enableIntegrityCheck)
{
encryptedData = AddIntegrityCheck(encryptedData);
}

File.WriteAllBytes(encryptedFilePath, encryptedData);
}

private byte[] EncryptData(byte[] data)
{
switch (method)
{
case EncryptionMethod.AES:
return EncryptAES(data);
case EncryptionMethod.XOR:
return EncryptXOR(data);
case EncryptionMethod.Custom:
return EncryptCustom(data);
default:
return data; // 不加密
}
}

private byte[] DecryptData(byte[] data)
{
if (enableIntegrityCheck)
{
data = RemoveIntegrityCheck(data);
}

switch (method)
{
case EncryptionMethod.AES:
return DecryptAES(data);
case EncryptionMethod.XOR:
return DecryptXOR(data);
case EncryptionMethod.Custom:
return DecryptCustom(data);
default:
return data; // 不解密
}
}

#region AES加密解密实现
private byte[] EncryptAES(byte[] data)
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32)); // 256位密钥
aesAlg.IV = Encoding.UTF8.GetBytes(iv.PadRight(16).Substring(0, 16)); // 128位IV

ICryptoTransform encryptor = aesAlg.CreateEncryptor();

using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
csEncrypt.FlushFinalBlock();
return msEncrypt.ToArray();
}
}
}
}

private byte[] DecryptAES(byte[] data)
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32)); // 256位密钥
aesAlg.IV = Encoding.UTF8.GetBytes(iv.PadRight(16).Substring(0, 16)); // 128位IV

ICryptoTransform decryptor = aesAlg.CreateDecryptor();

using (var msDecrypt = new MemoryStream(data))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var msOutput = new MemoryStream())
{
csDecrypt.CopyTo(msOutput);
return msOutput.ToArray();
}
}
}
}
}
#endregion

#region XOR加密解密实现
private byte[] EncryptXOR(byte[] data)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] result = new byte[data.Length];

for (int i = 0; i < data.Length; i++)
{
result[i] = (byte)(data[i] ^ keyBytes[i % keyBytes.Length]);
}

return result;
}

private byte[] DecryptXOR(byte[] data)
{
// XOR加密解密使用相同算法
return EncryptXOR(data);
}
#endregion

#region 自定义加密解密实现
private byte[] EncryptCustom(byte[] data)
{
// 实现自定义加密算法
// 这里使用简单的字节移位和异或操作作为示例
byte[] result = new byte[data.Length];
byte[] keyBytes = Encoding.UTF8.GetBytes(key);

for (int i = 0; i < data.Length; i++)
{
byte b = data[i];
// 移位操作
b = (byte)((b << 3) | (b >> 5));
// XOR操作
b ^= keyBytes[i % keyBytes.Length];
// 加法操作
b = (byte)(b + i % 256);

result[i] = b;
}

return result;
}

private byte[] DecryptCustom(byte[] data)
{
byte[] result = new byte[data.Length];
byte[] keyBytes = Encoding.UTF8.GetBytes(key);

for (int i = 0; i < data.Length; i++)
{
byte b = data[i];
// 逆向加法操作
b = (byte)(b - i % 256);
// 逆向XOR操作
b ^= keyBytes[i % keyBytes.Length];
// 逆向移位操作
b = (byte)((b >> 3) | (b << 5));

result[i] = b;
}

return result;
}
#endregion

#region 完整性检查实现
private bool ValidateIntegrity(byte[] data)
{
if (data.Length < 32) return false; // 至少需要32字节(16字节数据 + 16字节哈希)

byte[] storedHash = new byte[16];
Array.Copy(data, data.Length - 16, storedHash, 0, 16);

byte[] actualData = new byte[data.Length - 16];
Array.Copy(data, 0, actualData, 0, actualData.Length);

using (MD5 md5 = MD5.Create())
{
byte[] actualHash = md5.ComputeHash(actualData);

for (int i = 0; i < 16; i++)
{
if (storedHash[i] != actualHash[i])
return false;
}
}

return true;
}

private byte[] AddIntegrityCheck(byte[] data)
{
using (MD5 md5 = MD5.Create())
{
byte[] hash = md5.ComputeHash(data);

byte[] result = new byte[data.Length + 16];
Array.Copy(data, 0, result, 0, data.Length);
Array.Copy(hash, 0, result, data.Length, 16);

return result;
}
}

private byte[] RemoveIntegrityCheck(byte[] data)
{
if (data.Length < 16) return data;

byte[] result = new byte[data.Length - 16];
Array.Copy(data, 0, result, 0, result.Length);

return result;
}
#endregion
}

// 加密资源管理器
public class EncryptedResourceManager
{
private EncryptedResourceLoader loader;
private Dictionary<string, object> resourceCache = new Dictionary<string, object>();

public EncryptedResourceManager(EncryptedResourceLoader resourceLoader)
{
loader = resourceLoader;
}

/// <summary>
/// 加载加密资源
/// </summary>
public T LoadEncryptedAsset<T>(string encryptedFilePath) where T : class
{
if (resourceCache.ContainsKey(encryptedFilePath))
{
return resourceCache[encryptedFilePath] as T;
}

byte[] decryptedData = loader.LoadAndDecryptResource(encryptedFilePath);

// 这里需要根据资源类型进行反序列化
// 在实际实现中,这可能需要自定义的反序列化逻辑
object resource = DeserializeResource(decryptedData, typeof(T));

if (resource != null)
{
resourceCache[encryptedFilePath] = resource;
}

return resource as T;
}

/// <summary>
/// 保存加密资源
/// </summary>
public void SaveEncryptedAsset<T>(T asset, string encryptedFilePath)
{
byte[] rawData = SerializeResource(asset);
loader.SaveAndEncryptResource(rawData, encryptedFilePath);

// 更新缓存
if (resourceCache.ContainsKey(encryptedFilePath))
{
resourceCache[encryptedFilePath] = asset;
}
}

private object DeserializeResource(byte[] data, Type resourceType)
{
// 简化的反序列化实现
// 在实际应用中,这里需要根据资源类型实现相应的反序列化逻辑
if (resourceType == typeof(Texture2D))
{
// 对于纹理,可能需要特殊的处理
return new Texture2D(16, 16); // 返回模拟纹理
}
else if (resourceType == typeof(GameObject))
{
// 对于GameObject,需要Unity特定的反序列化
return new GameObject("EncryptedGameObject");
}

// 默认返回null,实际实现中应有适当的反序列化逻辑
return null;
}

private byte[] SerializeResource<T>(T asset)
{
// 简化的序列化实现
// 在实际应用中,这里需要实现适当的序列化逻辑
string assetString = JsonUtility.ToJson(asset);
return Encoding.UTF8.GetBytes(assetString);
}
}

[System.Serializable]
public class EncryptionAnalysisResult
{
public EncryptionMethod method;
public float encryptionTime;
public float decryptionTime;
public long originalSize;
public long encryptedSize;
public float sizeOverhead;
public bool integrityCheckPassed;
public string securityLevel;
}

private EncryptedResourceLoader resourceLoader;
private EncryptedResourceManager resourceManager;

void Start()
{
Debug.Log("资源加密系统启动");

if (enableEncryption)
{
InitializeEncryptionSystem();
}
}

private void InitializeEncryptionSystem()
{
resourceLoader = new EncryptedResourceLoader(encryptionKey, initializationVector, encryptionMethod);
resourceManager = new EncryptedResourceManager(resourceLoader);

Debug.Log($"加密系统初始化完成,方法: {encryptionMethod}");
}

/// <summary>
/// 分析加密性能
/// </summary>
public EncryptionAnalysisResult AnalyzeEncryptionPerformance(byte[] testData)
{
var result = new EncryptionAnalysisResult
{
method = encryptionMethod,
originalSize = testData.Length
};

// 测试加密性能
var encryptStart = DateTime.Now;
byte[] encryptedData = resourceLoader.EncryptData(testData);
result.encryptionTime = (float)(DateTime.Now - encryptStart).TotalSeconds;

// 测试解密性能
var decryptStart = DateTime.Now;
byte[] decryptedData = resourceLoader.DecryptData(encryptedData);
result.decryptionTime = (float)(DateTime.Now - decryptStart).TotalSeconds;

result.encryptedSize = encryptedData.Length;
result.sizeOverhead = (float)(encryptedData.Length - testData.Length) / testData.Length * 100;

if (enableIntegrityCheck)
{
result.integrityCheckPassed = resourceLoader.ValidateIntegrity(encryptedData);
}
else
{
result.integrityCheckPassed = true;
}

// 评估安全级别
result.securityLevel = encryptionMethod switch
{
EncryptionMethod.AES => "High",
EncryptionMethod.XOR => "Low",
EncryptionMethod.Custom => "Medium",
_ => "None"
};

return result;
}

/// <summary>
/// 获取加密系统信息
/// </summary>
public string GetEncryptionSystemInfo()
{
var info = new System.Text.StringBuilder();
info.AppendLine("=== 资源加密系统信息 ===");

info.AppendLine($"启用加密: {enableEncryption}");
info.AppendLine($"加密方法: {encryptionMethod}");
info.AppendLine($"完整性检查: {enableIntegrityCheck}");
info.AppendLine($"密钥长度: {encryptionKey.Length} 字符");
info.AppendLine($"IV长度: {initializationVector.Length} 字符");
info.AppendLine();

info.AppendLine("安全建议:");
info.AppendLine("• 使用强加密算法(如AES-256)");
info.AppendLine("• 安全存储加密密钥");
info.AppendLine("• 定期更换加密密钥");
info.AppendLine("• 实施适当的访问控制");

return info.ToString();
}

/// <summary>
/// 加密最佳实践
/// </summary>
public string GetEncryptionBestPractices()
{
var practices = new System.Text.StringBuilder();
practices.AppendLine("=== 资源加密最佳实践 ===");

practices.AppendLine("1. 算法选择:");
practices.AppendLine(" - 生产环境使用AES-256等强加密算法");
practices.AppendLine(" - 避免使用简单的XOR加密");
practices.AppendLine(" - 定期评估加密算法的安全性");
practices.AppendLine();

practices.AppendLine("2. 密钥管理:");
practices.AppendLine(" - 使用安全的密钥存储机制");
practices.AppendLine(" - 实现密钥轮换策略");
practices.AppendLine(" - 避免硬编码密钥");
practices.AppendLine();

practices.AppendLine("3. 性能考虑:");
practices.AppendLine(" - 评估加密对加载性能的影响");
practices.AppendLine(" - 实现异步加密/解密操作");
practices.AppendLine(" - 考虑选择性加密策略");
practices.AppendLine();

practices.AppendLine("4. 安全性:");
practices.AppendLine(" - 实施完整性验证");
practices.AppendLine(" - 防止侧信道攻击");
practices.AppendLine(" - 定期进行安全审计");
practices.AppendLine();

practices.AppendLine("5. 兼容性:");
practices.AppendLine(" - 确保跨平台兼容性");
practices.AppendLine(" - 实现版本管理");
practices.AppendLine(" - 提供解密向后兼容性");

return practices.ToString();
}

void OnDestroy()
{
Debug.Log("资源加密系统清理完成");
}
}

自定义缓存策略

Unity Addressables提供了灵活的缓存系统,可以通过自定义缓存策略来满足特定的性能和存储需求。

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.ResourceManagement;

public class CustomCacheStrategySystem : MonoBehaviour
{
[Header("自定义缓存策略配置")]
public bool enableCustomCaching = true;
public CacheStrategyType cacheStrategy = CacheStrategyType.LRU;
public long maxCacheSize = 100 * 1024 * 1024; // 100MB
public float cacheTimeout = 3600f; // 1小时
public bool enableDiskCaching = true;
public bool enableMemoryCaching = true;

public enum CacheStrategyType
{
LRU, // 最近最少使用
LFU, // 最少频繁使用
FIFO, // 先进先出
Priority, // 优先级缓存
Hybrid // 混合策略
}

// 自定义缓存条目
[System.Serializable]
public class CacheEntry
{
public string key;
public object data;
public DateTime lastAccessTime;
public DateTime creationTime;
public long size;
public int accessCount;
public float priority;
public string resourceType;

public CacheEntry(string key, object data, long size, string type)
{
this.key = key;
this.data = data;
this.size = size;
this.resourceType = type;
this.lastAccessTime = DateTime.Now;
this.creationTime = DateTime.Now;
this.accessCount = 1;
this.priority = 1.0f;
}
}

// 自定义缓存管理器
public class CustomCacheManager
{
private Dictionary<string, CacheEntry> memoryCache = new Dictionary<string, CacheEntry>();
private LinkedList<string> lruList = new LinkedList<string>(); // 用于LRU策略
private Dictionary<string, LinkedListNode<string>> lruMap = new Dictionary<string, LinkedListNode<string>>();
private long currentMemorySize = 0;
private long maxCacheSize;
private float cacheTimeout;
private CacheStrategyType strategy;
private bool enableDiskCaching;
private bool enableMemoryCaching;

public CustomCacheManager(long maxSize, float timeout, CacheStrategyType cacheStrategy,
bool diskCaching, bool memoryCaching)
{
maxCacheSize = maxSize;
cacheTimeout = timeout;
strategy = cacheStrategy;
enableDiskCaching = diskCaching;
enableMemoryCaching = memoryCaching;
}

/// <summary>
/// 添加到缓存
/// </summary>
public bool AddToCache(string key, object data, long size, string resourceType)
{
if (!enableMemoryCaching) return false;

// 检查是否已存在
if (memoryCache.ContainsKey(key))
{
// 更新现有条目
var entry = memoryCache[key];
currentMemorySize -= entry.size;
entry.data = data;
entry.size = size;
entry.lastAccessTime = DateTime.Now;
entry.accessCount++;
currentMemorySize += size;

UpdateCacheStrategy(key);
return true;
}

// 检查缓存大小限制
if (currentMemorySize + size > maxCacheSize)
{
if (!EvictCacheEntries(size))
{
return false; // 无法腾出足够空间
}
}

// 添加新条目
var newEntry = new CacheEntry(key, data, size, resourceType);
memoryCache[key] = newEntry;
currentMemorySize += size;

UpdateCacheStrategy(key);

// 如果启用磁盘缓存,也保存到磁盘
if (enableDiskCaching)
{
SaveToDisk(key, data, resourceType);
}

return true;
}

/// <summary>
/// 从缓存获取
/// </summary>
public bool TryGetFromCache(string key, out object data)
{
data = null;

if (!enableMemoryCaching) return false;

// 检查内存缓存
if (memoryCache.ContainsKey(key))
{
var entry = memoryCache[key];

// 检查是否过期
if ((DateTime.Now - entry.lastAccessTime).TotalSeconds > cacheTimeout)
{
RemoveFromCache(key);
return false;
}

// 更新访问信息
entry.lastAccessTime = DateTime.Now;
entry.accessCount++;

// 更新缓存策略
UpdateCacheStrategy(key);

data = entry.data;
return true;
}

// 如果在磁盘缓存中,加载到内存
if (enableDiskCaching && File.Exists(GetDiskCachePath(key)))
{
data = LoadFromDisk(key);
if (data != null)
{
// 重新添加到内存缓存
long size = GetObjectSize(data);
AddToCache(key, data, size, GetObjectType(data));
return true;
}
}

return false;
}

/// <summary>
/// 从缓存移除
/// </summary>
public bool RemoveFromCache(string key)
{
if (memoryCache.ContainsKey(key))
{
var entry = memoryCache[key];
currentMemorySize -= entry.size;

// 从LRU列表移除
if (lruMap.ContainsKey(key))
{
lruList.Remove(lruMap[key]);
lruMap.Remove(key);
}

memoryCache.Remove(key);

// 从磁盘移除
if (enableDiskCaching)
{
DeleteFromDisk(key);
}

return true;
}

return false;
}

/// <summary>
/// 清理过期缓存
/// </summary>
public void CleanupExpiredCache()
{
var keysToRemove = new List<string>();

foreach (var kvp in memoryCache)
{
if ((DateTime.Now - kvp.Value.lastAccessTime).TotalSeconds > cacheTimeout)
{
keysToRemove.Add(kvp.Key);
}
}

foreach (string key in keysToRemove)
{
RemoveFromCache(key);
}
}

private bool EvictCacheEntries(long requiredSize)
{
long freedSize = 0;

while (currentMemorySize + requiredSize > maxCacheSize && memoryCache.Count > 0)
{
string keyToEvict = null;

switch (strategy)
{
case CacheStrategyType.LRU:
keyToEvict = GetLRUEvictionCandidate();
break;
case CacheStrategyType.LFU:
keyToEvict = GetLFUEvictionCandidate();
break;
case CacheStrategyType.FIFO:
keyToEvict = GetFIFOEvictionCandidate();
break;
case CacheStrategyType.Priority:
keyToEvict = GetPriorityEvictionCandidate();
break;
case CacheStrategyType.Hybrid:
keyToEvict = GetHybridEvictionCandidate();
break;
}

if (keyToEvict == null)
{
return false; // 无法腾出空间
}

var entry = memoryCache[keyToEvict];
freedSize += entry.size;

RemoveFromCache(keyToEvict);
}

return true;
}

private string GetLRUEvictionCandidate()
{
if (lruList.First != null)
{
return lruList.First.Value;
}

// 如果LRU列表为空,返回第一个条目
foreach (var kvp in memoryCache)
{
return kvp.Key;
}

return null;
}

private string GetLFUEvictionCandidate()
{
string candidateKey = null;
int minAccessCount = int.MaxValue;

foreach (var kvp in memoryCache)
{
if (kvp.Value.accessCount < minAccessCount)
{
minAccessCount = kvp.Value.accessCount;
candidateKey = kvp.Key;
}
}

return candidateKey;
}

private string GetFIFOEvictionCandidate()
{
string candidateKey = null;
DateTime earliestTime = DateTime.MaxValue;

foreach (var kvp in memoryCache)
{
if (kvp.Value.creationTime < earliestTime)
{
earliestTime = kvp.Value.creationTime;
candidateKey = kvp.Key;
}
}

return candidateKey;
}

private string GetPriorityEvictionCandidate()
{
string candidateKey = null;
float minPriority = float.MaxValue;

foreach (var kvp in memoryCache)
{
if (kvp.Value.priority < minPriority)
{
minPriority = kvp.Value.priority;
candidateKey = kvp.Key;
}
}

return candidateKey;
}

private string GetHybridEvictionCandidate()
{
// 混合策略:结合访问频率和时间
string candidateKey = null;
double minScore = double.MaxValue;

foreach (var kvp in memoryCache)
{
var entry = kvp.Value;
double score = (entry.accessCount * 0.3) +
((DateTime.Now - entry.lastAccessTime).TotalMinutes * 0.7);

if (score < minScore)
{
minScore = score;
candidateKey = kvp.Key;
}
}

return candidateKey;
}

private void UpdateCacheStrategy(string key)
{
switch (strategy)
{
case CacheStrategyType.LRU:
UpdateLRU(key);
break;
}
}

private void UpdateLRU(string key)
{
if (lruMap.ContainsKey(key))
{
// 移动到列表末尾(最近使用)
lruList.Remove(lruMap[key]);
}

var node = lruList.AddLast(key);
lruMap[key] = node;
}

private void SaveToDisk(string key, object data, string resourceType)
{
try
{
string path = GetDiskCachePath(key);
string directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}

// 在实际实现中,这里会序列化对象并保存到文件
// 为简化,这里只创建一个标记文件
File.WriteAllText(path, key);
}
catch (Exception ex)
{
Debug.LogError($"保存到磁盘缓存失败: {ex.Message}");
}
}

private object LoadFromDisk(string key)
{
try
{
string path = GetDiskCachePath(key);
if (File.Exists(path))
{
// 在实际实现中,这里会从文件读取并反序列化对象
// 为简化,这里返回一个模拟对象
return new object();
}
}
catch (Exception ex)
{
Debug.LogError($"从磁盘缓存加载失败: {ex.Message}");
}

return null;
}

private void DeleteFromDisk(string key)
{
try
{
string path = GetDiskCachePath(key);
if (File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception ex)
{
Debug.LogError($"删除磁盘缓存失败: {ex.Message}");
}
}

private string GetDiskCachePath(string key)
{
// 生成磁盘缓存路径
string hash = key.GetHashCode().ToString("x8");
string subDir = hash.Substring(0, 2); // 使用哈希的前两位作为子目录
return Path.Combine(Application.persistentDataPath, "Cache", subDir, hash + ".cache");
}

private long GetObjectSize(object obj)
{
// 估算对象大小(在实际实现中,这可能需要更精确的计算)
return 1024; // 默认1KB
}

private string GetObjectType(object obj)
{
return obj?.GetType().Name ?? "Unknown";
}

/// <summary>
/// 获取缓存统计信息
/// </summary>
public string GetCacheStats()
{
var stats = new System.Text.StringBuilder();
stats.AppendLine("缓存统计:");
stats.AppendLine($" 条目数量: {memoryCache.Count}");
stats.AppendLine($" 当前大小: {FormatBytes(currentMemorySize)}");
stats.AppendLine($" 最大大小: {FormatBytes(maxCacheSize)}");
stats.AppendLine($" 使用率: {(float)currentMemorySize / maxCacheSize * 100:F1}%");
stats.AppendLine($" 策略: {strategy}");
stats.AppendLine($" 磁盘缓存: {enableDiskCaching}");
stats.AppendLine($" 内存缓存: {enableMemoryCaching}");

return stats.ToString();
}
}

// 缓存分析结果
[System.Serializable]
public class CacheAnalysisResult
{
public CacheStrategyType strategy;
public int hitCount;
public int missCount;
public float hitRate;
public long totalSize;
public int entryCount;
public float avgAccessTime;
public List<string> evictionStats;
}

private CustomCacheManager cacheManager;
private int hitCount = 0;
private int missCount = 0;
private List<float> accessTimes = new List<float>();

void Start()
{
Debug.Log("自定义缓存策略系统启动");

if (enableCustomCaching)
{
InitializeCacheSystem();
}
}

private void InitializeCacheSystem()
{
cacheManager = new CustomCacheManager(maxCacheSize, cacheTimeout, cacheStrategy,
enableDiskCaching, enableMemoryCaching);

Debug.Log($"缓存系统初始化完成,策略: {cacheStrategy}, 大小限制: {FormatBytes(maxCacheSize)}");
}

/// <summary>
/// 测试缓存性能
/// </summary>
public CacheAnalysisResult TestCachePerformance(int operationCount = 1000)
{
var result = new CacheAnalysisResult
{
strategy = cacheStrategy,
hitCount = 0,
missCount = 0,
evictionStats = new List<string>()
};

for (int i = 0; i < operationCount; i++)
{
string key = $"TestKey_{i}";
object testData = new object();
long size = 1024; // 1KB

var startTime = Time.realtimeSinceStartup;

if (i % 3 == 0) // 1/3 的概率进行读取操作
{
object data;
if (cacheManager.TryGetFromCache(key, out data))
{
result.hitCount++;
}
else
{
result.missCount++;
// 添加到缓存
cacheManager.AddToCache(key, testData, size, "TestObject");
}
}
else
{
// 写入操作
cacheManager.AddToCache(key, testData, size, "TestObject");
}

float accessTime = Time.realtimeSinceStartup - startTime;
accessTimes.Add(accessTime);
}

result.hitRate = operationCount > 0 ? (float)result.hitCount / operationCount : 0;
result.avgAccessTime = accessTimes.Count > 0 ?
accessTimes.Average() : 0;

// 获取缓存统计
var cacheStats = cacheManager.GetCacheStats();

return result;
}

private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double len = bytes;

while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}

return $"{len:0.##} {sizes[order]}";
}

/// <summary>
/// 获取缓存系统信息
/// </summary>
public string GetCacheSystemInfo()
{
var info = new System.Text.StringBuilder();
info.AppendLine("=== 自定义缓存策略系统信息 ===");

info.AppendLine($"启用自定义缓存: {enableCustomCaching}");
info.AppendLine($"缓存策略: {cacheStrategy}");
info.AppendLine($"最大缓存大小: {FormatBytes(maxCacheSize)}");
info.AppendLine($"缓存超时: {cacheTimeout}s");
info.AppendLine($"磁盘缓存: {enableDiskCaching}");
info.AppendLine($"内存缓存: {enableMemoryCaching}");
info.AppendLine();

if (cacheManager != null)
{
info.AppendLine(cacheManager.GetCacheStats());
}

return info.ToString();
}

/// <summary>
/// 缓存策略最佳实践
/// </summary>
public string GetCacheBestPractices()
{
var practices = new System.Text.StringBuilder();
practices.AppendLine("=== 自定义缓存策略最佳实践 ===");

practices.AppendLine("1. 策略选择:");
practices.AppendLine(" - LRU: 适用于访问模式相对稳定");
practices.AppendLine(" - LFU: 适用于有明显热点数据");
practices.AppendLine(" - FIFO: 适用于数据时效性强");
practices.AppendLine(" - Priority: 适用于有明确优先级");
practices.AppendLine();

practices.AppendLine("2. 大小管理:");
practices.AppendLine(" - 设置合理的缓存大小限制");
practices.AppendLine(" - 实现智能的驱逐策略");
practices.AppendLine(" - 监控缓存命中率");
practices.AppendLine();

practices.AppendLine("3. 性能优化:");
practices.AppendLine(" - 使用高效的数据结构");
practices.AppendLine(" - 实现异步缓存操作");
practices.AppendLine(" - 避免缓存雪崩");
practices.AppendLine();

practices.AppendLine("4. 内存管理:");
practices.AppendLine(" - 及时释放不需要的缓存");
practices.AppendLine(" - 实现内存使用监控");
practices.AppendLine(" - 防止内存泄漏");
practices.AppendLine();

practices.AppendLine("5. 持久化:");
practices.AppendLine(" - 实现磁盘缓存支持");
practices.AppendLine(" - 确保数据一致性");
practices.AppendLine(" - 处理缓存文件损坏");

return practices.ToString();
}

void OnDestroy()
{
Debug.Log("自定义缓存策略系统清理完成");
}
}

实战案例:实现加密资源加载系统

结合前面介绍的各种扩展点,我们来实现一个完整的加密资源加载系统:

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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;

public class EncryptedResourceLoadingSystem : MonoBehaviour
{
[Header("加密资源加载系统配置")]
public string encryptionKey = "SecureKey12345678";
public string initializationVector = "SecureIV12345678";
public bool enableResourceEncryption = true;
public bool enableCache = true;
public long cacheSizeLimit = 50 * 1024 * 1024; // 50MB

// 加密资源提供者
public class EncryptedResourceProvider : IResourceProvider
{
private ResourceEncryptionSystem.EncryptedResourceLoader loader;
private CustomCacheStrategySystem.CustomCacheManager cacheManager;

public EncryptedResourceProvider(string key, string iv,
CustomCacheStrategySystem.CustomCacheManager cacheMgr)
{
loader = new ResourceEncryptionSystem.EncryptedResourceLoader(key, iv,
ResourceEncryptionSystem.EncryptionMethod.AES);
cacheManager = cacheMgr;
}

public string ProviderId => "EncryptedResourceProvider";

public void Provide(ProvideHandle provideHandle)
{
string locationName = provideHandle.Location.PrimaryKey;

// 尝试从缓存获取
if (cacheManager != null)
{
object cachedData;
if (cacheManager.TryGetFromCache(locationName, out cachedData))
{
provideHandle.Complete(cachedData, true, null);
return;
}
}

// 异步加载加密资源
StartCoroutine(LoadEncryptedResourceAsync(locationName, provideHandle));
}

public void Release(IResourceLocation location, object asset)
{
// 从缓存移除(如果存在)
if (cacheManager != null)
{
cacheManager.RemoveFromCache(location.PrimaryKey);
}

// 释放资源
if (asset is UnityEngine.Object unityObject)
{
UnityEngine.Object.Destroy(unityObject);
}
}

private IEnumerator LoadEncryptedResourceAsync(string locationName, ProvideHandle provideHandle)
{
try
{
// 模拟异步加载过程
yield return new WaitForSeconds(0.1f); // 模拟加载延迟

// 加载加密资源(这里使用模拟数据)
byte[] encryptedData = System.Text.Encoding.UTF8.GetBytes($"EncryptedData_{locationName}");
byte[] decryptedData = loader.DecryptData(encryptedData);

// 创建资源对象
object resource = CreateResourceFromData(decryptedData, locationName);

// 添加到缓存
if (cacheManager != null)
{
long size = System.Text.Encoding.UTF8.GetByteCount(decryptedData);
cacheManager.AddToCache(locationName, resource, size, "EncryptedAsset");
}

provideHandle.Complete(resource, true, null);
}
catch (Exception ex)
{
provideHandle.Complete(null, false, ex);
}
}

private object CreateResourceFromData(byte[] data, string locationName)
{
// 根据资源类型创建相应的对象
string resourceString = System.Text.Encoding.UTF8.GetString(data);

if (locationName.EndsWith(".prefab"))
{
return new GameObject($"Encrypted_{locationName}");
}
else if (locationName.EndsWith(".png") || locationName.EndsWith(".jpg"))
{
Texture2D texture = new Texture2D(128, 128);
Color[] colors = new Color[128 * 128];
for (int i = 0; i < colors.Length; i++)
{
colors[i] = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
}
texture.SetPixels(colors);
texture.Apply();
return texture;
}
else
{
return new GameObject($"Encrypted_{resourceString}");
}
}
}

// 加密资源位置
public class EncryptedResourceLocation : IResourceLocation
{
public string InternalId { get; set; }
public string Provider { get; set; }
public IList<IResourceLocation> Dependencies { get; set; }
public object Data { get; set; }
public string PrimaryKey { get; set; }

public EncryptedResourceLocation(string primaryKey, string internalId)
{
PrimaryKey = primaryKey;
InternalId = internalId;
Provider = "EncryptedResourceProvider";
Dependencies = new List<IResourceLocation>();
}

public bool HasKey(string key)
{
return PrimaryKey == key;
}

public bool Matches(string key)
{
return PrimaryKey == key;
}

public T GetData<T>()
{
return (T)Data;
}
}

// 系统组件
private ResourceEncryptionSystem.EncryptedResourceLoader encryptionLoader;
private CustomCacheStrategySystem.CustomCacheManager cacheManager;
private EncryptedResourceProvider resourceProvider;

void Start()
{
Debug.Log("加密资源加载系统启动");
InitializeEncryptedResourceSystem();
}

private void InitializeEncryptedResourceSystem()
{
// 初始化加密加载器
encryptionLoader = new ResourceEncryptionSystem.EncryptedResourceLoader(
encryptionKey, initializationVector, ResourceEncryptionSystem.EncryptionMethod.AES);

// 初始化缓存管理器
if (enableCache)
{
cacheManager = new CustomCacheStrategySystem.CustomCacheManager(
cacheSizeLimit, 3600f, CustomCacheStrategySystem.CacheStrategyType.LRU,
true, true);
}

// 初始化资源提供者
resourceProvider = new EncryptedResourceProvider(
encryptionKey, initializationVector, cacheManager);

Debug.Log("加密资源加载系统初始化完成");
}

/// <summary>
/// 加载加密资源
/// </summary>
public AsyncOperationHandle<T> LoadEncryptedResource<T>(string resourcePath) where T : class
{
var location = new EncryptedResourceLocation(resourcePath, resourcePath);

// 在实际实现中,这里会使用Addressables系统的ResourceManager
// 为简化,这里返回一个模拟的AsyncOperationHandle
return default(AsyncOperationHandle<T>);
}

/// <summary>
/// 获取系统信息
/// </summary>
public string GetSystemInfo()
{
var info = new System.Text.StringBuilder();
info.AppendLine("=== 加密资源加载系统信息 ===");

info.AppendLine($"启用加密: {enableResourceEncryption}");
info.AppendLine($"启用缓存: {enableCache}");
info.AppendLine($"缓存大小限制: {FormatBytes(cacheSizeLimit)}");
info.AppendLine($"加密密钥长度: {encryptionKey.Length}");
info.AppendLine($"初始化向量长度: {initializationVector.Length}");
info.AppendLine();

if (cacheManager != null)
{
info.AppendLine("缓存统计:");
info.AppendLine(cacheManager.GetCacheStats());
}

return info.ToString();
}

private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double len = bytes;

while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}

return $"{len:0.##} {sizes[order]}";
}

/// <summary>
/// 加密资源系统最佳实践
/// </summary>
public string GetEncryptedResourceBestPractices()
{
var practices = new System.Text.StringBuilder();
practices.AppendLine("=== 加密资源加载系统最佳实践 ===");

practices.AppendLine("1. 安全性:");
practices.AppendLine(" - 使用强加密算法(如AES-256)");
practices.AppendLine(" - 安全存储和传输加密密钥");
practices.AppendLine(" - 实施完整性验证");
practices.AppendLine();

practices.AppendLine("2. 性能:");
practices.AppendLine(" - 实现异步加密/解密");
practices.AppendLine(" - 使用智能缓存策略");
practices.AppendLine(" - 优化解密性能");
practices.AppendLine();

practices.AppendLine("3. 可靠性:");
practices.AppendLine(" - 实现错误恢复机制");
practices.AppendLine(" - 提供降级方案");
practices.AppendLine(" - 记录详细的错误日志");
practices.AppendLine();

practices.AppendLine("4. 维护:");
practices.AppendLine(" - 支持密钥轮换");
practices.AppendLine(" - 实现版本兼容性");
practices.AppendLine(" - 提供监控和诊断工具");

return practices.ToString();
}

void OnDestroy()
{
Debug.Log("加密资源加载系统清理完成");
}
}

通过本章的学习,您已经掌握了Unity Addressables的高级扩展开发技术,包括自定义ResourceProvider、ResourceLocation、构建脚本、加密解密实现以及自定义缓存策略。这些技术能够帮助您构建更加安全、高效和灵活的资源管理系统。