refactor(core): 重构生命周期管理,引入Lifecycle统一管理模块和服务
重构模块和服务初始化流程,使用Lifecycle类统一管理依赖和生命周期 移除旧的ServiceLocator和Registry,简化架构 添加模块和服务依赖声明功能,支持自动拓扑排序 优化初始化顺序,支持并行初始化独立模块 更新相关模块和服务以适配新生命周期管理接口
This commit is contained in:
parent
d3973cd820
commit
174d7327ef
|
|
@ -1,26 +1,69 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/lifecycle.h>
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
class Window;
|
class WindowModule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 应用程序类
|
* @brief 应用程序类
|
||||||
*/
|
*/
|
||||||
class Application {
|
class Application {
|
||||||
public:
|
public:
|
||||||
static Application& instance();
|
static Application &instance();
|
||||||
|
|
||||||
Application(const Application&) = delete;
|
Application(const Application &) = delete;
|
||||||
Application& operator=(const Application&) = delete;
|
Application &operator=(const Application &) = delete;
|
||||||
|
|
||||||
std::string name = "Extra2D App";
|
std::string name = "Extra2D App";
|
||||||
std::string version = "1.0.0";
|
std::string version = "1.0.0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建并注册模块
|
||||||
|
* @tparam T 模块类型
|
||||||
|
* @tparam Args 构造函数参数类型
|
||||||
|
* @param args 构造函数参数
|
||||||
|
* @return 模块指针
|
||||||
|
*/
|
||||||
|
template <typename T, typename... Args> T *useModule(Args &&...args) {
|
||||||
|
return Lifecycle::instance().createModule<T>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块
|
||||||
|
* @tparam T 模块类型
|
||||||
|
* @return 模块指针
|
||||||
|
*/
|
||||||
|
template <typename T> T *module() const {
|
||||||
|
return Lifecycle::instance().module<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建并注册服务
|
||||||
|
* @tparam T 服务接口类型
|
||||||
|
* @tparam Impl 服务实现类型
|
||||||
|
* @tparam Args 构造函数参数类型
|
||||||
|
* @param args 构造函数参数
|
||||||
|
* @return 服务实例
|
||||||
|
*/
|
||||||
|
template <typename T, typename Impl, typename... Args>
|
||||||
|
Ref<T> useService(Args &&...args) {
|
||||||
|
return Lifecycle::instance().createService<T, Impl>(
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务
|
||||||
|
* @tparam T 服务接口类型
|
||||||
|
* @return 服务实例
|
||||||
|
*/
|
||||||
|
template <typename T> Ref<T> service() const {
|
||||||
|
return Lifecycle::instance().service<T>();
|
||||||
|
}
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
void run();
|
void run();
|
||||||
|
|
@ -28,14 +71,14 @@ public:
|
||||||
|
|
||||||
bool paused() const { return paused_; }
|
bool paused() const { return paused_; }
|
||||||
bool running() const { return running_; }
|
bool running() const { return running_; }
|
||||||
Window* window() const { return window_; }
|
WindowModule *windowModule() const;
|
||||||
|
|
||||||
f32 dt() const { return dt_; }
|
f32 dt() const { return dt_; }
|
||||||
f32 totalTime() const { return totalTime_; }
|
f32 totalTime() const { return totalTime_; }
|
||||||
int fps() const { return fps_; }
|
int fps() const { return fps_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Application() = default;
|
Application();
|
||||||
~Application();
|
~Application();
|
||||||
|
|
||||||
void mainLoop();
|
void mainLoop();
|
||||||
|
|
@ -43,7 +86,6 @@ private:
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
bool running_ = false;
|
bool running_ = false;
|
||||||
bool paused_ = false;
|
bool paused_ = false;
|
||||||
Window* window_ = nullptr;
|
|
||||||
|
|
||||||
f32 dt_ = 0.0f;
|
f32 dt_ = 0.0f;
|
||||||
f32 totalTime_ = 0.0f;
|
f32 totalTime_ = 0.0f;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,350 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/core/module.h>
|
||||||
|
#include <extra2d/core/service_interface.h>
|
||||||
|
#include <extra2d/core/types.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
class Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 编译期类型ID
|
||||||
|
*/
|
||||||
|
using TypeId = size_t;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
inline TypeId nextTypeId() {
|
||||||
|
static TypeId id = 0;
|
||||||
|
return ++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline TypeId getTypeId() {
|
||||||
|
static TypeId id = nextTypeId();
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 生命周期单元类型
|
||||||
|
*/
|
||||||
|
enum class UnitType : u8 {
|
||||||
|
Module,
|
||||||
|
Service
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 生命周期管理器
|
||||||
|
* 统一管理模块和服务的初始化、更新和销毁
|
||||||
|
*/
|
||||||
|
class Lifecycle {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 获取单例实例
|
||||||
|
* @return Lifecycle 实例引用
|
||||||
|
*/
|
||||||
|
static Lifecycle& instance();
|
||||||
|
|
||||||
|
Lifecycle(const Lifecycle&) = delete;
|
||||||
|
Lifecycle& operator=(const Lifecycle&) = delete;
|
||||||
|
|
||||||
|
// ========== 注册接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注册模块
|
||||||
|
* @tparam T 模块类型
|
||||||
|
* @param module 模块实例
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
void addModule(Unique<T> module) {
|
||||||
|
static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
|
||||||
|
|
||||||
|
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
|
||||||
|
auto typeId = detail::getTypeId<T>();
|
||||||
|
|
||||||
|
for (const auto& entry : modules_) {
|
||||||
|
if (entry.id == typeId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleEntry entry;
|
||||||
|
entry.id = typeId;
|
||||||
|
entry.module = std::move(module);
|
||||||
|
modules_.push_back(std::move(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建并注册模块
|
||||||
|
* @tparam T 模块类型
|
||||||
|
* @tparam Args 构造函数参数类型
|
||||||
|
* @param args 构造函数参数
|
||||||
|
* @return 模块指针
|
||||||
|
*/
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
T* createModule(Args&&... args) {
|
||||||
|
static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
|
||||||
|
|
||||||
|
auto module = ptr::unique<T>(std::forward<Args>(args)...);
|
||||||
|
T* ptr = module.get();
|
||||||
|
module->setApp(app_);
|
||||||
|
addModule<T>(std::move(module));
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注册服务
|
||||||
|
* @tparam T 服务接口类型
|
||||||
|
* @param service 服务实例
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
void addService(Ref<T> service) {
|
||||||
|
static_assert(std::is_base_of_v<IService, T>, "T must derive from IService");
|
||||||
|
|
||||||
|
std::unique_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
|
||||||
|
auto typeId = std::type_index(typeid(T));
|
||||||
|
|
||||||
|
for (const auto& entry : services_) {
|
||||||
|
if (entry.id == typeId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceEntry entry;
|
||||||
|
entry.id = typeId;
|
||||||
|
entry.service = std::static_pointer_cast<IService>(service);
|
||||||
|
services_.push_back(std::move(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建并注册服务
|
||||||
|
* @tparam T 服务接口类型
|
||||||
|
* @tparam Impl 服务实现类型
|
||||||
|
* @tparam Args 构造函数参数类型
|
||||||
|
* @param args 构造函数参数
|
||||||
|
* @return 服务实例
|
||||||
|
*/
|
||||||
|
template<typename T, typename Impl, typename... Args>
|
||||||
|
Ref<T> createService(Args&&... args) {
|
||||||
|
static_assert(std::is_base_of_v<IService, T>, "T must derive from IService");
|
||||||
|
static_assert(std::is_base_of_v<T, Impl>, "Impl must derive from T");
|
||||||
|
|
||||||
|
auto service = ptr::make<Impl>(std::forward<Args>(args)...);
|
||||||
|
auto result = std::static_pointer_cast<T>(service);
|
||||||
|
addService<T>(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 获取接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块
|
||||||
|
* @tparam T 模块类型
|
||||||
|
* @return 模块指针,不存在返回 nullptr
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T* module() const {
|
||||||
|
static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
|
||||||
|
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
auto typeId = detail::getTypeId<T>();
|
||||||
|
|
||||||
|
for (const auto& entry : modules_) {
|
||||||
|
if (entry.id == typeId && entry.module) {
|
||||||
|
return static_cast<T*>(entry.module.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务
|
||||||
|
* @tparam T 服务接口类型
|
||||||
|
* @return 服务实例,不存在返回 nullptr
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
Ref<T> service() const {
|
||||||
|
static_assert(std::is_base_of_v<IService, T>, "T must derive from IService");
|
||||||
|
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
auto typeId = std::type_index(typeid(T));
|
||||||
|
|
||||||
|
for (const auto& entry : services_) {
|
||||||
|
if (entry.id == typeId && entry.service) {
|
||||||
|
return std::static_pointer_cast<T>(entry.service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查模块是否存在
|
||||||
|
* @tparam T 模块类型
|
||||||
|
* @return 存在返回 true
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
bool hasModule() const {
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
auto typeId = detail::getTypeId<T>();
|
||||||
|
|
||||||
|
for (const auto& entry : modules_) {
|
||||||
|
if (entry.id == typeId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查服务是否存在
|
||||||
|
* @tparam T 服务接口类型
|
||||||
|
* @return 存在返回 true
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
bool hasService() const {
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
auto typeId = std::type_index(typeid(T));
|
||||||
|
|
||||||
|
for (const auto& entry : services_) {
|
||||||
|
if (entry.id == typeId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 生命周期控制 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化所有单元(按依赖拓扑排序)
|
||||||
|
* @return 全部成功返回 true
|
||||||
|
*/
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 更新所有单元
|
||||||
|
* @param dt 帧间隔时间
|
||||||
|
*/
|
||||||
|
void update(f32 dt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 暂停所有单元
|
||||||
|
*/
|
||||||
|
void pause();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 恢复所有单元
|
||||||
|
*/
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭所有单元(逆拓扑排序)
|
||||||
|
*/
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 清空所有单元
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// ========== 配置接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置 Application
|
||||||
|
* @param app Application 指针
|
||||||
|
*/
|
||||||
|
void setApp(Application* app) { app_ = app; }
|
||||||
|
|
||||||
|
// ========== 查询接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取单元总数
|
||||||
|
* @return 单元数量
|
||||||
|
*/
|
||||||
|
size_t size() const {
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
return modules_.size() + services_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块数量
|
||||||
|
* @return 模块数量
|
||||||
|
*/
|
||||||
|
size_t moduleCount() const {
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
return modules_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务数量
|
||||||
|
* @return 服务数量
|
||||||
|
*/
|
||||||
|
size_t serviceCount() const {
|
||||||
|
std::shared_lock<std::shared_mutex> lock(mutex_);
|
||||||
|
return services_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Lifecycle() = default;
|
||||||
|
~Lifecycle() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 单元索引(用于依赖图)
|
||||||
|
*/
|
||||||
|
struct UnitIndex {
|
||||||
|
UnitType type;
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 模块条目
|
||||||
|
*/
|
||||||
|
struct ModuleEntry {
|
||||||
|
TypeId id = 0;
|
||||||
|
Unique<Module> module;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 服务条目
|
||||||
|
*/
|
||||||
|
struct ServiceEntry {
|
||||||
|
std::type_index id;
|
||||||
|
Ref<IService> service;
|
||||||
|
|
||||||
|
ServiceEntry() : id(typeid(void)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按层级分组结果
|
||||||
|
*/
|
||||||
|
std::vector<std::vector<UnitIndex>> groupByLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查找模块索引
|
||||||
|
* @param type 类型索引
|
||||||
|
* @return 模块索引,不存在返回 SIZE_MAX
|
||||||
|
*/
|
||||||
|
size_t findModuleIndex(std::type_index type) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查找服务索引
|
||||||
|
* @param type 类型索引
|
||||||
|
* @return 服务索引,不存在返回 SIZE_MAX
|
||||||
|
*/
|
||||||
|
size_t findServiceIndex(std::type_index type) const;
|
||||||
|
|
||||||
|
std::vector<ModuleEntry> modules_;
|
||||||
|
std::vector<ServiceEntry> services_;
|
||||||
|
mutable std::shared_mutex mutex_;
|
||||||
|
Application* app_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -38,7 +37,7 @@ public:
|
||||||
* @brief 获取模块名称
|
* @brief 获取模块名称
|
||||||
* @return 模块名称
|
* @return 模块名称
|
||||||
*/
|
*/
|
||||||
virtual const char* name() const = 0;
|
virtual const char *name() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取模块优先级(数值越小越优先)
|
* @brief 获取模块优先级(数值越小越优先)
|
||||||
|
|
@ -52,6 +51,12 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual std::vector<std::type_index> deps() const { return {}; }
|
virtual std::vector<std::type_index> deps() const { return {}; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务依赖列表
|
||||||
|
* @return 依赖服务类型列表
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::type_index> needsServices() const { return {}; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 检查模块是否支持并行初始化
|
* @brief 检查模块是否支持并行初始化
|
||||||
* @return 支持并行初始化返回 true
|
* @return 支持并行初始化返回 true
|
||||||
|
|
@ -62,16 +67,16 @@ public:
|
||||||
* @brief 设置所属Application
|
* @brief 设置所属Application
|
||||||
* @param app Application指针
|
* @param app Application指针
|
||||||
*/
|
*/
|
||||||
void setApp(class Application* app) { app_ = app; }
|
void setApp(class Application *app) { app_ = app; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取Application
|
* @brief 获取Application
|
||||||
* @return Application指针
|
* @return Application指针
|
||||||
*/
|
*/
|
||||||
class Application* app() const { return app_; }
|
class Application *app() const { return app_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class Application* app_ = nullptr;
|
class Application *app_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <extra2d/core/module.h>
|
|
||||||
#include <extra2d/core/types.h>
|
|
||||||
#include <typeindex>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
class Application;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 编译期类型ID生成器
|
|
||||||
*/
|
|
||||||
using TypeId = size_t;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
inline TypeId nextTypeId() {
|
|
||||||
static TypeId id = 0;
|
|
||||||
return ++id;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> inline TypeId getTypeId() {
|
|
||||||
static TypeId id = nextTypeId();
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 模块注册表
|
|
||||||
* 管理模块的注册、拓扑排序和生命周期
|
|
||||||
*/
|
|
||||||
class Registry {
|
|
||||||
public:
|
|
||||||
static constexpr size_t MAX_MODULES = 64;
|
|
||||||
|
|
||||||
static Registry &instance();
|
|
||||||
|
|
||||||
Registry(const Registry &) = delete;
|
|
||||||
Registry &operator=(const Registry &) = delete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注册模块
|
|
||||||
* @tparam T 模块类型
|
|
||||||
* @tparam Args 构造函数参数类型
|
|
||||||
* @param args 构造函数参数
|
|
||||||
* @return 模块指针
|
|
||||||
*/
|
|
||||||
template <typename T, typename... Args> T *use(Args &&...args) {
|
|
||||||
static_assert(std::is_base_of_v<Module, T>, "T must derive from Module");
|
|
||||||
|
|
||||||
TypeId typeId = detail::getTypeId<T>();
|
|
||||||
|
|
||||||
// 数组查找,O(n) 但 n 很小,缓存友好
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (modules_[i].id == typeId) {
|
|
||||||
return static_cast<T *>(modules_[i].module.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加新模块
|
|
||||||
if (moduleCount_ >= MAX_MODULES) {
|
|
||||||
return nullptr; // 模块数量超过上限
|
|
||||||
}
|
|
||||||
|
|
||||||
auto module = ptr::unique<T>(std::forward<Args>(args)...);
|
|
||||||
T *ptr = module.get();
|
|
||||||
module->setApp(app_);
|
|
||||||
|
|
||||||
modules_[moduleCount_].id = typeId;
|
|
||||||
modules_[moduleCount_].module = std::move(module);
|
|
||||||
modules_[moduleCount_].valid = true;
|
|
||||||
++moduleCount_;
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取模块
|
|
||||||
* @tparam T 模块类型
|
|
||||||
* @return 模块指针,不存在返回 nullptr
|
|
||||||
*/
|
|
||||||
template <typename T> T *get() const {
|
|
||||||
TypeId typeId = detail::getTypeId<T>();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (modules_[i].id == typeId && modules_[i].valid) {
|
|
||||||
return static_cast<T *>(modules_[i].module.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取模块(基类版本)
|
|
||||||
* @param typeIdx 类型索引
|
|
||||||
* @return 模块指针
|
|
||||||
*/
|
|
||||||
Module *get(std::type_index typeIdx) const {
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (modules_[i].valid) {
|
|
||||||
Module *mod = modules_[i].module.get();
|
|
||||||
if (std::type_index(typeid(*mod)) == typeIdx) {
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置Application
|
|
||||||
*/
|
|
||||||
void setApp(Application *app) { app_ = app; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化所有模块(按优先级拓扑排序,支持并行初始化)
|
|
||||||
* @return 初始化成功返回 true
|
|
||||||
*/
|
|
||||||
bool init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 关闭所有模块
|
|
||||||
*/
|
|
||||||
void shutdown();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 清空所有模块
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取模块数量
|
|
||||||
*/
|
|
||||||
size_t size() const { return moduleCount_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Registry() = default;
|
|
||||||
~Registry() = default;
|
|
||||||
|
|
||||||
struct ModuleEntry {
|
|
||||||
TypeId id = 0;
|
|
||||||
Unique<Module> module;
|
|
||||||
bool valid = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 拓扑排序模块
|
|
||||||
* @return 排序后的模块列表
|
|
||||||
*/
|
|
||||||
std::vector<Module *> sort();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 按层级对模块进行分组
|
|
||||||
* 同一层级的模块没有相互依赖,可以并行初始化
|
|
||||||
* @return 按层级分组的模块列表
|
|
||||||
*/
|
|
||||||
std::vector<std::vector<Module *>> group();
|
|
||||||
|
|
||||||
std::array<ModuleEntry, MAX_MODULES> modules_;
|
|
||||||
size_t moduleCount_ = 0;
|
|
||||||
Application *app_ = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,398 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
|
||||||
#include <string>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 错误码枚举
|
|
||||||
*/
|
|
||||||
enum class ErrorCode {
|
|
||||||
None = 0,
|
|
||||||
Unknown = 1,
|
|
||||||
InvalidArgument = 2,
|
|
||||||
OutOfMemory = 3,
|
|
||||||
FileNotFound = 4,
|
|
||||||
PermissionDenied = 5,
|
|
||||||
NotImplemented = 6,
|
|
||||||
AlreadyExists = 7,
|
|
||||||
NotInitialized = 8,
|
|
||||||
AlreadyInitialized = 9,
|
|
||||||
OperationFailed = 10,
|
|
||||||
Timeout = 11,
|
|
||||||
Cancelled = 12,
|
|
||||||
InvalidState = 13,
|
|
||||||
ResourceExhausted = 14,
|
|
||||||
Unavailable = 15,
|
|
||||||
DataLoss = 16,
|
|
||||||
Unauthenticated = 17,
|
|
||||||
PermissionDenied2 = 18,
|
|
||||||
ResourceNotFound = 19,
|
|
||||||
Aborted = 20,
|
|
||||||
OutOfRange = 21,
|
|
||||||
Unimplemented = 22,
|
|
||||||
Internal = 23,
|
|
||||||
DataCorrupted = 24,
|
|
||||||
RequestTooLarge = 25,
|
|
||||||
ResourceBusy = 26,
|
|
||||||
QuotaExceeded = 27,
|
|
||||||
DeadlineExceeded = 28,
|
|
||||||
LoadBalancing = 29,
|
|
||||||
NetworkError = 30,
|
|
||||||
ProtocolError = 31,
|
|
||||||
ServiceUnavailable = 32,
|
|
||||||
GatewayError = 33,
|
|
||||||
RateLimited = 34,
|
|
||||||
BadRequest = 35,
|
|
||||||
Unauthorized = 36,
|
|
||||||
Forbidden = 37,
|
|
||||||
NotFound = 38,
|
|
||||||
MethodNotAllowed = 39,
|
|
||||||
Conflict = 40,
|
|
||||||
Gone = 41,
|
|
||||||
LengthRequired = 42,
|
|
||||||
PreconditionFailed = 43,
|
|
||||||
PayloadTooLarge = 44,
|
|
||||||
UriTooLong = 45,
|
|
||||||
UnsupportedMediaType = 46,
|
|
||||||
RangeNotSatisfiable = 47,
|
|
||||||
ExpectationFailed = 48,
|
|
||||||
ImATeapot = 49,
|
|
||||||
MisdirectedRequest = 50,
|
|
||||||
UnprocessableEntity = 51,
|
|
||||||
Locked = 52,
|
|
||||||
FailedDependency = 53,
|
|
||||||
TooEarly = 54,
|
|
||||||
UpgradeRequired = 55,
|
|
||||||
PreconditionRequired = 56,
|
|
||||||
TooManyRequests = 57,
|
|
||||||
RequestHeaderFieldsTooLarge = 58,
|
|
||||||
UnavailableForLegalReasons = 59
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 错误信息结构
|
|
||||||
*/
|
|
||||||
struct Error {
|
|
||||||
ErrorCode code = ErrorCode::None;
|
|
||||||
std::string message;
|
|
||||||
std::string file;
|
|
||||||
int line = 0;
|
|
||||||
|
|
||||||
Error() = default;
|
|
||||||
Error(ErrorCode c, const std::string& msg) : code(c), message(msg) {}
|
|
||||||
Error(ErrorCode c, const std::string& msg, const std::string& f, int l)
|
|
||||||
: code(c), message(msg), file(f), line(l) {}
|
|
||||||
|
|
||||||
bool ok() const { return code == ErrorCode::None; }
|
|
||||||
|
|
||||||
static Error none() { return Error(); }
|
|
||||||
static Error unknown(const std::string& msg) { return Error(ErrorCode::Unknown, msg); }
|
|
||||||
static Error invalidArgument(const std::string& msg) { return Error(ErrorCode::InvalidArgument, msg); }
|
|
||||||
static Error outOfMemory(const std::string& msg) { return Error(ErrorCode::OutOfMemory, msg); }
|
|
||||||
static Error fileNotFound(const std::string& msg) { return Error(ErrorCode::FileNotFound, msg); }
|
|
||||||
static Error permissionDenied(const std::string& msg) { return Error(ErrorCode::PermissionDenied, msg); }
|
|
||||||
static Error notImplemented(const std::string& msg) { return Error(ErrorCode::NotImplemented, msg); }
|
|
||||||
static Error alreadyExists(const std::string& msg) { return Error(ErrorCode::AlreadyExists, msg); }
|
|
||||||
static Error notInitialized(const std::string& msg) { return Error(ErrorCode::NotInitialized, msg); }
|
|
||||||
static Error alreadyInitialized(const std::string& msg) { return Error(ErrorCode::AlreadyInitialized, msg); }
|
|
||||||
static Error operationFailed(const std::string& msg) { return Error(ErrorCode::OperationFailed, msg); }
|
|
||||||
static Error timeout(const std::string& msg) { return Error(ErrorCode::Timeout, msg); }
|
|
||||||
static Error cancelled(const std::string& msg) { return Error(ErrorCode::Cancelled, msg); }
|
|
||||||
static Error invalidState(const std::string& msg) { return Error(ErrorCode::InvalidState, msg); }
|
|
||||||
static Error resourceExhausted(const std::string& msg) { return Error(ErrorCode::ResourceExhausted, msg); }
|
|
||||||
static Error unavailable(const std::string& msg) { return Error(ErrorCode::Unavailable, msg); }
|
|
||||||
static Error dataLoss(const std::string& msg) { return Error(ErrorCode::DataLoss, msg); }
|
|
||||||
static Error unauthenticated(const std::string& msg) { return Error(ErrorCode::Unauthenticated, msg); }
|
|
||||||
static Error permissionDenied2(const std::string& msg) { return Error(ErrorCode::PermissionDenied2, msg); }
|
|
||||||
static Error resourceNotFound(const std::string& msg) { return Error(ErrorCode::ResourceNotFound, msg); }
|
|
||||||
static Error aborted(const std::string& msg) { return Error(ErrorCode::Aborted, msg); }
|
|
||||||
static Error outOfRange(const std::string& msg) { return Error(ErrorCode::OutOfRange, msg); }
|
|
||||||
static Error unimplemented(const std::string& msg) { return Error(ErrorCode::Unimplemented, msg); }
|
|
||||||
static Error internal(const std::string& msg) { return Error(ErrorCode::Internal, msg); }
|
|
||||||
static Error dataCorrupted(const std::string& msg) { return Error(ErrorCode::DataCorrupted, msg); }
|
|
||||||
static Error requestTooLarge(const std::string& msg) { return Error(ErrorCode::RequestTooLarge, msg); }
|
|
||||||
static Error resourceBusy(const std::string& msg) { return Error(ErrorCode::ResourceBusy, msg); }
|
|
||||||
static Error quotaExceeded(const std::string& msg) { return Error(ErrorCode::QuotaExceeded, msg); }
|
|
||||||
static Error deadlineExceeded(const std::string& msg) { return Error(ErrorCode::DeadlineExceeded, msg); }
|
|
||||||
static Error loadBalancing(const std::string& msg) { return Error(ErrorCode::LoadBalancing, msg); }
|
|
||||||
static Error networkError(const std::string& msg) { return Error(ErrorCode::NetworkError, msg); }
|
|
||||||
static Error protocolError(const std::string& msg) { return Error(ErrorCode::ProtocolError, msg); }
|
|
||||||
static Error serviceUnavailable(const std::string& msg) { return Error(ErrorCode::ServiceUnavailable, msg); }
|
|
||||||
static Error gatewayError(const std::string& msg) { return Error(ErrorCode::GatewayError, msg); }
|
|
||||||
static Error rateLimited(const std::string& msg) { return Error(ErrorCode::RateLimited, msg); }
|
|
||||||
static Error badRequest(const std::string& msg) { return Error(ErrorCode::BadRequest, msg); }
|
|
||||||
static Error unauthorized(const std::string& msg) { return Error(ErrorCode::Unauthorized, msg); }
|
|
||||||
static Error forbidden(const std::string& msg) { return Error(ErrorCode::Forbidden, msg); }
|
|
||||||
static Error notFound(const std::string& msg) { return Error(ErrorCode::NotFound, msg); }
|
|
||||||
static Error methodNotAllowed(const std::string& msg) { return Error(ErrorCode::MethodNotAllowed, msg); }
|
|
||||||
static Error conflict(const std::string& msg) { return Error(ErrorCode::Conflict, msg); }
|
|
||||||
static Error gone(const std::string& msg) { return Error(ErrorCode::Gone, msg); }
|
|
||||||
static Error lengthRequired(const std::string& msg) { return Error(ErrorCode::LengthRequired, msg); }
|
|
||||||
static Error preconditionFailed(const std::string& msg) { return Error(ErrorCode::PreconditionFailed, msg); }
|
|
||||||
static Error payloadTooLarge(const std::string& msg) { return Error(ErrorCode::PayloadTooLarge, msg); }
|
|
||||||
static Error uriTooLong(const std::string& msg) { return Error(ErrorCode::UriTooLong, msg); }
|
|
||||||
static Error unsupportedMediaType(const std::string& msg) { return Error(ErrorCode::UnsupportedMediaType, msg); }
|
|
||||||
static Error rangeNotSatisfiable(const std::string& msg) { return Error(ErrorCode::RangeNotSatisfiable, msg); }
|
|
||||||
static Error expectationFailed(const std::string& msg) { return Error(ErrorCode::ExpectationFailed, msg); }
|
|
||||||
static Error imATeapot(const std::string& msg) { return Error(ErrorCode::ImATeapot, msg); }
|
|
||||||
static Error misdirectedRequest(const std::string& msg) { return Error(ErrorCode::MisdirectedRequest, msg); }
|
|
||||||
static Error unprocessableEntity(const std::string& msg) { return Error(ErrorCode::UnprocessableEntity, msg); }
|
|
||||||
static Error locked(const std::string& msg) { return Error(ErrorCode::Locked, msg); }
|
|
||||||
static Error failedDependency(const std::string& msg) { return Error(ErrorCode::FailedDependency, msg); }
|
|
||||||
static Error tooEarly(const std::string& msg) { return Error(ErrorCode::TooEarly, msg); }
|
|
||||||
static Error upgradeRequired(const std::string& msg) { return Error(ErrorCode::UpgradeRequired, msg); }
|
|
||||||
static Error preconditionRequired(const std::string& msg) { return Error(ErrorCode::PreconditionRequired, msg); }
|
|
||||||
static Error tooManyRequests(const std::string& msg) { return Error(ErrorCode::TooManyRequests, msg); }
|
|
||||||
static Error requestHeaderFieldsTooLarge(const std::string& msg) { return Error(ErrorCode::RequestHeaderFieldsTooLarge, msg); }
|
|
||||||
static Error unavailableForLegalReasons(const std::string& msg) { return Error(ErrorCode::UnavailableForLegalReasons, msg); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Result类型,用于错误处理
|
|
||||||
* @tparam T 成功时的值类型
|
|
||||||
* @tparam E 错误类型,默认为Error
|
|
||||||
*/
|
|
||||||
template<typename T, typename E = Error>
|
|
||||||
class Result {
|
|
||||||
public:
|
|
||||||
Result() : hasValue_(false) {
|
|
||||||
new (&storage_.error) E();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Result() {
|
|
||||||
if (hasValue_) {
|
|
||||||
storage_.value.~T();
|
|
||||||
} else {
|
|
||||||
storage_.error.~E();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(const Result& other) : hasValue_(other.hasValue_) {
|
|
||||||
if (hasValue_) {
|
|
||||||
new (&storage_.value) T(other.storage_.value);
|
|
||||||
} else {
|
|
||||||
new (&storage_.error) E(other.storage_.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(Result&& other) noexcept : hasValue_(other.hasValue_) {
|
|
||||||
if (hasValue_) {
|
|
||||||
new (&storage_.value) T(std::move(other.storage_.value));
|
|
||||||
} else {
|
|
||||||
new (&storage_.error) E(std::move(other.storage_.error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result& operator=(const Result& other) {
|
|
||||||
if (this != &other) {
|
|
||||||
this->~Result();
|
|
||||||
hasValue_ = other.hasValue_;
|
|
||||||
if (hasValue_) {
|
|
||||||
new (&storage_.value) T(other.storage_.value);
|
|
||||||
} else {
|
|
||||||
new (&storage_.error) E(other.storage_.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result& operator=(Result&& other) noexcept {
|
|
||||||
if (this != &other) {
|
|
||||||
this->~Result();
|
|
||||||
hasValue_ = other.hasValue_;
|
|
||||||
if (hasValue_) {
|
|
||||||
new (&storage_.value) T(std::move(other.storage_.value));
|
|
||||||
} else {
|
|
||||||
new (&storage_.error) E(std::move(other.storage_.error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result<T, E> ok(T value) {
|
|
||||||
Result<T, E> result;
|
|
||||||
result.hasValue_ = true;
|
|
||||||
new (&result.storage_.value) T(std::move(value));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result<T, E> err(E error) {
|
|
||||||
Result<T, E> result;
|
|
||||||
result.hasValue_ = false;
|
|
||||||
new (&result.storage_.error) E(std::move(error));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok() const { return hasValue_; }
|
|
||||||
bool isOk() const { return hasValue_; }
|
|
||||||
bool isErr() const { return !hasValue_; }
|
|
||||||
|
|
||||||
T& value() & {
|
|
||||||
return storage_.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& value() const & {
|
|
||||||
return storage_.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
T&& value() && {
|
|
||||||
return std::move(storage_.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
E& error() & {
|
|
||||||
return storage_.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const E& error() const & {
|
|
||||||
return storage_.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
E&& error() && {
|
|
||||||
return std::move(storage_.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
T valueOr(T defaultValue) const {
|
|
||||||
return hasValue_ ? storage_.value : std::move(defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
Result<T, E> map(F&& f) {
|
|
||||||
if (hasValue_) {
|
|
||||||
return Result<T, E>::ok(f(storage_.value));
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
Result<T, E> mapErr(F&& f) {
|
|
||||||
if (!hasValue_) {
|
|
||||||
return Result<T, E>::err(f(storage_.error));
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
auto andThen(F&& f) -> decltype(f(std::declval<T>())) {
|
|
||||||
if (hasValue_) {
|
|
||||||
return f(storage_.value);
|
|
||||||
}
|
|
||||||
return Result<typename decltype(f(std::declval<T>()))::ValueType, E>::err(storage_.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
Result<T, E> orElse(F&& f) {
|
|
||||||
if (!hasValue_) {
|
|
||||||
return f(storage_.error);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
union Storage {
|
|
||||||
T value;
|
|
||||||
E error;
|
|
||||||
|
|
||||||
Storage() {}
|
|
||||||
~Storage() {}
|
|
||||||
} storage_;
|
|
||||||
|
|
||||||
bool hasValue_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 特化void类型
|
|
||||||
template<typename E>
|
|
||||||
class Result<void, E> {
|
|
||||||
public:
|
|
||||||
Result() : hasValue_(true) {}
|
|
||||||
|
|
||||||
~Result() {
|
|
||||||
if (!hasValue_) {
|
|
||||||
storage_.error.~E();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(const Result& other) : hasValue_(other.hasValue_) {
|
|
||||||
if (!hasValue_) {
|
|
||||||
new (&storage_.error) E(other.storage_.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(Result&& other) noexcept : hasValue_(other.hasValue_) {
|
|
||||||
if (!hasValue_) {
|
|
||||||
new (&storage_.error) E(std::move(other.storage_.error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result& operator=(const Result& other) {
|
|
||||||
if (this != &other) {
|
|
||||||
this->~Result();
|
|
||||||
hasValue_ = other.hasValue_;
|
|
||||||
if (!hasValue_) {
|
|
||||||
new (&storage_.error) E(other.storage_.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result& operator=(Result&& other) noexcept {
|
|
||||||
if (this != &other) {
|
|
||||||
this->~Result();
|
|
||||||
hasValue_ = other.hasValue_;
|
|
||||||
if (!hasValue_) {
|
|
||||||
new (&storage_.error) E(std::move(other.storage_.error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result<void, E> ok() {
|
|
||||||
return Result<void, E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result<void, E> err(E error) {
|
|
||||||
Result<void, E> result;
|
|
||||||
result.hasValue_ = false;
|
|
||||||
new (&result.storage_.error) E(std::move(error));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok() const { return hasValue_; }
|
|
||||||
bool isOk() const { return hasValue_; }
|
|
||||||
bool isErr() const { return !hasValue_; }
|
|
||||||
|
|
||||||
E& error() & {
|
|
||||||
return storage_.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const E& error() const & {
|
|
||||||
return storage_.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
E&& error() && {
|
|
||||||
return std::move(storage_.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
union Storage {
|
|
||||||
E error;
|
|
||||||
|
|
||||||
Storage() {}
|
|
||||||
~Storage() {}
|
|
||||||
} storage_;
|
|
||||||
|
|
||||||
bool hasValue_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 便捷宏
|
|
||||||
#define E2D_TRY(result) \
|
|
||||||
do { \
|
|
||||||
auto _res = (result); \
|
|
||||||
if (!_res.ok()) { \
|
|
||||||
return Result<decltype(_res)::ValueType, decltype(_res)::ErrorType>::err(_res.error()); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -48,6 +50,7 @@ struct ServiceInfo {
|
||||||
*/
|
*/
|
||||||
class IService {
|
class IService {
|
||||||
friend class ServiceLocator;
|
friend class ServiceLocator;
|
||||||
|
friend class Lifecycle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~IService() = default;
|
virtual ~IService() = default;
|
||||||
|
|
@ -69,6 +72,18 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void shutdown() = 0;
|
virtual void shutdown() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务依赖列表
|
||||||
|
* @return 依赖服务类型列表
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::type_index> deps() const { return {}; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块依赖列表
|
||||||
|
* @return 依赖模块类型列表
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::type_index> needsModules() const { return {}; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 暂停服务
|
* @brief 暂停服务
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,307 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <extra2d/core/service_interface.h>
|
|
||||||
#include <extra2d/core/types.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <shared_mutex>
|
|
||||||
#include <typeindex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务工厂函数类型
|
|
||||||
*/
|
|
||||||
template <typename T> using ServiceFactory = Fn<Ref<T>()>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务定位器
|
|
||||||
* 实现依赖注入和服务发现模式,解耦模块间依赖
|
|
||||||
*
|
|
||||||
* 特性:
|
|
||||||
* - 类型安全的服务注册和获取
|
|
||||||
* - 支持服务工厂延迟创建
|
|
||||||
* - 支持服务依赖声明
|
|
||||||
* - 线程安全(读写锁)
|
|
||||||
* - 支持 Mock 测试
|
|
||||||
*/
|
|
||||||
class ServiceLocator {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief 获取单例实例
|
|
||||||
* @return 服务定位器实例引用
|
|
||||||
*/
|
|
||||||
static ServiceLocator &instance();
|
|
||||||
|
|
||||||
ServiceLocator(const ServiceLocator &) = delete;
|
|
||||||
ServiceLocator &operator=(const ServiceLocator &) = delete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注册服务实例
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @param svc 服务实例
|
|
||||||
*/
|
|
||||||
template <typename T> void add(Ref<T> svc) {
|
|
||||||
static_assert(std::is_base_of_v<IService, T>,
|
|
||||||
"T must derive from IService");
|
|
||||||
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
auto typeId = std::type_index(typeid(T));
|
|
||||||
services_[typeId] = std::static_pointer_cast<IService>(svc);
|
|
||||||
orderedServices_.push_back(svc);
|
|
||||||
sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注册服务工厂
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @param fn 服务工厂函数
|
|
||||||
*/
|
|
||||||
template <typename T> void setFactory(ServiceFactory<T> fn) {
|
|
||||||
static_assert(std::is_base_of_v<IService, T>,
|
|
||||||
"T must derive from IService");
|
|
||||||
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
auto typeId = std::type_index(typeid(T));
|
|
||||||
factories_[typeId] = [fn]() -> Ref<IService> {
|
|
||||||
return std::static_pointer_cast<IService>(fn());
|
|
||||||
};
|
|
||||||
|
|
||||||
// 立即创建服务实例并添加到有序列表
|
|
||||||
auto svc = factories_[typeId]();
|
|
||||||
services_[typeId] = svc;
|
|
||||||
orderedServices_.push_back(svc);
|
|
||||||
sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取服务实例
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @return 服务实例,不存在返回 nullptr
|
|
||||||
*/
|
|
||||||
template <typename T> Ref<T> get() const {
|
|
||||||
static_assert(std::is_base_of_v<IService, T>,
|
|
||||||
"T must derive from IService");
|
|
||||||
|
|
||||||
auto typeId = std::type_index(typeid(T));
|
|
||||||
|
|
||||||
// 读锁查询
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
auto it = services_.find(typeId);
|
|
||||||
if (it != services_.end()) {
|
|
||||||
return std::static_pointer_cast<T>(it->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto factoryIt = factories_.find(typeId);
|
|
||||||
if (factoryIt != factories_.end()) {
|
|
||||||
auto svc = factoryIt->second();
|
|
||||||
services_[typeId] = svc;
|
|
||||||
return std::static_pointer_cast<T>(svc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 尝试获取服务实例(不创建)
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @return 服务实例,不存在返回 nullptr
|
|
||||||
*/
|
|
||||||
template <typename T> Ref<T> tryGet() const {
|
|
||||||
static_assert(std::is_base_of_v<IService, T>,
|
|
||||||
"T must derive from IService");
|
|
||||||
|
|
||||||
auto typeId = std::type_index(typeid(T));
|
|
||||||
|
|
||||||
// 读锁查询
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
auto it = services_.find(typeId);
|
|
||||||
if (it != services_.end()) {
|
|
||||||
return std::static_pointer_cast<T>(it->second);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 检查服务是否已注册
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @return 已注册返回 true
|
|
||||||
*/
|
|
||||||
template <typename T> bool has() const {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
auto typeId = std::type_index(typeid(T));
|
|
||||||
return services_.find(typeId) != services_.end() ||
|
|
||||||
factories_.find(typeId) != factories_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注销服务
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
*/
|
|
||||||
template <typename T> void remove() {
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
auto typeId = std::type_index(typeid(T));
|
|
||||||
|
|
||||||
auto it = services_.find(typeId);
|
|
||||||
if (it != services_.end()) {
|
|
||||||
auto svc = it->second;
|
|
||||||
services_.erase(it);
|
|
||||||
|
|
||||||
auto orderIt =
|
|
||||||
std::find(orderedServices_.begin(), orderedServices_.end(), svc);
|
|
||||||
if (orderIt != orderedServices_.end()) {
|
|
||||||
orderedServices_.erase(orderIt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
factories_.erase(typeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化所有已注册的服务
|
|
||||||
* @return 所有服务初始化成功返回 true
|
|
||||||
*/
|
|
||||||
bool init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 关闭所有服务
|
|
||||||
*/
|
|
||||||
void shutdown();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 更新所有服务
|
|
||||||
* @param dt 帧间隔时间
|
|
||||||
*/
|
|
||||||
void update(f32 dt);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 暂停所有服务
|
|
||||||
*/
|
|
||||||
void pause();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 恢复所有服务
|
|
||||||
*/
|
|
||||||
void resume();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取所有服务(按优先级排序)
|
|
||||||
* @return 服务列表
|
|
||||||
*/
|
|
||||||
std::vector<Ref<IService>> all() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 清空所有服务和工厂
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取已注册服务数量
|
|
||||||
* @return 服务数量
|
|
||||||
*/
|
|
||||||
size_t size() const { return services_.size(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
ServiceLocator() = default;
|
|
||||||
~ServiceLocator() = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 按优先级排序服务
|
|
||||||
*/
|
|
||||||
void sort();
|
|
||||||
|
|
||||||
mutable std::unordered_map<std::type_index, Ref<IService>> services_;
|
|
||||||
std::unordered_map<std::type_index, std::function<Ref<IService>()>>
|
|
||||||
factories_;
|
|
||||||
std::vector<Ref<IService>> orderedServices_;
|
|
||||||
mutable std::shared_mutex mutex_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务注册器
|
|
||||||
* 用于静态注册服务
|
|
||||||
*/
|
|
||||||
template <typename Interface, typename Implementation> class ServiceRegistrar {
|
|
||||||
public:
|
|
||||||
explicit ServiceRegistrar(ServiceFactory<Interface> fn = nullptr) {
|
|
||||||
if (fn) {
|
|
||||||
ServiceLocator::instance().setFactory<Interface>(fn);
|
|
||||||
} else {
|
|
||||||
ServiceLocator::instance().setFactory<Interface>(
|
|
||||||
[]() -> Ref<Interface> {
|
|
||||||
return ptr::make<Implementation>();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务注册元数据模板
|
|
||||||
* 使用模板元编程实现编译期服务注册
|
|
||||||
* 通过静态成员变量的初始化触发注册
|
|
||||||
*/
|
|
||||||
template <typename Interface, typename Implementation> struct ServiceAutoReg {
|
|
||||||
/**
|
|
||||||
* @brief 注册标记,访问此变量时触发服务注册
|
|
||||||
*/
|
|
||||||
static const bool registered;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行实际的服务注册
|
|
||||||
* @return true 表示注册成功
|
|
||||||
*/
|
|
||||||
static bool doRegister() {
|
|
||||||
::extra2d::ServiceLocator::instance().setFactory<Interface>(
|
|
||||||
[]() -> ::extra2d::Ref<Interface> {
|
|
||||||
return ::extra2d::ptr::make<Implementation>();
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 静态成员定义,在此处触发注册
|
|
||||||
template <typename Interface, typename Implementation>
|
|
||||||
const bool ServiceAutoReg<Interface, Implementation>::registered =
|
|
||||||
ServiceAutoReg<Interface, Implementation>::doRegister();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务注册元数据(带自定义工厂)
|
|
||||||
*/
|
|
||||||
template <typename Interface> struct ServiceAutoRegFactory {
|
|
||||||
template <typename Factory> struct Impl {
|
|
||||||
static const bool registered;
|
|
||||||
|
|
||||||
static bool doRegister(Factory fn) {
|
|
||||||
::extra2d::ServiceLocator::instance().setFactory<Interface>(fn);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Interface>
|
|
||||||
template <typename Factory>
|
|
||||||
const bool ServiceAutoRegFactory<Interface>::Impl<Factory>::registered =
|
|
||||||
ServiceAutoRegFactory<Interface>::Impl<Factory>::doRegister(Factory{});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 自动注册服务宏(元数据驱动)
|
|
||||||
* 在服务实现类中使用,通过模板元编程实现自动注册
|
|
||||||
* 比静态对象更可靠,不易被编译器优化
|
|
||||||
*/
|
|
||||||
#define E2D_AUTO_REGISTER_SERVICE(Interface, Implementation) \
|
|
||||||
static inline const bool E2D_CONCAT(_service_reg_, __LINE__) = \
|
|
||||||
ServiceAutoReg<Interface, Implementation>::registered
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 带自定义工厂的自动注册服务宏(元数据驱动)
|
|
||||||
*/
|
|
||||||
#define E2D_AUTO_REGISTER_SERVICE_FACTORY(Interface, Factory) \
|
|
||||||
static inline const bool E2D_CONCAT(_service_factory_reg_, __LINE__) = \
|
|
||||||
ServiceAutoRegFactory<Interface>::Impl<Factory>::registered
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <extra2d/core/service_interface.h>
|
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务注册信息
|
|
||||||
*/
|
|
||||||
struct ServiceRegistration {
|
|
||||||
std::string name;
|
|
||||||
ServicePriority priority;
|
|
||||||
std::function<Ref<IService>()> factory;
|
|
||||||
bool enabled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 服务注册表
|
|
||||||
* 管理服务的注册信息,支持延迟创建和配置
|
|
||||||
*/
|
|
||||||
class ServiceRegistry {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief 获取单例实例
|
|
||||||
* @return 服务注册表实例引用
|
|
||||||
*/
|
|
||||||
static ServiceRegistry& instance();
|
|
||||||
|
|
||||||
ServiceRegistry(const ServiceRegistry&) = delete;
|
|
||||||
ServiceRegistry& operator=(const ServiceRegistry&) = delete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注册服务
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @tparam Impl 服务实现类型
|
|
||||||
* @param name 服务名称
|
|
||||||
* @param priority 服务优先级
|
|
||||||
*/
|
|
||||||
template<typename T, typename Impl>
|
|
||||||
void add(const std::string& name, ServicePriority priority) {
|
|
||||||
static_assert(std::is_base_of_v<IService, T>,
|
|
||||||
"T must derive from IService");
|
|
||||||
static_assert(std::is_base_of_v<T, Impl>,
|
|
||||||
"Impl must derive from T");
|
|
||||||
|
|
||||||
ServiceRegistration reg;
|
|
||||||
reg.name = name;
|
|
||||||
reg.priority = priority;
|
|
||||||
reg.factory = []() -> Ref<IService> {
|
|
||||||
return std::static_pointer_cast<IService>(ptr::make<Impl>());
|
|
||||||
};
|
|
||||||
registrations_.push_back(reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 注册服务(带工厂函数)
|
|
||||||
* @tparam T 服务接口类型
|
|
||||||
* @param name 服务名称
|
|
||||||
* @param priority 服务优先级
|
|
||||||
* @param factory 工厂函数
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
void addWithFactory(
|
|
||||||
const std::string& name,
|
|
||||||
ServicePriority priority,
|
|
||||||
std::function<Ref<T>()> factory) {
|
|
||||||
static_assert(std::is_base_of_v<IService, T>,
|
|
||||||
"T must derive from IService");
|
|
||||||
|
|
||||||
ServiceRegistration reg;
|
|
||||||
reg.name = name;
|
|
||||||
reg.priority = priority;
|
|
||||||
reg.factory = [factory]() -> Ref<IService> {
|
|
||||||
return std::static_pointer_cast<IService>(factory());
|
|
||||||
};
|
|
||||||
registrations_.push_back(reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 启用/禁用服务
|
|
||||||
* @param name 服务名称
|
|
||||||
* @param enabled 是否启用
|
|
||||||
*/
|
|
||||||
void setEnabled(const std::string& name, bool enabled);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 创建所有已注册的服务
|
|
||||||
* 并注册到 ServiceLocator
|
|
||||||
*/
|
|
||||||
void createAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取所有注册信息
|
|
||||||
* @return 注册信息列表
|
|
||||||
*/
|
|
||||||
const std::vector<ServiceRegistration>& all() const {
|
|
||||||
return registrations_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 清空所有注册
|
|
||||||
*/
|
|
||||||
void clear() {
|
|
||||||
registrations_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ServiceRegistry() = default;
|
|
||||||
~ServiceRegistry() = default;
|
|
||||||
|
|
||||||
std::vector<ServiceRegistration> registrations_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 自动服务注册器
|
|
||||||
* 在全局作用域使用,自动注册服务
|
|
||||||
*/
|
|
||||||
template<typename Interface, typename Implementation>
|
|
||||||
class AutoServiceRegistrar {
|
|
||||||
public:
|
|
||||||
AutoServiceRegistrar(const std::string& name, ServicePriority priority) {
|
|
||||||
ServiceRegistry::instance().add<Interface, Implementation>(
|
|
||||||
name, priority);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#define E2D_REGISTER_SERVICE_AUTO(Interface, Implementation, Name, Priority) \
|
|
||||||
namespace { \
|
|
||||||
static ::extra2d::AutoServiceRegistrar<Interface, Implementation> \
|
|
||||||
E2D_CONCAT(auto_service_registrar_, __LINE__)(Name, Priority); \
|
|
||||||
}
|
|
||||||
|
|
@ -5,14 +5,15 @@
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
#include <extra2d/core/color.h>
|
#include <extra2d/core/color.h>
|
||||||
|
#include <extra2d/core/lifecycle.h>
|
||||||
#include <extra2d/core/math_types.h>
|
#include <extra2d/core/math_types.h>
|
||||||
#include <extra2d/core/module.h>
|
#include <extra2d/core/module.h>
|
||||||
#include <extra2d/core/registry.h>
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
#include <extra2d/window/keys.h>
|
#include <extra2d/window/keys.h>
|
||||||
#include <extra2d/window/window.h>
|
#include <extra2d/window/window.h>
|
||||||
|
#include <extra2d/window/window_module.h>
|
||||||
#include <extra2d/window/event_converter.h>
|
#include <extra2d/window/event_converter.h>
|
||||||
|
|
||||||
// Window - SDL2 + OpenGL
|
// Window - SDL2 + OpenGL
|
||||||
|
|
@ -21,6 +22,7 @@
|
||||||
#include <extra2d/render/buffer.h>
|
#include <extra2d/render/buffer.h>
|
||||||
#include <extra2d/render/render_context.h>
|
#include <extra2d/render/render_context.h>
|
||||||
#include <extra2d/render/render_device.h>
|
#include <extra2d/render/render_device.h>
|
||||||
|
#include <extra2d/render/render_module.h>
|
||||||
#include <extra2d/render/render_queue.h>
|
#include <extra2d/render/render_queue.h>
|
||||||
#include <extra2d/render/render_stats.h>
|
#include <extra2d/render/render_stats.h>
|
||||||
#include <extra2d/render/render_types.h>
|
#include <extra2d/render/render_types.h>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/core/module.h>
|
||||||
|
#include <extra2d/render/render_device.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
|
#include <extra2d/window/window_module.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 渲染模块配置结构
|
||||||
|
*/
|
||||||
|
struct RenderCfg {
|
||||||
|
int glMajor = 4;
|
||||||
|
int glMinor = 5;
|
||||||
|
bool useES = false;
|
||||||
|
int redBits = 8;
|
||||||
|
int greenBits = 8;
|
||||||
|
int blueBits = 8;
|
||||||
|
int alphaBits = 8;
|
||||||
|
int depthBits = 24;
|
||||||
|
int stencilBits = 8;
|
||||||
|
bool doubleBuffer = true;
|
||||||
|
int msaaSamples = 0;
|
||||||
|
bool vsync = true;
|
||||||
|
int priority = 10;
|
||||||
|
|
||||||
|
RenderCfg() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 渲染模块
|
||||||
|
* 管理 OpenGL 渲染设备和上下文
|
||||||
|
*/
|
||||||
|
class RenderModule : public Module {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 构造函数(Lambda 配置)
|
||||||
|
* @param configFn 配置函数
|
||||||
|
*/
|
||||||
|
explicit RenderModule(std::function<void(RenderCfg &)> configFn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 析构函数
|
||||||
|
*/
|
||||||
|
~RenderModule() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化渲染模块
|
||||||
|
* @return 初始化成功返回 true
|
||||||
|
*/
|
||||||
|
bool init() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭渲染模块
|
||||||
|
*/
|
||||||
|
void shutdown() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查模块是否已初始化
|
||||||
|
* @return 已初始化返回 true
|
||||||
|
*/
|
||||||
|
bool ok() const override { return initialized_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块名称
|
||||||
|
* @return 模块名称
|
||||||
|
*/
|
||||||
|
const char *name() const override { return "RenderModule"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块优先级
|
||||||
|
* @return 优先级值(渲染模块在窗口模块之后初始化)
|
||||||
|
*/
|
||||||
|
int priority() const override { return cfg_.priority; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块依赖
|
||||||
|
* @return 依赖 WindowModule
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> deps() const override {
|
||||||
|
return {std::type_index(typeid(WindowModule))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务依赖
|
||||||
|
* @return 依赖 ILogger
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> needsServices() const override {
|
||||||
|
return {std::type_index(typeid(ILogger))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 渲染模块不支持并行初始化(OpenGL 上下文需要串行创建)
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
bool parallel() const override { return false; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 交换缓冲区
|
||||||
|
*/
|
||||||
|
void swapBuffers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置 VSync
|
||||||
|
* @param enabled 是否启用
|
||||||
|
*/
|
||||||
|
void setVSync(bool enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取渲染设备
|
||||||
|
* @return 渲染设备引用
|
||||||
|
*/
|
||||||
|
RenderDevice &device() { return RenderDevice::instance(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取渲染能力信息
|
||||||
|
* @return 渲染能力信息
|
||||||
|
*/
|
||||||
|
const RenderCaps &caps() const { return RenderDevice::instance().caps(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RenderCfg cfg_;
|
||||||
|
bool initialized_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -9,8 +9,8 @@
|
||||||
#include <extra2d/asset/asset_types.h>
|
#include <extra2d/asset/asset_types.h>
|
||||||
#include <extra2d/asset/data_processor.h>
|
#include <extra2d/asset/data_processor.h>
|
||||||
#include <extra2d/core/service_interface.h>
|
#include <extra2d/core/service_interface.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -232,6 +232,13 @@ public:
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 资源服务依赖日志服务
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> deps() const override {
|
||||||
|
return { std::type_index(typeid(ILogger)) };
|
||||||
|
}
|
||||||
|
|
||||||
bool init() override;
|
bool init() override;
|
||||||
void shutdown() override;
|
void shutdown() override;
|
||||||
|
|
||||||
|
|
@ -327,8 +334,6 @@ private:
|
||||||
* @return 资源类型索引
|
* @return 资源类型索引
|
||||||
*/
|
*/
|
||||||
std::type_index inferType(const std::string &path);
|
std::type_index inferType(const std::string &path);
|
||||||
|
|
||||||
E2D_AUTO_REGISTER_SERVICE(IAssetService, AssetService);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/core/service_interface.h>
|
#include <extra2d/core/service_interface.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/event/event_dispatcher.h>
|
#include <extra2d/event/event_dispatcher.h>
|
||||||
#include <extra2d/event/event_queue.h>
|
#include <extra2d/event/event_queue.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
|
#include <extra2d/window/window_module.h>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -14,16 +18,16 @@ class IEventService : public IService {
|
||||||
public:
|
public:
|
||||||
virtual ~IEventService() = default;
|
virtual ~IEventService() = default;
|
||||||
|
|
||||||
virtual void push(const Event& event) = 0;
|
virtual void push(const Event &event) = 0;
|
||||||
virtual void push(Event&& event) = 0;
|
virtual void push(Event &&event) = 0;
|
||||||
virtual bool poll(Event& event) = 0;
|
virtual bool poll(Event &event) = 0;
|
||||||
|
|
||||||
virtual ListenerID on(EventType type, EventDispatcher::EventFn fn) = 0;
|
virtual ListenerID on(EventType type, EventDispatcher::EventFn fn) = 0;
|
||||||
virtual void off(ListenerID id) = 0;
|
virtual void off(ListenerID id) = 0;
|
||||||
virtual void offAll(EventType type) = 0;
|
virtual void offAll(EventType type) = 0;
|
||||||
virtual void offAll() = 0;
|
virtual void offAll() = 0;
|
||||||
|
|
||||||
virtual void dispatch(Event& event) = 0;
|
virtual void dispatch(Event &event) = 0;
|
||||||
virtual void process() = 0;
|
virtual void process() = 0;
|
||||||
|
|
||||||
virtual size_t listenerCount(EventType type) const = 0;
|
virtual size_t listenerCount(EventType type) const = 0;
|
||||||
|
|
@ -41,37 +45,48 @@ public:
|
||||||
|
|
||||||
ServiceInfo info() const override;
|
ServiceInfo info() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 事件服务依赖日志服务
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> deps() const override {
|
||||||
|
return {std::type_index(typeid(ILogger))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 事件服务依赖窗口模块
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> needsModules() const override {
|
||||||
|
return {std::type_index(typeid(WindowModule))};
|
||||||
|
}
|
||||||
|
|
||||||
bool init() override;
|
bool init() override;
|
||||||
void shutdown() override;
|
void shutdown() override;
|
||||||
void update(f32 dt) override;
|
void update(f32 dt) override;
|
||||||
|
|
||||||
void push(const Event& event) override;
|
void push(const Event &event) override;
|
||||||
void push(Event&& event) override;
|
void push(Event &&event) override;
|
||||||
bool poll(Event& event) override;
|
bool poll(Event &event) override;
|
||||||
|
|
||||||
ListenerID on(EventType type, EventDispatcher::EventFn fn) override;
|
ListenerID on(EventType type, EventDispatcher::EventFn fn) override;
|
||||||
void off(ListenerID id) override;
|
void off(ListenerID id) override;
|
||||||
void offAll(EventType type) override;
|
void offAll(EventType type) override;
|
||||||
void offAll() override;
|
void offAll() override;
|
||||||
|
|
||||||
void dispatch(Event& event) override;
|
void dispatch(Event &event) override;
|
||||||
void process() override;
|
void process() override;
|
||||||
|
|
||||||
size_t listenerCount(EventType type) const override;
|
size_t listenerCount(EventType type) const override;
|
||||||
size_t totalListeners() const override;
|
size_t totalListeners() const override;
|
||||||
size_t queueSize() const override;
|
size_t queueSize() const override;
|
||||||
|
|
||||||
EventQueue& queue() { return queue_; }
|
EventQueue &queue() { return queue_; }
|
||||||
const EventQueue& queue() const { return queue_; }
|
const EventQueue &queue() const { return queue_; }
|
||||||
EventDispatcher& dispatcher() { return dispatcher_; }
|
EventDispatcher &dispatcher() { return dispatcher_; }
|
||||||
const EventDispatcher& dispatcher() const { return dispatcher_; }
|
const EventDispatcher &dispatcher() const { return dispatcher_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventQueue queue_;
|
EventQueue queue_;
|
||||||
EventDispatcher dispatcher_;
|
EventDispatcher dispatcher_;
|
||||||
|
|
||||||
// 服务注册元数据
|
|
||||||
E2D_AUTO_REGISTER_SERVICE(IEventService, EventService);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/core/lifecycle.h>
|
||||||
#include <extra2d/core/service_interface.h>
|
#include <extra2d/core/service_interface.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
@ -74,6 +74,11 @@ public:
|
||||||
i.priority = ServicePriority::Core;
|
i.priority = ServicePriority::Core;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 日志服务无依赖
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> deps() const override { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -117,8 +122,6 @@ private:
|
||||||
LogColor levelColors_[7];
|
LogColor levelColors_[7];
|
||||||
class Impl;
|
class Impl;
|
||||||
Unique<Impl> impl_;
|
Unique<Impl> impl_;
|
||||||
|
|
||||||
E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
@ -173,16 +176,16 @@ inline std::string format_str(const char *fmt) { return fmt; }
|
||||||
// 日志宏
|
// 日志宏
|
||||||
#define E2D_LOG(lvl, ...) \
|
#define E2D_LOG(lvl, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (auto log = ::extra2d::ServiceLocator::instance() \
|
if (auto log = \
|
||||||
.tryGet<::extra2d::ILogger>()) \
|
::extra2d::Lifecycle::instance().service<::extra2d::ILogger>()) \
|
||||||
if (log->enabled(lvl)) \
|
if (log->enabled(lvl)) \
|
||||||
log->log(lvl, ::extra2d::format_str(__VA_ARGS__)); \
|
log->log(lvl, ::extra2d::format_str(__VA_ARGS__)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define E2D_LOG_CAT(lvl, cat, ...) \
|
#define E2D_LOG_CAT(lvl, cat, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (auto log = ::extra2d::ServiceLocator::instance() \
|
if (auto log = \
|
||||||
.tryGet<::extra2d::ILogger>()) \
|
::extra2d::Lifecycle::instance().service<::extra2d::ILogger>()) \
|
||||||
if (log->enabled(lvl)) { \
|
if (log->enabled(lvl)) { \
|
||||||
std::string _e2d_msg = ::extra2d::format_str(__VA_ARGS__); \
|
std::string _e2d_msg = ::extra2d::format_str(__VA_ARGS__); \
|
||||||
log->log(lvl, ::extra2d::format_str("[{}] {}", cat, _e2d_msg)); \
|
log->log(lvl, ::extra2d::format_str("[{}] {}", cat, _e2d_msg)); \
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/core/service_interface.h>
|
#include <extra2d/core/service_interface.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/types.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
#include <extra2d/utils/timer.h>
|
#include <extra2d/utils/timer.h>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -32,6 +35,13 @@ public:
|
||||||
|
|
||||||
ServiceInfo info() const override;
|
ServiceInfo info() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 计时器服务依赖日志服务
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> deps() const override {
|
||||||
|
return { std::type_index(typeid(ILogger)) };
|
||||||
|
}
|
||||||
|
|
||||||
bool init() override;
|
bool init() override;
|
||||||
void shutdown() override;
|
void shutdown() override;
|
||||||
void update(f32 dt) override;
|
void update(f32 dt) override;
|
||||||
|
|
@ -49,9 +59,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TimerManager mgr_;
|
TimerManager mgr_;
|
||||||
|
|
||||||
// 服务注册元数据
|
|
||||||
E2D_AUTO_REGISTER_SERVICE(ITimerService, TimerService);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 窗口配置结构体
|
||||||
|
*/
|
||||||
struct WindowConfig {
|
struct WindowConfig {
|
||||||
std::string title = "Extra2D Application";
|
std::string title = "Extra2D Application";
|
||||||
int width = 1280;
|
int width = 1280;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <extra2d/core/module.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
|
#include <extra2d/window/window.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 窗口模块配置结构
|
||||||
|
*/
|
||||||
|
struct WindowCfg {
|
||||||
|
std::string title = "Extra2D";
|
||||||
|
int width = 1280;
|
||||||
|
int height = 720;
|
||||||
|
bool fullscreen = false;
|
||||||
|
bool resizable = true;
|
||||||
|
bool centerWindow = true;
|
||||||
|
int priority = 0;
|
||||||
|
|
||||||
|
WindowCfg() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 窗口模块
|
||||||
|
* 管理窗口创建和生命周期
|
||||||
|
*/
|
||||||
|
class WindowModule : public Module {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 构造函数(Lambda 配置)
|
||||||
|
* @param configFn 配置函数
|
||||||
|
*/
|
||||||
|
explicit WindowModule(std::function<void(WindowCfg &)> configFn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 析构函数
|
||||||
|
*/
|
||||||
|
~WindowModule() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化窗口模块
|
||||||
|
* @return 初始化成功返回 true
|
||||||
|
*/
|
||||||
|
bool init() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭窗口模块
|
||||||
|
*/
|
||||||
|
void shutdown() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查模块是否已初始化
|
||||||
|
* @return 已初始化返回 true
|
||||||
|
*/
|
||||||
|
bool ok() const override { return initialized_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块名称
|
||||||
|
* @return 模块名称
|
||||||
|
*/
|
||||||
|
const char *name() const override { return "WindowModule"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取模块优先级
|
||||||
|
* @return 优先级值
|
||||||
|
*/
|
||||||
|
int priority() const override { return cfg_.priority; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取服务依赖
|
||||||
|
* @return 依赖 ILogger
|
||||||
|
*/
|
||||||
|
std::vector<std::type_index> needsServices() const override {
|
||||||
|
return {std::type_index(typeid(ILogger))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 窗口模块不支持并行初始化(SDL 窗口创建需要串行)
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
bool parallel() const override { return false; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 轮询窗口事件
|
||||||
|
*/
|
||||||
|
void poll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查窗口是否应该关闭
|
||||||
|
* @return 应该关闭返回 true
|
||||||
|
*/
|
||||||
|
bool shouldClose() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭窗口
|
||||||
|
*/
|
||||||
|
void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置窗口标题
|
||||||
|
* @param title 窗口标题
|
||||||
|
*/
|
||||||
|
void setTitle(const std::string &title);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置窗口大小
|
||||||
|
* @param width 窗口宽度
|
||||||
|
* @param height 窗口高度
|
||||||
|
*/
|
||||||
|
void setSize(int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置全屏模式
|
||||||
|
* @param fullscreen 是否全屏
|
||||||
|
*/
|
||||||
|
void setFullscreen(bool fullscreen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取窗口宽度
|
||||||
|
* @return 窗口宽度
|
||||||
|
*/
|
||||||
|
int width() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取窗口高度
|
||||||
|
* @return 窗口高度
|
||||||
|
*/
|
||||||
|
int height() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查是否全屏
|
||||||
|
* @return 全屏返回 true
|
||||||
|
*/
|
||||||
|
bool fullscreen() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置事件回调
|
||||||
|
* @param cb 事件回调函数
|
||||||
|
*/
|
||||||
|
void onEvent(std::function<void(const SDL_Event &)> cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取原生窗口指针
|
||||||
|
* @return SDL 窗口指针
|
||||||
|
*/
|
||||||
|
SDL_Window *native() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取内部窗口对象
|
||||||
|
* @return 窗口对象指针
|
||||||
|
*/
|
||||||
|
Window *win() const { return window_.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
WindowCfg cfg_;
|
||||||
|
Unique<Window> window_;
|
||||||
|
bool initialized_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/render/render_device.h>
|
#include <extra2d/core/lifecycle.h>
|
||||||
|
#include <extra2d/render/render_module.h>
|
||||||
#include <extra2d/services/event_service.h>
|
#include <extra2d/services/event_service.h>
|
||||||
#include <extra2d/services/logger_service.h>
|
#include <extra2d/services/logger_service.h>
|
||||||
#include <extra2d/window/event_converter.h>
|
#include <extra2d/window/event_converter.h>
|
||||||
#include <extra2d/window/window.h>
|
#include <extra2d/window/window_module.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
Application::Application() { Lifecycle::instance().setApp(this); }
|
||||||
|
|
||||||
Application &Application::instance() {
|
Application &Application::instance() {
|
||||||
static Application app;
|
static Application app;
|
||||||
return app;
|
return app;
|
||||||
|
|
@ -20,37 +23,24 @@ bool Application::init() {
|
||||||
if (initialized_)
|
if (initialized_)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// 先初始化服务定位器(包括日志服务)
|
|
||||||
ServiceLocator::instance().init();
|
|
||||||
|
|
||||||
E2D_INFO(CAT_APP, "应用程序初始化中:{}", name);
|
E2D_INFO(CAT_APP, "应用程序初始化中:{}", name);
|
||||||
|
|
||||||
window_ = new Window();
|
if (!Lifecycle::instance().init()) {
|
||||||
if (!window_->create({.title = name, .width = 1280, .height = 720})) {
|
E2D_ERROR(CAT_APP, "初始化失败");
|
||||||
E2D_ERROR(CAT_APP, "创建窗口失败");
|
|
||||||
delete window_;
|
|
||||||
window_ = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置事件回调,将 SDL 事件转换为 Extra2D 事件
|
auto *winMod = module<WindowModule>();
|
||||||
window_->onEvent([](const SDL_Event &e) {
|
if (winMod && winMod->win()) {
|
||||||
|
winMod->onEvent([](const SDL_Event &e) {
|
||||||
Event event = EventConverter::convert(e);
|
Event event = EventConverter::convert(e);
|
||||||
if (event.type != EventType::None) {
|
if (event.type != EventType::None) {
|
||||||
auto eventService = ServiceLocator::instance().get<IEventService>();
|
auto eventService = Lifecycle::instance().service<IEventService>();
|
||||||
if (eventService) {
|
if (eventService) {
|
||||||
eventService->push(event);
|
eventService->push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
auto &device = RenderDevice::instance();
|
|
||||||
if (!device.init(window_->native())) {
|
|
||||||
E2D_ERROR(CAT_APP, "渲染设备初始化失败");
|
|
||||||
window_->destroy();
|
|
||||||
delete window_;
|
|
||||||
window_ = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
|
|
@ -67,15 +57,7 @@ void Application::shutdown() {
|
||||||
|
|
||||||
E2D_INFO(CAT_APP, "应用程序正在关闭");
|
E2D_INFO(CAT_APP, "应用程序正在关闭");
|
||||||
|
|
||||||
RenderDevice::instance().shutdown();
|
Lifecycle::instance().clear();
|
||||||
|
|
||||||
if (window_) {
|
|
||||||
window_->destroy();
|
|
||||||
delete window_;
|
|
||||||
window_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceLocator::instance().shutdown();
|
|
||||||
|
|
||||||
initialized_ = false;
|
initialized_ = false;
|
||||||
running_ = false;
|
running_ = false;
|
||||||
|
|
@ -85,13 +67,19 @@ void Application::run() {
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (running_ && !window_->shouldClose()) {
|
auto *winMod = module<WindowModule>();
|
||||||
|
if (!winMod || !winMod->win())
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (running_ && !winMod->shouldClose()) {
|
||||||
mainLoop();
|
mainLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::quit() { running_ = false; }
|
void Application::quit() { running_ = false; }
|
||||||
|
|
||||||
|
WindowModule *Application::windowModule() const { return module<WindowModule>(); }
|
||||||
|
|
||||||
void Application::mainLoop() {
|
void Application::mainLoop() {
|
||||||
u64 currentTime = SDL_GetPerformanceCounter();
|
u64 currentTime = SDL_GetPerformanceCounter();
|
||||||
u64 frequency = SDL_GetPerformanceFrequency();
|
u64 frequency = SDL_GetPerformanceFrequency();
|
||||||
|
|
@ -109,9 +97,16 @@ void Application::mainLoop() {
|
||||||
fpsTimer_ -= 1.0f;
|
fpsTimer_ -= 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
window_->poll();
|
auto *winMod = module<WindowModule>();
|
||||||
ServiceLocator::instance().update(dt_);
|
if (winMod) {
|
||||||
RenderDevice::instance().swapBuffers();
|
winMod->poll();
|
||||||
|
}
|
||||||
|
Lifecycle::instance().update(dt_);
|
||||||
|
|
||||||
|
auto *renderMod = module<RenderModule>();
|
||||||
|
if (renderMod) {
|
||||||
|
renderMod->swapBuffers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,329 @@
|
||||||
|
#include <extra2d/core/lifecycle.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <future>
|
||||||
|
#include <iostream>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
Lifecycle& Lifecycle::instance() {
|
||||||
|
static Lifecycle instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Lifecycle::findModuleIndex(std::type_index type) const {
|
||||||
|
for (size_t i = 0; i < modules_.size(); ++i) {
|
||||||
|
if (modules_[i].module &&
|
||||||
|
std::type_index(typeid(*modules_[i].module)) == type) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Lifecycle::findServiceIndex(std::type_index type) const {
|
||||||
|
for (size_t i = 0; i < services_.size(); ++i) {
|
||||||
|
if (services_[i].id == type) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<Lifecycle::UnitIndex>> Lifecycle::groupByLevel() {
|
||||||
|
std::vector<std::vector<UnitIndex>> levels;
|
||||||
|
|
||||||
|
size_t totalUnits = modules_.size() + services_.size();
|
||||||
|
std::vector<int> inDegree(totalUnits, 0);
|
||||||
|
std::vector<std::vector<size_t>> adj(totalUnits);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < modules_.size(); ++i) {
|
||||||
|
if (!modules_[i].module) continue;
|
||||||
|
|
||||||
|
auto* mod = modules_[i].module.get();
|
||||||
|
|
||||||
|
for (auto& depType : mod->deps()) {
|
||||||
|
size_t depIdx = findModuleIndex(depType);
|
||||||
|
if (depIdx != SIZE_MAX) {
|
||||||
|
adj[depIdx].push_back(i);
|
||||||
|
inDegree[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& depType : mod->needsServices()) {
|
||||||
|
size_t depIdx = findServiceIndex(depType);
|
||||||
|
if (depIdx != SIZE_MAX) {
|
||||||
|
adj[modules_.size() + depIdx].push_back(i);
|
||||||
|
inDegree[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < services_.size(); ++i) {
|
||||||
|
if (!services_[i].service) continue;
|
||||||
|
|
||||||
|
auto* svc = services_[i].service.get();
|
||||||
|
|
||||||
|
for (auto& depType : svc->deps()) {
|
||||||
|
size_t depIdx = findServiceIndex(depType);
|
||||||
|
if (depIdx != SIZE_MAX) {
|
||||||
|
adj[modules_.size() + depIdx].push_back(modules_.size() + i);
|
||||||
|
inDegree[modules_.size() + i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& depType : svc->needsModules()) {
|
||||||
|
size_t depIdx = findModuleIndex(depType);
|
||||||
|
if (depIdx != SIZE_MAX) {
|
||||||
|
adj[depIdx].push_back(modules_.size() + i);
|
||||||
|
inDegree[modules_.size() + i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::queue<size_t> q;
|
||||||
|
std::vector<int> levelMap(totalUnits, -1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < totalUnits; ++i) {
|
||||||
|
if (inDegree[i] == 0) {
|
||||||
|
q.push(i);
|
||||||
|
levelMap[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!q.empty()) {
|
||||||
|
size_t curr = q.front();
|
||||||
|
q.pop();
|
||||||
|
|
||||||
|
int currLevel = levelMap[curr];
|
||||||
|
|
||||||
|
if (levels.size() <= static_cast<size_t>(currLevel)) {
|
||||||
|
levels.resize(currLevel + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitIndex ui;
|
||||||
|
if (curr < modules_.size()) {
|
||||||
|
ui.type = UnitType::Module;
|
||||||
|
ui.index = curr;
|
||||||
|
} else {
|
||||||
|
ui.type = UnitType::Service;
|
||||||
|
ui.index = curr - modules_.size();
|
||||||
|
}
|
||||||
|
levels[currLevel].push_back(ui);
|
||||||
|
|
||||||
|
for (size_t next : adj[curr]) {
|
||||||
|
inDegree[next]--;
|
||||||
|
if (inDegree[next] == 0) {
|
||||||
|
q.push(next);
|
||||||
|
levelMap[next] = currLevel + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lifecycle::init() {
|
||||||
|
auto levels = groupByLevel();
|
||||||
|
|
||||||
|
std::cout << "[INFO] [生命周期] 正在初始化 " << modules_.size() + services_.size()
|
||||||
|
<< " 个单元,共 " << levels.size() << " 个层级..." << std::endl;
|
||||||
|
|
||||||
|
for (size_t level = 0; level < levels.size(); ++level) {
|
||||||
|
auto& units = levels[level];
|
||||||
|
|
||||||
|
bool hasParallelUnits = false;
|
||||||
|
for (auto& ui : units) {
|
||||||
|
if (ui.type == UnitType::Module) {
|
||||||
|
if (modules_[ui.index].module &&
|
||||||
|
modules_[ui.index].module->parallel()) {
|
||||||
|
hasParallelUnits = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (units.size() <= 1 || !hasParallelUnits) {
|
||||||
|
for (auto& ui : units) {
|
||||||
|
if (ui.type == UnitType::Module) {
|
||||||
|
auto* mod = modules_[ui.index].module.get();
|
||||||
|
if (!mod) continue;
|
||||||
|
|
||||||
|
std::cout << "[INFO] [模块系统] 正在初始化模块: " << mod->name()
|
||||||
|
<< " (层级 " << level << ")" << std::endl;
|
||||||
|
|
||||||
|
if (!mod->init()) {
|
||||||
|
std::cerr << "[ERROR] [模块系统] 初始化模块失败: " << mod->name() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[INFO] [模块系统] 模块 " << mod->name() << " 初始化成功" << std::endl;
|
||||||
|
} else {
|
||||||
|
auto& svc = services_[ui.index].service;
|
||||||
|
if (!svc) continue;
|
||||||
|
|
||||||
|
auto info = svc->info();
|
||||||
|
if (!info.enabled) continue;
|
||||||
|
|
||||||
|
std::cout << "[INFO] [服务系统] 正在初始化服务: " << info.name
|
||||||
|
<< " (层级 " << level << ")" << std::endl;
|
||||||
|
|
||||||
|
svc->setState(ServiceState::Initializing);
|
||||||
|
if (!svc->init()) {
|
||||||
|
svc->setState(ServiceState::Stopped);
|
||||||
|
std::cerr << "[ERROR] [服务系统] 初始化服务失败: " << info.name << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
svc->setState(ServiceState::Running);
|
||||||
|
|
||||||
|
std::cout << "[INFO] [服务系统] 服务 " << info.name << " 初始化成功" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "[INFO] [生命周期] 正在并行初始化 " << units.size()
|
||||||
|
<< " 个单元 (层级 " << level << ")..." << std::endl;
|
||||||
|
|
||||||
|
std::vector<std::future<std::pair<UnitIndex, bool>>> futures;
|
||||||
|
std::vector<UnitIndex> serialUnits;
|
||||||
|
|
||||||
|
for (auto& ui : units) {
|
||||||
|
if (ui.type == UnitType::Module) {
|
||||||
|
auto* mod = modules_[ui.index].module.get();
|
||||||
|
if (!mod) continue;
|
||||||
|
|
||||||
|
if (mod->parallel()) {
|
||||||
|
futures.push_back(std::async(std::launch::async,
|
||||||
|
[this, ui, level]() -> std::pair<UnitIndex, bool> {
|
||||||
|
auto* m = modules_[ui.index].module.get();
|
||||||
|
std::cout << "[INFO] [模块系统] 正在初始化模块: " << m->name()
|
||||||
|
<< " (层级 " << level << ")" << std::endl;
|
||||||
|
bool success = m->init();
|
||||||
|
if (success) {
|
||||||
|
std::cout << "[INFO] [模块系统] 模块 " << m->name()
|
||||||
|
<< " 初始化成功 (并行)" << std::endl;
|
||||||
|
}
|
||||||
|
return {ui, success};
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
serialUnits.push_back(ui);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
serialUnits.push_back(ui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& future : futures) {
|
||||||
|
auto [ui, success] = future.get();
|
||||||
|
if (!success) {
|
||||||
|
if (ui.type == UnitType::Module) {
|
||||||
|
auto* mod = modules_[ui.index].module.get();
|
||||||
|
std::cerr << "[ERROR] [模块系统] 初始化模块失败: " << mod->name() << std::endl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& ui : serialUnits) {
|
||||||
|
if (ui.type == UnitType::Module) {
|
||||||
|
auto* mod = modules_[ui.index].module.get();
|
||||||
|
if (!mod) continue;
|
||||||
|
|
||||||
|
std::cout << "[INFO] [模块系统] 正在初始化模块: " << mod->name()
|
||||||
|
<< " (串行, 层级 " << level << ")" << std::endl;
|
||||||
|
|
||||||
|
if (!mod->init()) {
|
||||||
|
std::cerr << "[ERROR] [模块系统] 初始化模块失败: " << mod->name() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[INFO] [模块系统] 模块 " << mod->name() << " 初始化成功" << std::endl;
|
||||||
|
} else {
|
||||||
|
auto& svc = services_[ui.index].service;
|
||||||
|
if (!svc) continue;
|
||||||
|
|
||||||
|
auto info = svc->info();
|
||||||
|
if (!info.enabled) continue;
|
||||||
|
|
||||||
|
std::cout << "[INFO] [服务系统] 正在初始化服务: " << info.name
|
||||||
|
<< " (层级 " << level << ")" << std::endl;
|
||||||
|
|
||||||
|
svc->setState(ServiceState::Initializing);
|
||||||
|
if (!svc->init()) {
|
||||||
|
svc->setState(ServiceState::Stopped);
|
||||||
|
std::cerr << "[ERROR] [服务系统] 初始化服务失败: " << info.name << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
svc->setState(ServiceState::Running);
|
||||||
|
|
||||||
|
std::cout << "[INFO] [服务系统] 服务 " << info.name << " 初始化成功" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[INFO] [生命周期] 层级 " << level << " 初始化完成" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[INFO] [生命周期] 所有单元初始化完成" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lifecycle::update(f32 dt) {
|
||||||
|
for (auto& entry : services_) {
|
||||||
|
if (entry.service && entry.service->initialized()) {
|
||||||
|
auto state = entry.service->state();
|
||||||
|
if (state == ServiceState::Running) {
|
||||||
|
entry.service->update(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lifecycle::pause() {
|
||||||
|
for (auto& entry : services_) {
|
||||||
|
if (entry.service && entry.service->initialized()) {
|
||||||
|
entry.service->pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lifecycle::resume() {
|
||||||
|
for (auto& entry : services_) {
|
||||||
|
if (entry.service && entry.service->initialized()) {
|
||||||
|
entry.service->resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lifecycle::shutdown() {
|
||||||
|
auto levels = groupByLevel();
|
||||||
|
|
||||||
|
for (auto it = levels.rbegin(); it != levels.rend(); ++it) {
|
||||||
|
for (auto& ui : *it) {
|
||||||
|
if (ui.type == UnitType::Module) {
|
||||||
|
auto* mod = modules_[ui.index].module.get();
|
||||||
|
if (mod && mod->ok()) {
|
||||||
|
E2D_INFO(CAT_MODULES, "正在关闭模块: {}", mod->name());
|
||||||
|
mod->shutdown();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto& svc = services_[ui.index].service;
|
||||||
|
if (svc && svc->initialized()) {
|
||||||
|
E2D_INFO(CAT_SERVICES, "正在关闭服务: {}", svc->name());
|
||||||
|
svc->setState(ServiceState::Stopping);
|
||||||
|
svc->shutdown();
|
||||||
|
svc->setState(ServiceState::Stopped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lifecycle::clear() {
|
||||||
|
shutdown();
|
||||||
|
|
||||||
|
modules_.clear();
|
||||||
|
services_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,224 +0,0 @@
|
||||||
#include <extra2d/core/registry.h>
|
|
||||||
#include <extra2d/services/logger_service.h>
|
|
||||||
#include <future>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
Registry &Registry::instance() {
|
|
||||||
static Registry instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Registry::init() {
|
|
||||||
auto levels = group();
|
|
||||||
E2D_INFO(CAT_MODULES, "正在初始化 {} 个模块,共 {} 个层级...", moduleCount_,
|
|
||||||
levels.size());
|
|
||||||
|
|
||||||
for (size_t level = 0; level < levels.size(); ++level) {
|
|
||||||
auto &modules = levels[level];
|
|
||||||
|
|
||||||
// 检查当前层级是否有支持并行初始化的模块
|
|
||||||
bool hasParallelModules = false;
|
|
||||||
for (auto *module : modules) {
|
|
||||||
if (module->parallel()) {
|
|
||||||
hasParallelModules = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果只有一个模块或不支持并行,使用串行初始化
|
|
||||||
if (modules.size() <= 1 || !hasParallelModules) {
|
|
||||||
for (auto *module : modules) {
|
|
||||||
E2D_INFO(CAT_MODULES, "正在初始化模块: {} (层级 {})", module->name(),
|
|
||||||
level);
|
|
||||||
|
|
||||||
if (!module->init()) {
|
|
||||||
E2D_ERROR(CAT_MODULES, "初始化模块失败: {}", module->name());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
E2D_INFO(CAT_MODULES, "模块 {} 初始化成功", module->name());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 并行初始化当前层级的模块
|
|
||||||
E2D_INFO(CAT_MODULES, "正在并行初始化 {} 个模块 (层级 {})...",
|
|
||||||
modules.size(), level);
|
|
||||||
|
|
||||||
std::vector<std::future<std::pair<Module *, bool>>> futures;
|
|
||||||
std::vector<Module *> serialModules;
|
|
||||||
|
|
||||||
// 分离支持并行和不支持并行的模块
|
|
||||||
for (auto *module : modules) {
|
|
||||||
if (module->parallel()) {
|
|
||||||
futures.push_back(std::async(std::launch::async, [module]() {
|
|
||||||
return std::make_pair(module, module->init());
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
serialModules.push_back(module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待并行模块完成
|
|
||||||
for (auto &future : futures) {
|
|
||||||
auto [module, success] = future.get();
|
|
||||||
if (!success) {
|
|
||||||
E2D_ERROR(CAT_MODULES, "初始化模块失败: {}", module->name());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
E2D_INFO(CAT_MODULES, "模块 {} 初始化成功 (并行)", module->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 串行初始化不支持并行的模块
|
|
||||||
for (auto *module : serialModules) {
|
|
||||||
E2D_INFO(CAT_MODULES, "正在初始化模块: {} (串行, 层级 {})",
|
|
||||||
module->name(), level);
|
|
||||||
if (!module->init()) {
|
|
||||||
E2D_ERROR(CAT_MODULES, "初始化模块失败: {}", module->name());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
E2D_INFO(CAT_MODULES, "模块 {} 初始化成功", module->name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
E2D_INFO(CAT_MODULES, "层级 {} 初始化完成", level);
|
|
||||||
}
|
|
||||||
|
|
||||||
E2D_INFO(CAT_MODULES, "所有模块初始化完成");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Registry::shutdown() {
|
|
||||||
// 从后向前关闭模块
|
|
||||||
for (size_t i = moduleCount_; i > 0; --i) {
|
|
||||||
if (modules_[i - 1].valid && modules_[i - 1].module) {
|
|
||||||
modules_[i - 1].module->shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Registry::clear() {
|
|
||||||
shutdown();
|
|
||||||
|
|
||||||
// 销毁所有模块
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
modules_[i].module.reset();
|
|
||||||
modules_[i].valid = false;
|
|
||||||
}
|
|
||||||
moduleCount_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Module *> Registry::sort() {
|
|
||||||
std::vector<Module *> result;
|
|
||||||
std::vector<int> inDegree(moduleCount_, 0);
|
|
||||||
std::vector<std::vector<size_t>> adj(moduleCount_);
|
|
||||||
|
|
||||||
// 构建依赖图
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (!modules_[i].valid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto deps = modules_[i].module->deps();
|
|
||||||
for (auto &depType : deps) {
|
|
||||||
// 查找依赖模块的索引
|
|
||||||
for (size_t j = 0; j < moduleCount_; ++j) {
|
|
||||||
auto &mod = *modules_[j].module;
|
|
||||||
if (modules_[j].valid && std::type_index(typeid(mod)) == depType) {
|
|
||||||
adj[j].push_back(i);
|
|
||||||
inDegree[i]++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用优先队列,按优先级排序
|
|
||||||
auto cmp = [this](size_t a, size_t b) {
|
|
||||||
return modules_[a].module->priority() > modules_[b].module->priority();
|
|
||||||
};
|
|
||||||
std::priority_queue<size_t, std::vector<size_t>, decltype(cmp)> pq(cmp);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (inDegree[i] == 0) {
|
|
||||||
pq.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!pq.empty()) {
|
|
||||||
size_t curr = pq.top();
|
|
||||||
pq.pop();
|
|
||||||
result.push_back(modules_[curr].module.get());
|
|
||||||
|
|
||||||
for (size_t next : adj[curr]) {
|
|
||||||
inDegree[next]--;
|
|
||||||
if (inDegree[next] == 0) {
|
|
||||||
pq.push(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::vector<Module *>> Registry::group() {
|
|
||||||
std::vector<std::vector<Module *>> levels;
|
|
||||||
std::vector<int> inDegree(moduleCount_, 0);
|
|
||||||
std::vector<std::vector<size_t>> adj(moduleCount_);
|
|
||||||
|
|
||||||
// 构建依赖图
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (!modules_[i].valid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto deps = modules_[i].module->deps();
|
|
||||||
for (auto &depType : deps) {
|
|
||||||
for (size_t j = 0; j < moduleCount_; ++j) {
|
|
||||||
auto &mod = *modules_[j].module;
|
|
||||||
if (modules_[j].valid && std::type_index(typeid(mod)) == depType) {
|
|
||||||
adj[j].push_back(i);
|
|
||||||
inDegree[i]++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用 BFS 按层级分组
|
|
||||||
std::queue<size_t> q;
|
|
||||||
std::vector<int> levelMap(moduleCount_, -1);
|
|
||||||
|
|
||||||
// 找到所有入度为 0 的模块(第一层)
|
|
||||||
for (size_t i = 0; i < moduleCount_; ++i) {
|
|
||||||
if (inDegree[i] == 0) {
|
|
||||||
q.push(i);
|
|
||||||
levelMap[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BFS 遍历
|
|
||||||
while (!q.empty()) {
|
|
||||||
size_t curr = q.front();
|
|
||||||
q.pop();
|
|
||||||
|
|
||||||
int currLevel = levelMap[curr];
|
|
||||||
|
|
||||||
// 确保当前层级存在
|
|
||||||
if (levels.size() <= static_cast<size_t>(currLevel)) {
|
|
||||||
levels.resize(currLevel + 1);
|
|
||||||
}
|
|
||||||
levels[currLevel].push_back(modules_[curr].module.get());
|
|
||||||
|
|
||||||
// 处理依赖当前模块的其他模块
|
|
||||||
for (size_t next : adj[curr]) {
|
|
||||||
inDegree[next]--;
|
|
||||||
if (inDegree[next] == 0) {
|
|
||||||
q.push(next);
|
|
||||||
levelMap[next] = currLevel + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return levels;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace extra2d
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
#include <extra2d/core/service_locator.h>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
ServiceLocator& ServiceLocator::instance() {
|
|
||||||
static ServiceLocator instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServiceLocator::init() {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
for (auto& svc : orderedServices_) {
|
|
||||||
if (!svc) continue;
|
|
||||||
|
|
||||||
auto info = svc->info();
|
|
||||||
if (!info.enabled) continue;
|
|
||||||
|
|
||||||
if (!svc->initialized()) {
|
|
||||||
svc->setState(ServiceState::Initializing);
|
|
||||||
if (!svc->init()) {
|
|
||||||
svc->setState(ServiceState::Stopped);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
svc->setState(ServiceState::Running);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceLocator::shutdown() {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
for (auto it = orderedServices_.rbegin();
|
|
||||||
it != orderedServices_.rend(); ++it) {
|
|
||||||
if (*it && (*it)->initialized()) {
|
|
||||||
(*it)->setState(ServiceState::Stopping);
|
|
||||||
(*it)->shutdown();
|
|
||||||
(*it)->setState(ServiceState::Stopped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceLocator::update(f32 dt) {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
for (auto& svc : orderedServices_) {
|
|
||||||
if (svc && svc->initialized()) {
|
|
||||||
auto state = svc->state();
|
|
||||||
if (state == ServiceState::Running) {
|
|
||||||
svc->update(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceLocator::pause() {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
for (auto& svc : orderedServices_) {
|
|
||||||
if (svc && svc->initialized()) {
|
|
||||||
svc->pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceLocator::resume() {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
for (auto& svc : orderedServices_) {
|
|
||||||
if (svc && svc->initialized()) {
|
|
||||||
svc->resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Ref<IService>> ServiceLocator::all() const {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
return orderedServices_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceLocator::clear() {
|
|
||||||
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
||||||
|
|
||||||
for (auto it = orderedServices_.rbegin();
|
|
||||||
it != orderedServices_.rend(); ++it) {
|
|
||||||
if (*it && (*it)->initialized()) {
|
|
||||||
(*it)->setState(ServiceState::Stopping);
|
|
||||||
(*it)->shutdown();
|
|
||||||
(*it)->setState(ServiceState::Stopped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
services_.clear();
|
|
||||||
factories_.clear();
|
|
||||||
orderedServices_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceLocator::sort() {
|
|
||||||
std::stable_sort(orderedServices_.begin(), orderedServices_.end(),
|
|
||||||
[](const Ref<IService>& a, const Ref<IService>& b) {
|
|
||||||
if (!a || !b) return false;
|
|
||||||
return static_cast<int>(a->info().priority) <
|
|
||||||
static_cast<int>(b->info().priority);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
#include <extra2d/core/service_registry.h>
|
|
||||||
|
|
||||||
namespace extra2d {
|
|
||||||
|
|
||||||
ServiceRegistry& ServiceRegistry::instance() {
|
|
||||||
static ServiceRegistry instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceRegistry::setEnabled(const std::string& name, bool enabled) {
|
|
||||||
for (auto& reg : registrations_) {
|
|
||||||
if (reg.name == name) {
|
|
||||||
reg.enabled = enabled;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceRegistry::createAll() {
|
|
||||||
std::sort(registrations_.begin(), registrations_.end(),
|
|
||||||
[](const ServiceRegistration& a, const ServiceRegistration& b) {
|
|
||||||
return static_cast<int>(a.priority) < static_cast<int>(b.priority);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const auto& reg : registrations_) {
|
|
||||||
if (!reg.enabled) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto service = reg.factory();
|
|
||||||
if (service) {
|
|
||||||
ServiceLocator::instance().add<IService>(service);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include <extra2d/app/application.h>
|
||||||
|
#include <extra2d/render/render_module.h>
|
||||||
|
#include <extra2d/services/logger_service.h>
|
||||||
|
#include <extra2d/window/window_module.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 构造函数
|
||||||
|
* 使用 Lambda 配置渲染参数
|
||||||
|
*/
|
||||||
|
RenderModule::RenderModule(std::function<void(RenderCfg &)> configFn) {
|
||||||
|
if (configFn) {
|
||||||
|
configFn(cfg_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 析构函数
|
||||||
|
*/
|
||||||
|
RenderModule::~RenderModule() { shutdown(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化渲染模块
|
||||||
|
* 创建 OpenGL 上下文并初始化渲染设备
|
||||||
|
*/
|
||||||
|
bool RenderModule::init() {
|
||||||
|
if (initialized_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取窗口模块
|
||||||
|
auto *winMod = app()->module<WindowModule>();
|
||||||
|
if (!winMod || !winMod->win()) {
|
||||||
|
E2D_ERROR(CAT_RENDER, "WindowModule 未初始化");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换配置
|
||||||
|
RenderDeviceConfig config;
|
||||||
|
config.glMajor = cfg_.glMajor;
|
||||||
|
config.glMinor = cfg_.glMinor;
|
||||||
|
config.useES = cfg_.useES;
|
||||||
|
config.redBits = cfg_.redBits;
|
||||||
|
config.greenBits = cfg_.greenBits;
|
||||||
|
config.blueBits = cfg_.blueBits;
|
||||||
|
config.alphaBits = cfg_.alphaBits;
|
||||||
|
config.depthBits = cfg_.depthBits;
|
||||||
|
config.stencilBits = cfg_.stencilBits;
|
||||||
|
config.doubleBuffer = cfg_.doubleBuffer;
|
||||||
|
config.msaaSamples = cfg_.msaaSamples;
|
||||||
|
config.vsync = cfg_.vsync;
|
||||||
|
|
||||||
|
auto &device = RenderDevice::instance();
|
||||||
|
if (!device.init(winMod->native(), config)) {
|
||||||
|
E2D_ERROR(CAT_RENDER, "RenderDevice 初始化失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized_ = true;
|
||||||
|
|
||||||
|
E2D_INFO(CAT_RENDER, "RenderModule initialized");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭渲染模块
|
||||||
|
*/
|
||||||
|
void RenderModule::shutdown() {
|
||||||
|
if (!initialized_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderDevice::instance().shutdown();
|
||||||
|
initialized_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 交换缓冲区
|
||||||
|
*/
|
||||||
|
void RenderModule::swapBuffers() { RenderDevice::instance().swapBuffers(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置 VSync
|
||||||
|
*/
|
||||||
|
void RenderModule::setVSync(bool enabled) {
|
||||||
|
RenderDevice::instance().setVSync(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <chrono>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
@ -96,7 +97,11 @@ static void SDLCALL logOutput(void *userdata, int category,
|
||||||
const char *content;
|
const char *content;
|
||||||
parseCategory(message, cat, content);
|
parseCategory(message, cat, content);
|
||||||
|
|
||||||
Uint32 ticks = SDL_GetTicks();
|
// 使用 std::chrono 替代 SDL_GetTicks(),避免 SDL 未初始化的问题
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
now.time_since_epoch());
|
||||||
|
Uint32 ticks = static_cast<Uint32>(ms.count() % (24 * 60 * 60 * 1000));
|
||||||
Uint32 seconds = ticks / 1000;
|
Uint32 seconds = ticks / 1000;
|
||||||
Uint32 minutes = seconds / 60;
|
Uint32 minutes = seconds / 60;
|
||||||
Uint32 hours = minutes / 60;
|
Uint32 hours = minutes / 60;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
#include <extra2d/window/window_module.h>
|
||||||
|
|
||||||
|
namespace extra2d {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 构造函数
|
||||||
|
* 使用 Lambda 配置窗口参数
|
||||||
|
*/
|
||||||
|
WindowModule::WindowModule(std::function<void(WindowCfg&)> configFn) {
|
||||||
|
if (configFn) {
|
||||||
|
configFn(cfg_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 析构函数
|
||||||
|
*/
|
||||||
|
WindowModule::~WindowModule() {
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化窗口模块
|
||||||
|
* 创建窗口并设置事件回调
|
||||||
|
*/
|
||||||
|
bool WindowModule::init() {
|
||||||
|
if (initialized_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_ = ptr::unique<Window>();
|
||||||
|
|
||||||
|
WindowConfig config;
|
||||||
|
config.title = cfg_.title;
|
||||||
|
config.width = cfg_.width;
|
||||||
|
config.height = cfg_.height;
|
||||||
|
config.fullscreen = cfg_.fullscreen;
|
||||||
|
config.resizable = cfg_.resizable;
|
||||||
|
config.centerWindow = cfg_.centerWindow;
|
||||||
|
|
||||||
|
if (!window_->create(config)) {
|
||||||
|
window_.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭窗口模块
|
||||||
|
* 销毁窗口并释放资源
|
||||||
|
*/
|
||||||
|
void WindowModule::shutdown() {
|
||||||
|
if (!initialized_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_) {
|
||||||
|
window_->destroy();
|
||||||
|
window_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 轮询窗口事件
|
||||||
|
*/
|
||||||
|
void WindowModule::poll() {
|
||||||
|
if (window_) {
|
||||||
|
window_->poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查窗口是否应该关闭
|
||||||
|
*/
|
||||||
|
bool WindowModule::shouldClose() const {
|
||||||
|
return window_ ? window_->shouldClose() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭窗口
|
||||||
|
*/
|
||||||
|
void WindowModule::close() {
|
||||||
|
if (window_) {
|
||||||
|
window_->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置窗口标题
|
||||||
|
*/
|
||||||
|
void WindowModule::setTitle(const std::string& title) {
|
||||||
|
if (window_) {
|
||||||
|
window_->setTitle(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置窗口大小
|
||||||
|
*/
|
||||||
|
void WindowModule::setSize(int width, int height) {
|
||||||
|
if (window_) {
|
||||||
|
window_->setSize(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置全屏模式
|
||||||
|
*/
|
||||||
|
void WindowModule::setFullscreen(bool fullscreen) {
|
||||||
|
if (window_) {
|
||||||
|
window_->setFullscreen(fullscreen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取窗口宽度
|
||||||
|
*/
|
||||||
|
int WindowModule::width() const {
|
||||||
|
return window_ ? window_->width() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取窗口高度
|
||||||
|
*/
|
||||||
|
int WindowModule::height() const {
|
||||||
|
return window_ ? window_->height() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 检查是否全屏
|
||||||
|
*/
|
||||||
|
bool WindowModule::fullscreen() const {
|
||||||
|
return window_ ? window_->fullscreen() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置事件回调
|
||||||
|
*/
|
||||||
|
void WindowModule::onEvent(std::function<void(const SDL_Event&)> cb) {
|
||||||
|
if (window_) {
|
||||||
|
window_->onEvent(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取原生窗口指针
|
||||||
|
*/
|
||||||
|
SDL_Window* WindowModule::native() const {
|
||||||
|
return window_ ? window_->native() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extra2d
|
||||||
|
|
@ -2,27 +2,36 @@
|
||||||
|
|
||||||
using namespace extra2d;
|
using namespace extra2d;
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Hello World 示例
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
E2D_INFO(CAT_APP, "========================");
|
E2D_INFO(CAT_APP, "========================");
|
||||||
E2D_INFO(CAT_APP, "Extra2D Hello World Demo");
|
E2D_INFO(CAT_APP, "Extra2D Hello World Demo");
|
||||||
E2D_INFO(CAT_APP, "========================");
|
E2D_INFO(CAT_APP, "========================");
|
||||||
|
|
||||||
// 获取应用实例并初始化
|
|
||||||
auto &app = Application::instance();
|
auto &app = Application::instance();
|
||||||
|
app.name = "Hello World";
|
||||||
|
|
||||||
|
// 注册服务和模块(顺序无关,Lifecycle 会自动按依赖拓扑排序)
|
||||||
|
app.useService<ILogger, ConsoleLogger>();
|
||||||
|
app.useService<IEventService, EventService>();
|
||||||
|
app.useService<ITimerService, TimerService>();
|
||||||
|
app.useModule<WindowModule>([](WindowCfg &cfg) {
|
||||||
|
cfg.title = "Extra2D - Hello World";
|
||||||
|
cfg.width = 1280;
|
||||||
|
cfg.height = 720;
|
||||||
|
});
|
||||||
|
app.useModule<RenderModule>([](RenderCfg &cfg) {
|
||||||
|
cfg.glMajor = 4;
|
||||||
|
cfg.glMinor = 5;
|
||||||
|
cfg.vsync = true;
|
||||||
|
});
|
||||||
|
|
||||||
if (!app.init()) {
|
if (!app.init()) {
|
||||||
E2D_ERROR(CAT_APP, "应用初始化失败!");
|
E2D_ERROR(CAT_APP, "应用初始化失败!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取事件服务并订阅键盘事件
|
auto eventService = Lifecycle::instance().service<IEventService>();
|
||||||
auto eventService = ServiceLocator::instance().get<IEventService>();
|
|
||||||
if (eventService) {
|
if (eventService) {
|
||||||
// 订阅 ESC 键退出
|
|
||||||
eventService->on(EventType::KeyPressed, [&app](Event &e) {
|
eventService->on(EventType::KeyPressed, [&app](Event &e) {
|
||||||
auto &keyEvent = std::get<KeyEvent>(e.data);
|
auto &keyEvent = std::get<KeyEvent>(e.data);
|
||||||
if (keyEvent.key == static_cast<i32>(Key::Escape)) {
|
if (keyEvent.key == static_cast<i32>(Key::Escape)) {
|
||||||
|
|
@ -31,7 +40,6 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 订阅手柄按钮退出
|
|
||||||
eventService->on(EventType::GamepadButtonPressed, [&app](Event &e) {
|
eventService->on(EventType::GamepadButtonPressed, [&app](Event &e) {
|
||||||
auto &btnEvent = std::get<GamepadButtonEvent>(e.data);
|
auto &btnEvent = std::get<GamepadButtonEvent>(e.data);
|
||||||
if (btnEvent.button == static_cast<i32>(Gamepad::Start)) {
|
if (btnEvent.button == static_cast<i32>(Gamepad::Start)) {
|
||||||
|
|
@ -42,11 +50,9 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
E2D_INFO(CAT_APP, "开始主循环...");
|
E2D_INFO(CAT_APP, "开始主循环...");
|
||||||
|
|
||||||
// 运行应用
|
|
||||||
app.run();
|
app.run();
|
||||||
|
|
||||||
E2D_INFO(CAT_APP, "应用结束");
|
E2D_INFO(CAT_APP, "应用结束");
|
||||||
|
|
||||||
|
app.shutdown();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue