Extra2D/Extra2D/include/extra2d/services/asset_service.h

345 lines
9.0 KiB
C++

#pragma once
#include <condition_variable>
#include <extra2d/asset/asset.h>
#include <extra2d/asset/asset_cache.h>
#include <extra2d/asset/asset_handle.h>
#include <extra2d/asset/asset_loader.h>
#include <extra2d/asset/asset_pack.h>
#include <extra2d/asset/asset_types.h>
#include <extra2d/asset/data_processor.h>
#include <extra2d/asset/texture_asset.h>
#include <extra2d/asset/font_asset.h>
#include <extra2d/asset/shader_asset.h>
#include <extra2d/asset/audio_asset.h>
#include <extra2d/asset/data_asset.h>
#include <extra2d/core/service_interface.h>
#include <extra2d/core/types.h>
#include <extra2d/services/logger_service.h>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <queue>
#include <shared_mutex>
#include <string>
#include <thread>
#include <typeindex>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ---------------------------------------------------------------------------
// IAssetService - 资源服务接口
// ---------------------------------------------------------------------------
/**
* @brief 资源服务接口
*
* 提供资源加载、缓存、异步加载等功能。
* 使用模板方法支持类型安全的资源加载。
*/
class IAssetService : public IService {
public:
virtual ~IAssetService() = default;
/**
* @brief 同步加载资源
* @tparam T 资源类型
* @param path 资源路径
* @return 资源句柄
*/
template <typename T> AssetHandle<T> load(const std::string &path) {
static_assert(std::is_base_of_v<Asset, T>, "T must derive from Asset");
return AssetHandle<T>(loadImpl(AssetID(path), typeid(T)));
}
/**
* @brief 异步加载资源
* @tparam T 资源类型
* @param path 资源路径
* @param callback 加载完成回调
*/
template <typename T>
void loadAsync(const std::string &path, AssetLoadCallback<T> callback) {
static_assert(std::is_base_of_v<Asset, T>, "T must derive from Asset");
loadAsyncImpl(AssetID(path), typeid(T),
[cb = std::move(callback)](AssetHandleBase handle) {
cb(AssetHandle<T>(handle));
});
}
/**
* @brief 获取已缓存的资源
* @tparam T 资源类型
* @param path 资源路径
* @return 资源句柄,不存在返回空句柄
*/
template <typename T> AssetHandle<T> get(const std::string &path) {
static_assert(std::is_base_of_v<Asset, T>, "T must derive from Asset");
return AssetHandle<T>(getImpl(AssetID(path), typeid(T)));
}
/**
* @brief 预加载资源(后台加载,不返回句柄)
* @tparam T 资源类型
* @param path 资源路径
*/
template <typename T> void preload(const std::string &path) {
static_assert(std::is_base_of_v<Asset, T>, "T must derive from Asset");
preloadImpl(AssetID(path), typeid(T));
}
/**
* @brief 检查资源是否已加载
* @param path 资源路径
* @return 已加载返回 true
*/
virtual bool isLoaded(const std::string &path) const = 0;
/**
* @brief 检查资源是否正在加载
* @param path 资源路径
* @return 正在加载返回 true
*/
virtual bool isLoading(const std::string &path) const = 0;
/**
* @brief 卸载资源
* @param path 资源路径
*/
virtual void unload(const std::string &path) = 0;
/**
* @brief 设置缓存上限
* @param maxBytes 最大字节数
*/
virtual void setLimit(size_t maxBytes) = 0;
/**
* @brief 获取当前缓存大小
* @return 缓存字节数
*/
virtual size_t size() const = 0;
/**
* @brief 清理无引用资源
*/
virtual void purge() = 0;
/**
* @brief 清空所有缓存
*/
virtual void clear() = 0;
/**
* @brief 获取缓存统计信息
* @return 缓存统计
*/
virtual CacheStats stats() const = 0;
/**
* @brief 注册加载器
* @tparam T 资源类型
* @param loader 加载器实例
*/
template <typename T> void registerLoader(Unique<AssetLoader<T>> loader) {
static_assert(std::is_base_of_v<Asset, T>, "T must derive from Asset");
registerLoaderImpl(typeid(T), std::move(loader));
}
/**
* @brief 挂载资源包
* @param path 资源包路径
* @return 成功返回 true
*/
virtual bool mount(const std::string &path) = 0;
/**
* @brief 卸载资源包
* @param path 资源包路径
*/
virtual void unmount(const std::string &path) = 0;
/**
* @brief 设置数据处理管道
* @param pipe 处理管道
*/
virtual void setPipe(DataPipe pipe) = 0;
/**
* @brief 设置资源根目录
* @param path 根目录路径
*/
virtual void setRoot(const std::string &path) = 0;
/**
* @brief 获取资源根目录
* @return 根目录路径
*/
virtual std::string root() const = 0;
/**
* @brief 处理异步加载完成回调(在主线程调用)
*/
virtual void process() = 0;
protected:
/**
* @brief 同步加载实现
*/
virtual AssetHandleBase loadImpl(const AssetID &id, std::type_index type) = 0;
/**
* @brief 异步加载实现
*/
virtual void loadAsyncImpl(const AssetID &id, std::type_index type,
std::function<void(AssetHandleBase)> callback) = 0;
/**
* @brief 获取资源实现
*/
virtual AssetHandleBase getImpl(const AssetID &id, std::type_index type) = 0;
/**
* @brief 预加载实现
*/
virtual void preloadImpl(const AssetID &id, std::type_index type) = 0;
/**
* @brief 注册加载器实现
*/
virtual void registerLoaderImpl(std::type_index type,
Unique<AssetLoaderBase> loader) = 0;
};
// ---------------------------------------------------------------------------
// AssetService - 资源服务实现
// ---------------------------------------------------------------------------
/**
* @brief 资源服务实现
*
* 实现资源加载、缓存、异步加载等功能。
* 使用线程池处理异步加载任务。
*/
class AssetService : public IAssetService {
public:
AssetService();
~AssetService() override;
ServiceInfo info() const override {
ServiceInfo i;
i.name = "AssetService";
i.priority = ServicePriority::Resource;
i.enabled = true;
return i;
}
/**
* @brief 资源服务依赖日志服务
*/
std::vector<std::type_index> deps() const override {
return { std::type_index(typeid(ILogger)) };
}
bool init() override;
void shutdown() override;
bool isLoaded(const std::string &path) const override;
bool isLoading(const std::string &path) const override;
void unload(const std::string &path) override;
void setLimit(size_t maxBytes) override;
size_t size() const override;
void purge() override;
void clear() override;
CacheStats stats() const override;
bool mount(const std::string &path) override;
void unmount(const std::string &path) override;
void setPipe(DataPipe pipe) override;
void setRoot(const std::string &path) override;
std::string root() const override;
void process() override;
protected:
AssetHandleBase loadImpl(const AssetID &id, std::type_index type) override;
void loadAsyncImpl(const AssetID &id, std::type_index type,
std::function<void(AssetHandleBase)> callback) override;
AssetHandleBase getImpl(const AssetID &id, std::type_index type) override;
void preloadImpl(const AssetID &id, std::type_index type) override;
void registerLoaderImpl(std::type_index type,
Unique<AssetLoaderBase> loader) override;
private:
struct LoadTask {
AssetID id;
std::type_index type = typeid(void);
std::function<void(AssetHandleBase)> callback;
};
struct LoadedAsset {
Ref<Asset> asset;
std::type_index type = typeid(void);
};
std::string root_;
Unique<AssetCache> cache_;
PackManager packManager_;
DataPipe pipe_;
mutable std::shared_mutex mutex_;
std::unordered_map<AssetID, LoadedAsset> assets_;
std::unordered_map<AssetID, AssetState> states_;
std::unordered_map<std::type_index, Unique<AssetLoaderBase>> loaders_;
std::thread workerThread_;
std::queue<LoadTask> taskQueue_;
std::mutex taskMutex_;
std::condition_variable taskCv_;
std::atomic<bool> running_{false};
std::queue<std::function<void()>> callbackQueue_;
std::mutex callbackMutex_;
/**
* @brief 工作线程函数
*/
void workerFunc();
/**
* @brief 从文件系统加载资源
* @param id 资源ID
* @param type 资源类型
* @return 加载的资源
*/
Ref<Asset> loadFromFile(const AssetID &id, std::type_index type);
/**
* @brief 从资源包加载资源
* @param id 资源ID
* @param type 资源类型
* @return 加载的资源
*/
Ref<Asset> loadFromPack(const AssetID &id, std::type_index type);
/**
* @brief 获取加载器
* @param type 资源类型
* @return 加载器指针
*/
AssetLoaderBase *getLoader(std::type_index type);
/**
* @brief 根据路径推断资源类型
* @param path 资源路径
* @return 资源类型索引
*/
std::type_index inferType(const std::string &path);
};
} // namespace extra2d