diff --git a/docs/module_system.md b/docs/module_system.md new file mode 100644 index 0000000..b6f523d --- /dev/null +++ b/docs/module_system.md @@ -0,0 +1,505 @@ +# Extra2D 模块系统 + +## 概述 + +Extra2D 采用模块化架构设计,所有核心功能都通过模块系统管理。模块系统提供: + +- **统一的生命周期管理**:初始化、关闭、依赖处理 +- **优先级排序**:确保模块按正确顺序初始化 +- **配置驱动**:每个模块可独立配置 +- **解耦设计**:Application 只协调模块,不直接管理任何依赖 + +## 架构图 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Application │ +│ (只负责协调模块,不直接管理任何依赖) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ ModuleRegistry │ +│ (模块注册表,管理所有模块的生命周期) │ +└─────────────────────────────────────────────────────────────┘ + │ + ┌─────────────────────┼─────────────────────┐ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│ Logger Module │ │ Config Module │ │Platform Module│ +│ (日志系统) │ │ (配置管理) │ │ (平台初始化) │ +└───────────────┘ └───────────────┘ └───────────────┘ + │ │ │ + └─────────────────────┼─────────────────────┘ + ▼ + ┌───────────────┐ + │ Window Module │ + │ (窗口管理) │ + └───────────────┘ + │ + ▼ + ┌───────────────┐ + │ Render Module │ + │ (渲染系统) │ + └───────────────┘ +``` + +## 模块优先级 + +模块按优先级从小到大初始化,关闭时逆序执行: + +| 优先级值 | 枚举名称 | 用途 | 模块示例 | +|---------|---------|------|---------| +| 0 | `Core` | 核心模块,最先初始化 | Logger, Config, Platform, Window | +| 50 | `Input` | 输入处理 | Input | +| 100 | `Graphics` | 图形渲染 | Render | +| 200 | `Audio` | 音频系统 | Audio | +| 300 | `Physics` | 物理系统 | Physics | +| 400 | `Gameplay` | 游戏逻辑 | Gameplay | +| 500 | `UI` | 用户界面 | UI | + +## 核心接口 + +### IModuleConfig + +模块配置接口,定义模块的元数据和配置: + +```cpp +class IModuleConfig { +public: + virtual ~IModuleConfig() = default; + + // 模块信息 + virtual ModuleInfo getModuleInfo() const = 0; + + // 配置管理 + virtual std::string getConfigSectionName() const = 0; + virtual bool validate() const = 0; + virtual void resetToDefaults() = 0; + virtual bool loadFromJson(const void* jsonData) = 0; + virtual bool saveToJson(void* jsonData) const = 0; + + // 平台约束 + virtual void applyPlatformConstraints(PlatformType platform) {} +}; +``` + +### IModuleInitializer + +模块初始化器接口,管理模块的生命周期: + +```cpp +class IModuleInitializer { +public: + virtual ~IModuleInitializer() = default; + + // 模块标识 + virtual ModuleId getModuleId() const = 0; + virtual ModulePriority getPriority() const = 0; + virtual std::vector getDependencies() const = 0; + + // 生命周期 + virtual bool initialize(const IModuleConfig* config) = 0; + virtual void shutdown() = 0; + virtual bool isInitialized() const = 0; +}; +``` + +### ModuleRegistry + +模块注册表,管理所有模块: + +```cpp +class ModuleRegistry { +public: + static ModuleRegistry& instance(); + + // 注册模块 + ModuleId registerModule( + UniquePtr config, + ModuleInitializerFactory factory + ); + + // 获取模块 + IModuleConfig* getModuleConfig(ModuleId id); + IModuleInitializer* getInitializer(ModuleId id); + + // 初始化顺序 + std::vector getInitializationOrder() const; + + // 查询 + bool hasModule(const std::string& name) const; + std::vector getModuleNames() const; +}; +``` + +## 创建新模块 + +### 步骤 1:定义配置类 + +```cpp +// my_module.h +class MyModuleConfig : public IModuleConfig { +public: + int someSetting = 42; + std::string somePath; + + ModuleInfo getModuleInfo() const override { + ModuleInfo info; + info.name = "MyModule"; + info.version = "1.0.0"; + info.priority = ModulePriority::Gameplay; + info.enabled = true; + return info; + } + + std::string getConfigSectionName() const override { + return "my_module"; + } + + bool validate() const override { + return someSetting > 0; + } + + void resetToDefaults() override { + someSetting = 42; + somePath.clear(); + } + + bool loadFromJson(const void* jsonData) override; + bool saveToJson(void* jsonData) const override; +}; +``` + +### 步骤 2:定义初始化器 + +```cpp +// my_module.h +class MyModuleInitializer : public IModuleInitializer { +public: + ModuleId getModuleId() const override { return moduleId_; } + ModulePriority getPriority() const override { return ModulePriority::Gameplay; } + std::vector getDependencies() const override { return {}; } + + bool initialize(const IModuleConfig* config) override { + if (initialized_) return true; + + const MyModuleConfig* cfg = dynamic_cast(config); + if (!cfg) return false; + + // 执行初始化逻辑... + + initialized_ = true; + E2D_LOG_INFO("MyModule initialized"); + return true; + } + + void shutdown() override { + if (!initialized_) return; + + // 执行清理逻辑... + + initialized_ = false; + E2D_LOG_INFO("MyModule shutdown"); + } + + bool isInitialized() const override { return initialized_; } + void setModuleId(ModuleId id) { moduleId_ = id; } + +private: + ModuleId moduleId_ = INVALID_MODULE_ID; + bool initialized_ = false; +}; +``` + +### 步骤 3:注册模块 + +```cpp +// my_module.cpp +#include + +namespace extra2d { + +static ModuleId s_myModuleId = INVALID_MODULE_ID; + +ModuleId get_my_module_id() { + return s_myModuleId; +} + +void register_my_module() { + if (s_myModuleId != INVALID_MODULE_ID) return; + + s_myModuleId = ModuleRegistry::instance().registerModule( + makeUnique(), + []() -> UniquePtr { + auto initializer = makeUnique(); + initializer->setModuleId(s_myModuleId); + return initializer; + } + ); +} + +// 自动注册 +namespace { + struct MyModuleAutoRegister { + MyModuleAutoRegister() { + register_my_module(); + } + }; + + static MyModuleAutoRegister s_autoRegister; +} + +} // namespace extra2d +``` + +### 步骤 4:在 Application 中使用 + +```cpp +// application.cpp +#include + +bool Application::init(const AppConfig& config) { + // 注册模块 + register_my_module(); + + // 初始化所有模块 + return initModules(); +} +``` + +## 内置模块 + +### Logger 模块 + +**职责**:管理日志系统初始化和关闭 + +**配置**: +```cpp +LoggerModuleConfig config; +config.logLevel = LogLevel::Info; +config.consoleOutput = true; +config.fileOutput = true; +config.logFilePath = "app.log"; +``` + +**平台支持**: +- Windows:彩色控制台输出 +- Linux/macOS:ANSI 彩色输出 +- Switch:libnx console + +--- + +### Config 模块 + +**职责**:管理 ConfigManager 和应用配置 + +**配置**: +```cpp +ConfigModuleConfig config; +config.configPath = "config.json"; +config.appConfig = AppConfig::createDefault(); +``` + +--- + +### Platform 模块 + +**职责**:平台检测和平台特定初始化 + +**平台特定操作**: +- Switch:初始化 romfs 和 socket + +**配置**: +```cpp +PlatformModuleConfig config; +config.targetPlatform = PlatformType::Auto; // 自动检测 +``` + +--- + +### Window 模块 + +**职责**:窗口创建和后端管理 + +**后端支持**: +- SDL2:跨平台 +- GLFW:跨平台 +- Switch:原生 + +**配置**: +```cpp +WindowModuleConfig config; +config.backend = "sdl2"; +config.windowConfig.title = "My App"; +config.windowConfig.width = 1280; +config.windowConfig.height = 720; +config.windowConfig.vsync = true; +``` + +--- + +### Render 模块 + +**职责**:渲染器初始化和管理 + +**配置**: +```cpp +RenderModuleConfig config; +config.backend = BackendType::OpenGL; +config.vsync = true; +config.targetFPS = 60; +config.multisamples = 4; +``` + +## 模块依赖 + +模块可以声明依赖关系: + +```cpp +std::vector getDependencies() const override { + return { get_window_module_id(), get_config_module_id() }; +} +``` + +ModuleRegistry 会自动解析依赖并按正确顺序初始化。 + +## 配置文件格式 + +模块配置使用 JSON 格式: + +```json +{ + "logger": { + "logLevel": 2, + "consoleOutput": true, + "fileOutput": false + }, + "window": { + "backend": "sdl2", + "title": "My Application", + "width": 1280, + "height": 720, + "vsync": true + }, + "render": { + "backend": "opengl", + "targetFPS": 60, + "multisamples": 4 + } +} +``` + +## 最佳实践 + +### 1. 单一职责 + +每个模块只负责一个明确的功能领域: + +``` +✅ Logger Module → 只管理日志 +✅ Window Module → 只管理窗口 +❌ Game Module → 管理输入、渲染、音频(职责过多) +``` + +### 2. 依赖最小化 + +模块应尽量减少对其他模块的依赖: + +```cpp +// 好的做法:通过接口获取信息 +std::vector getDependencies() const override { + return { get_window_module_id() }; // 只依赖窗口 +} + +// 不好的做法:依赖过多 +std::vector getDependencies() const override { + return { + get_window_module_id(), + get_config_module_id(), + get_logger_module_id(), + get_render_module_id() + }; +} +``` + +### 3. 延迟初始化 + +资源在需要时才初始化,不是在构造函数中: + +```cpp +bool initialize(const IModuleConfig* config) override { + if (initialized_) return true; + + // 在这里初始化资源 + resource_ = createResource(); + + initialized_ = true; + return true; +} +``` + +### 4. 安全关闭 + +关闭时要检查状态,避免重复关闭: + +```cpp +void shutdown() override { + if (!initialized_) return; // 避免重复关闭 + + // 清理资源 + resource_.reset(); + + initialized_ = false; +} +``` + +### 5. 使用日志 + +在关键操作处添加日志: + +```cpp +bool initialize(const IModuleConfig* config) override { + E2D_LOG_INFO("Initializing MyModule..."); + + if (!doSomething()) { + E2D_LOG_ERROR("Failed to do something"); + return false; + } + + E2D_LOG_INFO("MyModule initialized successfully"); + return true; +} +``` + +## 调试 + +### 查看模块初始化顺序 + +```cpp +auto order = ModuleRegistry::instance().getInitializationOrder(); +for (ModuleId id : order) { + auto* config = ModuleRegistry::instance().getModuleConfig(id); + if (config) { + auto info = config->getModuleInfo(); + E2D_LOG_INFO("Module: {} (priority: {})", + info.name, static_cast(info.priority)); + } +} +``` + +### 检查模块状态 + +```cpp +auto* initializer = ModuleRegistry::instance().getInitializer(moduleId); +if (initializer && initializer->isInitialized()) { + E2D_LOG_INFO("Module is initialized"); +} +``` + +## 示例 + +完整示例请参考: +- [examples/basic/main.cpp](../../examples/basic/main.cpp) - 基础示例 +- [Extra2D/src/platform/window_module.cpp](../../Extra2D/src/platform/window_module.cpp) - Window 模块实现 +- [Extra2D/src/graphics/render_module.cpp](../../Extra2D/src/graphics/render_module.cpp) - Render 模块实现