529 lines
11 KiB
Markdown
529 lines
11 KiB
Markdown
# Extra2D 资源服务系统
|
||
|
||
## 概述
|
||
|
||
Extra2D 资源服务系统提供了一套完整的资源管理解决方案,包括资源加载、缓存、打包和加密压缩功能。
|
||
|
||
### 主要特性
|
||
|
||
- **类型安全**:使用模板和强类型 ID 避免类型错误
|
||
- **自动缓存**:LRU 缓存策略,自动管理内存
|
||
- **异步加载**:后台线程加载,不阻塞主线程
|
||
- **资源打包**:支持压缩和加密的资源包格式
|
||
- **多格式支持**:纹理、字体、着色器、音频等
|
||
|
||
## 模块结构
|
||
|
||
```
|
||
extra2d/asset/
|
||
├── asset_types.h # 资源类型定义
|
||
├── asset.h # 资源基类
|
||
├── asset_handle.h # 资源句柄
|
||
├── asset_cache.h # 资源缓存
|
||
├── asset_loader.h # 资源加载器
|
||
├── asset_pack.h # 资源包
|
||
├── data_processor.h # 数据处理器
|
||
└── asset_service.h # 资源服务
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 1. 初始化资源服务
|
||
|
||
```cpp
|
||
#include <extra2d/extra2d.h>
|
||
|
||
using namespace extra2d;
|
||
|
||
// 创建资源服务
|
||
AssetService service;
|
||
service.init();
|
||
service.setRoot("assets");
|
||
|
||
// 注册加载器
|
||
service.registerLoader<TextureAsset>(AssetLoaderFactory::createTextureLoader());
|
||
service.registerLoader<FontAsset>(AssetLoaderFactory::createFontLoader());
|
||
service.registerLoader<ShaderAsset>(AssetLoaderFactory::createShaderLoader());
|
||
```
|
||
|
||
### 2. 同步加载资源
|
||
|
||
```cpp
|
||
// 加载纹理
|
||
AssetHandle<TextureAsset> texture = service.load<TextureAsset>("sprites/player.png");
|
||
if (texture.valid()) {
|
||
int width = texture->width();
|
||
int height = texture->height();
|
||
const u8* data = texture->data();
|
||
}
|
||
```
|
||
|
||
### 3. 异步加载资源
|
||
|
||
```cpp
|
||
// 异步加载
|
||
service.loadAsync<TextureAsset>("sprites/background.png",
|
||
[](AssetHandle<TextureAsset> handle) {
|
||
if (handle.valid()) {
|
||
// 资源加载完成,在主线程处理
|
||
}
|
||
});
|
||
|
||
// 在主线程处理回调
|
||
service.process();
|
||
```
|
||
|
||
### 4. 使用资源包
|
||
|
||
```cpp
|
||
// 挂载资源包
|
||
service.mount("data.pak");
|
||
|
||
// 从资源包加载
|
||
auto texture = service.load<TextureAsset>("textures/hero.png");
|
||
|
||
// 卸载资源包
|
||
service.unmount("data.pak");
|
||
```
|
||
|
||
### 5. 缓存管理
|
||
|
||
```cpp
|
||
// 设置缓存上限 (100MB)
|
||
service.setLimit(100 * 1024 * 1024);
|
||
|
||
// 获取缓存统计
|
||
CacheStats stats = service.stats();
|
||
std::cout << "缓存使用: " << stats.bytes << " 字节\n";
|
||
std::cout << "命中率: " << (stats.hitRate() * 100) << "%\n";
|
||
|
||
// 清理无引用资源
|
||
service.purge();
|
||
|
||
// 清空缓存
|
||
service.clear();
|
||
```
|
||
|
||
## API 参考
|
||
|
||
### AssetID
|
||
|
||
资源标识符,使用哈希值进行快速比较。
|
||
|
||
```cpp
|
||
struct AssetID {
|
||
u64 hash; // 哈希值
|
||
std::string path; // 原始路径
|
||
|
||
explicit AssetID(const std::string& path);
|
||
bool valid() const;
|
||
bool operator==(const AssetID& other) const;
|
||
};
|
||
```
|
||
|
||
### AssetHandle<T>
|
||
|
||
类型安全的资源句柄,使用弱引用避免阻止资源回收。
|
||
|
||
```cpp
|
||
template<typename T>
|
||
class AssetHandle {
|
||
public:
|
||
bool valid() const; // 检查是否有效
|
||
Ref<T> get() const; // 获取强引用
|
||
T* operator->() const; // 解引用
|
||
bool loaded() const; // 检查是否已加载
|
||
AssetState state() const; // 获取状态
|
||
};
|
||
```
|
||
|
||
### AssetCache
|
||
|
||
LRU 缓存管理器。
|
||
|
||
```cpp
|
||
class AssetCache {
|
||
public:
|
||
explicit AssetCache(size_t limit = 0);
|
||
|
||
template<typename T>
|
||
AssetHandle<T> add(Ref<T> asset);
|
||
|
||
template<typename T>
|
||
AssetHandle<T> get(const AssetID& id);
|
||
|
||
bool has(const AssetID& id) const;
|
||
bool remove(const AssetID& id);
|
||
|
||
void setLimit(size_t limit);
|
||
size_t bytes() const;
|
||
size_t count() const;
|
||
|
||
size_t purge(); // 清理无引用资源
|
||
void clear(); // 清空缓存
|
||
CacheStats stats() const;
|
||
};
|
||
```
|
||
|
||
### IAssetService
|
||
|
||
资源服务接口。
|
||
|
||
```cpp
|
||
class IAssetService : public IService {
|
||
public:
|
||
// 同步加载
|
||
template<typename T>
|
||
AssetHandle<T> load(const std::string& path);
|
||
|
||
// 异步加载
|
||
template<typename T>
|
||
void loadAsync(const std::string& path, AssetLoadCallback<T> callback);
|
||
|
||
// 获取已缓存资源
|
||
template<typename T>
|
||
AssetHandle<T> get(const std::string& path);
|
||
|
||
// 预加载
|
||
template<typename T>
|
||
void preload(const std::string& path);
|
||
|
||
// 状态查询
|
||
bool isLoaded(const std::string& path) const;
|
||
bool isLoading(const std::string& path) const;
|
||
|
||
// 资源管理
|
||
void unload(const std::string& path);
|
||
void setLimit(size_t maxBytes);
|
||
size_t size() const;
|
||
void purge();
|
||
void clear();
|
||
CacheStats stats() const;
|
||
|
||
// 加载器注册
|
||
template<typename T>
|
||
void registerLoader(Unique<AssetLoader<T>> loader);
|
||
|
||
// 资源包管理
|
||
bool mount(const std::string& path);
|
||
void unmount(const std::string& path);
|
||
|
||
// 数据处理管道
|
||
void setPipe(DataPipe pipe);
|
||
|
||
// 根目录
|
||
void setRoot(const std::string& path);
|
||
std::string root() const;
|
||
|
||
// 处理异步回调
|
||
void process();
|
||
};
|
||
```
|
||
|
||
### DataPipe
|
||
|
||
数据处理管道,支持链式调用。
|
||
|
||
```cpp
|
||
class DataPipe {
|
||
public:
|
||
DataPipe& decrypt(const std::string& key, Decryptor::Type type = Decryptor::Type::XOR);
|
||
DataPipe& decompress(Compression algo);
|
||
DataPipe& encrypt(const std::string& key, Decryptor::Type type = Decryptor::Type::XOR);
|
||
DataPipe& compress(Compression algo, int level = 3);
|
||
DataPipe& add(Unique<DataProcessor> processor);
|
||
|
||
std::vector<u8> process(const std::vector<u8>& input);
|
||
void clear();
|
||
bool empty() const;
|
||
size_t size() const;
|
||
};
|
||
```
|
||
|
||
### AssetPackBuilder
|
||
|
||
资源包构建器。
|
||
|
||
```cpp
|
||
class AssetPackBuilder {
|
||
public:
|
||
explicit AssetPackBuilder(Compression compression = Compression::None, int level = 3);
|
||
|
||
void add(const std::string& path, const std::vector<u8>& data);
|
||
void add(const std::string& path, std::vector<u8>&& data);
|
||
bool addFile(const std::string& filePath, const std::string& packPath = "");
|
||
size_t addDirectory(const std::string& dirPath, const std::string& prefix = "");
|
||
|
||
void setEncryption(const std::string& key, Decryptor::Type type = Decryptor::Type::XOR);
|
||
bool build(const std::string& outputPath);
|
||
|
||
void clear();
|
||
size_t count() const;
|
||
size_t totalOriginalSize() const;
|
||
size_t totalCompressedSize() const;
|
||
};
|
||
```
|
||
|
||
## 资源类型
|
||
|
||
### TextureAsset
|
||
|
||
纹理资源,使用 stb_image 加载。
|
||
|
||
```cpp
|
||
class TextureAsset : public Asset {
|
||
public:
|
||
AssetType type() const override { return AssetType::Texture; }
|
||
|
||
int width() const;
|
||
int height() const;
|
||
int channels() const;
|
||
const u8* data() const;
|
||
size_t dataSize() const;
|
||
};
|
||
```
|
||
|
||
### FontAsset
|
||
|
||
字体资源,支持 TrueType 字体。
|
||
|
||
```cpp
|
||
class FontAsset : public Asset {
|
||
public:
|
||
AssetType type() const override { return AssetType::Font; }
|
||
|
||
float scaleForPixelHeight(float pixels) const;
|
||
const u8* data() const;
|
||
size_t dataSize() const;
|
||
};
|
||
```
|
||
|
||
### ShaderAsset
|
||
|
||
着色器资源。
|
||
|
||
```cpp
|
||
class ShaderAsset : public Asset {
|
||
public:
|
||
AssetType type() const override { return AssetType::Shader; }
|
||
|
||
const std::string& vertexSource() const;
|
||
const std::string& fragmentSource() const;
|
||
};
|
||
```
|
||
|
||
### AudioAsset
|
||
|
||
音频资源。
|
||
|
||
```cpp
|
||
class AudioAsset : public Asset {
|
||
public:
|
||
AssetType type() const override { return AssetType::Audio; }
|
||
|
||
AudioFormat format() const;
|
||
int channels() const;
|
||
int sampleRate() const;
|
||
int bitsPerSample() const;
|
||
float duration() const;
|
||
const u8* data() const;
|
||
size_t dataSize() const;
|
||
bool streaming() const;
|
||
};
|
||
```
|
||
|
||
### DataAsset
|
||
|
||
通用二进制数据。
|
||
|
||
```cpp
|
||
class DataAsset : public Asset {
|
||
public:
|
||
AssetType type() const override { return AssetType::Data; }
|
||
|
||
const u8* data() const;
|
||
size_t size() const;
|
||
};
|
||
```
|
||
|
||
## 资源打包工具
|
||
|
||
### 安装
|
||
|
||
```bash
|
||
xmake build asset_packer
|
||
```
|
||
|
||
### 用法
|
||
|
||
```
|
||
Extra2D 资源打包工具 v1.0.0
|
||
|
||
用法:
|
||
asset_packer create <output.pack> [options] <inputs...>
|
||
asset_packer list <pack file>
|
||
asset_packer extract <pack file> <output dir>
|
||
|
||
命令:
|
||
create 创建资源包
|
||
list 列出资源包内容
|
||
extract 提取资源包内容
|
||
|
||
选项:
|
||
-c, --compression <algo> 压缩算法 (none, zstd, lz4, zlib),默认 zstd
|
||
-l, --level <level> 压缩级别 (1-22),默认 3
|
||
-e, --encrypt <key> 加密密钥
|
||
-t, --encrypt-type <type> 加密类型 (xor, aes),默认 xor
|
||
-v, --verbose 详细输出
|
||
-h, --help 显示帮助
|
||
```
|
||
|
||
### 示例
|
||
|
||
```bash
|
||
# 创建资源包(使用 Zstd 压缩)
|
||
asset_packer create game.pak -c zstd -v assets/
|
||
|
||
# 创建加密资源包
|
||
asset_packer create game.pak -c zstd -e "secret_key" -t xor -v assets/
|
||
|
||
# 列出资源包内容
|
||
asset_packer list game.pak
|
||
|
||
# 提取资源包
|
||
asset_packer extract game.pak extracted/
|
||
|
||
# 使用不同压缩算法
|
||
asset_packer create game.pak -c lz4 -v assets/
|
||
asset_packer create game.pak -c zlib -l 9 -v assets/
|
||
```
|
||
|
||
## 压缩算法对比
|
||
|
||
| 算法 | 压缩率 | 压缩速度 | 解压速度 | 适用场景 |
|
||
|------|--------|----------|----------|----------|
|
||
| Zstd | 高 | 快 | 很快 | 通用推荐 |
|
||
| LZ4 | 中 | 很快 | 很快 | 实时解压 |
|
||
| Zlib | 高 | 中 | 中 | 兼容性好 |
|
||
| None | - | - | - | 已压缩资源 |
|
||
|
||
## 设计模式
|
||
|
||
### 策略模式 (AssetLoader)
|
||
|
||
不同资源类型使用不同的加载策略。
|
||
|
||
```cpp
|
||
class AssetLoader<T> {
|
||
public:
|
||
virtual Ref<T> load(const std::string& path) = 0;
|
||
virtual Ref<T> loadFromMemory(const u8* data, size_t size) = 0;
|
||
virtual bool canLoad(const std::string& path) const = 0;
|
||
virtual AssetType type() const = 0;
|
||
virtual std::vector<std::string> extensions() const = 0;
|
||
};
|
||
```
|
||
|
||
### 享元模式 (AssetCache)
|
||
|
||
共享资源实例,减少内存占用。
|
||
|
||
### 装饰器模式 (DataProcessor)
|
||
|
||
链式处理数据流。
|
||
|
||
```cpp
|
||
DataPipe pipe;
|
||
pipe.encrypt("key")
|
||
.compress(Compression::Zstd);
|
||
```
|
||
|
||
### 服务定位器模式
|
||
|
||
全局访问资源服务。
|
||
|
||
```cpp
|
||
auto* service = ServiceLocator::get<IAssetService>();
|
||
```
|
||
|
||
## 线程安全
|
||
|
||
- `AssetCache` 使用读写锁 (`std::shared_mutex`)
|
||
- `AssetService` 使用读写锁保护资源映射
|
||
- 异步加载使用独立的工作线程
|
||
- 回调在主线程执行(需要调用 `process()`)
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 资源路径约定
|
||
|
||
```
|
||
assets/
|
||
├── textures/
|
||
│ ├── sprites/
|
||
│ └── backgrounds/
|
||
├── fonts/
|
||
├── shaders/
|
||
└── audio/
|
||
```
|
||
|
||
### 2. 预加载关键资源
|
||
|
||
```cpp
|
||
// 游戏启动时预加载
|
||
service.preload<TextureAsset>("textures/loading.png");
|
||
service.preload<FontAsset>("fonts/main.ttf");
|
||
```
|
||
|
||
### 3. 合理设置缓存上限
|
||
|
||
```cpp
|
||
// 根据目标平台设置
|
||
#ifdef MOBILE
|
||
service.setLimit(50 * 1024 * 1024); // 50MB
|
||
#else
|
||
service.setLimit(200 * 1024 * 1024); // 200MB
|
||
#endif
|
||
```
|
||
|
||
### 4. 定期清理缓存
|
||
|
||
```cpp
|
||
// 场景切换时清理
|
||
void onSceneChange() {
|
||
service.purge();
|
||
}
|
||
```
|
||
|
||
### 5. 使用资源包减少文件数量
|
||
|
||
```cpp
|
||
// 将小文件打包成资源包
|
||
// 减少文件 I/O 操作,提高加载速度
|
||
service.mount("textures.pak");
|
||
service.mount("audio.pak");
|
||
```
|
||
|
||
## 错误处理
|
||
|
||
```cpp
|
||
auto handle = service.load<TextureAsset>("missing.png");
|
||
if (!handle.valid()) {
|
||
// 资源加载失败
|
||
std::cerr << "Failed to load texture\n";
|
||
}
|
||
|
||
// 检查加载状态
|
||
if (handle.state() == AssetState::Failed) {
|
||
// 处理失败情况
|
||
}
|
||
```
|
||
|
||
## 版本历史
|
||
|
||
- **v1.0.0** - 初始版本
|
||
- 资源加载和缓存
|
||
- 资源打包和加密
|
||
- 异步加载支持
|
||
- 多种压缩算法
|