Extra2D/Docs/asset_service.md

11 KiB
Raw Blame History

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. 初始化资源服务

#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. 同步加载资源

// 加载纹理
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. 异步加载资源

// 异步加载
service.loadAsync<TextureAsset>("sprites/background.png", 
    [](AssetHandle<TextureAsset> handle) {
        if (handle.valid()) {
            // 资源加载完成,在主线程处理
        }
    });

// 在主线程处理回调
service.process();

4. 使用资源包

// 挂载资源包
service.mount("data.pak");

// 从资源包加载
auto texture = service.load<TextureAsset>("textures/hero.png");

// 卸载资源包
service.unmount("data.pak");

5. 缓存管理

// 设置缓存上限 (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

资源标识符,使用哈希值进行快速比较。

struct AssetID {
    u64 hash;           // 哈希值
    std::string path;   // 原始路径
    
    explicit AssetID(const std::string& path);
    bool valid() const;
    bool operator==(const AssetID& other) const;
};

AssetHandle

类型安全的资源句柄,使用弱引用避免阻止资源回收。

template<typename T>
class AssetHandle {
public:
    bool valid() const;         // 检查是否有效
    Ref<T> get() const;         // 获取强引用
    T* operator->() const;      // 解引用
    bool loaded() const;        // 检查是否已加载
    AssetState state() const;   // 获取状态
};

AssetCache

LRU 缓存管理器。

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

资源服务接口。

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

数据处理管道,支持链式调用。

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

资源包构建器。

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 加载。

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 字体。

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

着色器资源。

class ShaderAsset : public Asset {
public:
    AssetType type() const override { return AssetType::Shader; }
    
    const std::string& vertexSource() const;
    const std::string& fragmentSource() const;
};

AudioAsset

音频资源。

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

通用二进制数据。

class DataAsset : public Asset {
public:
    AssetType type() const override { return AssetType::Data; }
    
    const u8* data() const;
    size_t size() const;
};

资源打包工具

安装

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                显示帮助

示例

# 创建资源包(使用 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)

不同资源类型使用不同的加载策略。

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)

链式处理数据流。

DataPipe pipe;
pipe.encrypt("key")
    .compress(Compression::Zstd);

服务定位器模式

全局访问资源服务。

auto* service = ServiceLocator::get<IAssetService>();

线程安全

  • AssetCache 使用读写锁 (std::shared_mutex)
  • AssetService 使用读写锁保护资源映射
  • 异步加载使用独立的工作线程
  • 回调在主线程执行(需要调用 process()

最佳实践

1. 资源路径约定

assets/
├── textures/
│   ├── sprites/
│   └── backgrounds/
├── fonts/
├── shaders/
└── audio/

2. 预加载关键资源

// 游戏启动时预加载
service.preload<TextureAsset>("textures/loading.png");
service.preload<FontAsset>("fonts/main.ttf");

3. 合理设置缓存上限

// 根据目标平台设置
#ifdef MOBILE
    service.setLimit(50 * 1024 * 1024);  // 50MB
#else
    service.setLimit(200 * 1024 * 1024); // 200MB
#endif

4. 定期清理缓存

// 场景切换时清理
void onSceneChange() {
    service.purge();
}

5. 使用资源包减少文件数量

// 将小文件打包成资源包
// 减少文件 I/O 操作,提高加载速度
service.mount("textures.pak");
service.mount("audio.pak");

错误处理

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 - 初始版本
    • 资源加载和缓存
    • 资源打包和加密
    • 异步加载支持
    • 多种压缩算法