345 lines
9.0 KiB
C++
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
|