Skip to main content

cpp-algo-style

MaaEnd cpp-algo C++ 编码风格与工程规范指南。参考 MaaFramework 的优秀实践,规范命名、头文件、公共工具、错误处理、日志、CMake 等方面。在编写、修改或审查 agent/cpp-algo/ 下的 C++ 代码时使用。

الانتقال إلى التثبيت

معلومات المصدر

المستودع
isHarryh/MaaEnd
آخر نشاط في المصدر
١٥ يوليو ٢٠٢٦ في ١٧:٤١
لغة SKILL.md المكتشفة
الصينية
النجوم
٢
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
2 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
cpp-algo-style
description
MaaEnd cpp-algo C++ 编码风格与工程规范指南。参考 MaaFramework 的优秀实践,规范命名、头文件、公共工具、错误处理、日志、CMake 等方面。在编写、修改或审查 agent/cpp-algo/ 下的 C++ 代码时使用。
# cpp-algo C++ 编码风格指南 本指南以 MaaFramework 源码为标杆,针对 cpp-algo 中已知的工程缺陷制定规范。 ## 1. 命名规范 cpp-algo 当前最严重的问题是 **命名风格不统一**,同一个项目中混用了多种约定。 ### 必须遵循的规则 | 元素 | 风格 | 示例 | | ------------------ | ------------------------------------------ | -------------------------------------- | | 类 / 结构体 / 枚举 | PascalCase | `MapLocator`, `MatchFeature` | | 成员函数 | camelCase | `initialize()`, `resetTrackingState()` | | 自由函数 | PascalCase(对外)/ snake_case(内部工具) | `CreateInputBackend()` | | 成员变量 | snake*case + 尾下划线 `*` | `locator_`, `current_zone_id_` | | 局部变量 | snake_case | `search_rect`, `fine_result` | | 常量(constexpr) | `k` 前缀 + PascalCase | `kDefaultMinimapRoi`, `kMaxLostFrames` | | 宏 | ALL_CAPS | `MAA_TRUE`, `LOG_ARGS` | | 命名空间 | lowercase | `maplocator`, `mapnavigator` | | 模板参数 | 后缀 `_t` 或 PascalCase | `Item_t`, `OutT` | | 枚举值 | PascalCase | `TrackingLost`, `ScreenBlocked` | ### 已知违规(修改时顺手修复) - `MapPosition` 中 `zoneId`、`sliceIndex` 等用了 camelCase 成员,应改为 `zone_id_`、`slice_index_` - `TrackingConfig` 中 `maxNormalSpeed`、`screenBlockedThreshold` 同理 - `MatchStrategy` 中 `_isBase`(前导下划线)应改为 `is_base_` - 常量 `MinimapROIOriginX`、`MaxLostTrackingCount`、`MinMatchScore` 缺少 `k` 前缀 ## 2. 头文件规范 ### Include Guard 统一使用 `#pragma once`(已做到)。 ### Include 顺序 按以下分组排列,组间空行分隔: 1. 本 `.cpp` 对应的 `.h` 2. C++ 标准库 `<algorithm>`, `<string>` ... 3. 第三方库 `<opencv2/...>`, `<meojson/json.hpp>`, `<onnxruntime/...>` 4. MaaFramework `<MaaFramework/...>`, `<MaaUtils/...>` 5. 本项目头文件 `"MapTypes.h"`, `"../utils.h"` ### OpenCV 引入 **必须** 通过 `<MaaUtils/NoWarningCV.hpp>` 引入 OpenCV,禁止直接 `<opencv2/opencv.hpp>`。这是 MaaFramework 的统一做法,用于抑制编译器警告。 当前违规文件:`MatchStrategy.h`、`MotionTracker.h`、`YoloPredictor.h` 直接引入了 `<opencv2/opencv.hpp>`。 ### MaaFramework 头文件引号 对外部依赖(MaaFramework、第三方库)统一使用尖括号 `<>`,对本项目内部头文件使用双引号 `""`。 ## 3. 公共工具复用(消除重复代码) cpp-algo 中存在多处 **重复实现**,必须提取到公共头文件。 ### 必须提取的工具 **`ScopedImageBuffer`** — 当前在 `MapLocateAction.cpp`、`position_provider.cpp`、`adb_input_backend.cpp` 三处重复定义,应提取到公共头文件(如 `source/common/scoped_buffer.h`): ```cpp class ScopedImageBuffer { public: ScopedImageBuffer() : buffer_(MaaImageBufferCreate()) {} ~ScopedImageBuffer() { MaaImageBufferDestroy(buffer_); } ScopedImageBuffer(const ScopedImageBuffer&) = delete; ScopedImageBuffer& operator=(const ScopedImageBuffer&) = delete; MaaImageBuffer* Get() const { return buffer_; } private: MaaImageBuffer* buffer_; }; ``` **`DetectControllerType`** — 当前在 `MapLocateAction.cpp`、`position_provider.cpp`、`backend.cpp` 三处重复实现,应提取到 `controller_type_utils.h`。 **`MAA_TRUE` / `MAA_FALSE` 宏** — 在多个 `.cpp` 中条件定义。应在一个公共头文件中统一处理,或直接使用 `MaaBool` 的 `1` / `0`。 ### 新增公共工具的原则 - 在 `source/common/` 下建立公共头文件 - 跨模块(MapLocator / MapNavigator)共用的工具放这里 - 模块内部工具放在模块自己的匿名命名空间或 `detail` 命名空间中 ## 4. 命名空间 ### 正确做法 - 顶层按模块分:`maplocator`、`mapnavigator` - 后端按层级嵌套:`mapnavigator::backend::adb` - 实现细节用匿名命名空间(`namespace { }` 在 `.cpp` 中) ### 避免的问题 `utils::SleepFor` 嵌套在 `mapnavigator` 命名空间中(`navi_math.h`),而 `source/utils.h` 是另一个全局工具头。这造成了命名空间语义冲突。应将通用工具统一放入 `source/common/`。 ## 5. 类设计 ### 推荐模式(参考 MaaFramework) - **PIMPL**:对外暴露的复杂类使用 PIMPL 隐藏实现(`MapLocator` 已正确使用) - **NonCopyable**:需要禁止拷贝的类应明确 `= delete` 拷贝构造和赋值(`ScopedImageBuffer` 已做到,但建议提取基类或用宏) - **Strategy 模式**:`IMatchStrategy` + Factory 的设计是好的,保持 - **RAII**:资源获取即初始化,析构时释放(`ScopedImageBuffer` 是好例子) ### 需要改进的点 - `NavigationStateMachine` 持有多个裸指针(`ActionWrapper*` 等),生命周期依赖调用者保证——应添加注释说明所有权语义,或使用 `std::shared_ptr` / `std::weak_ptr` - 全局单例 `getOrInitLocator()` 使用 `static std::shared_ptr`——可接受但应注意线程安全和测试性 ## 6. 日志规范 遵循 [maa-logging skill](../maa-logging/SKILL.md) 的完整指南。此处强调 cpp-algo 特有的问题: ### 禁止高频大量日志 YOLO 推理中每帧输出完整 softmax 向量是 **严重性能问题**: ```cpp // 错误 — 每帧打印完整分类向量 LogInfo << "YOLO Raw All:" << yoloClassNames << std::vector<float>(...); // 正确 — 仅输出关键结果,详细信息用 LogTrace LogDebug << "YOLO:" << VAR(predicted_name) << VAR(max_conf); LogTrace << "YOLO all scores:" << scores; ``` ### 日志级别选择 | 场景 | 级别 | | ----------------------------- | ---------- | | 初始化成功/失败、关键状态变更 | `LogInfo` | | 定位结果、导航阶段切换 | `LogInfo` | | 匹配分数、中间计算 | `LogDebug` | | 完整矩阵/向量数据 | `LogTrace` | | 可恢复异常(追踪丢失) | `LogWarn` | | 不可恢复错误 | `LogError` | ## 7. 错误处理 ### 模式 - 返回 `bool` / `std::optional` 表示成功/失败 - 失败路径 `LogError` + 早期 `return` - OpenCV 操作用 `try/catch` 保护(`CoreMatch` 中已有,应推广到其他 cv 调用密集处) - MaaFramework C API 返回值必须检查 ### 禁止 - 静默忽略错误 - 假设指针非空而不检查 ## 8. 现代 C++ 用法 项目目标 **C++20**,应积极使用现代特性: | 推荐 | 示例 | | ----------------- | ------------------------------------------------- | | `std::optional` | 返回可能失败的结果 | | 指定初始化器 | `LocateResult { .status = ..., .position = ... }` | | `std::filesystem` | 路径操作 | | `std::format` | 字符串格式化(替代 `std::stringstream`) | | `std::ranges` | 容器算法链(`controller_type_utils.h` 中已用) | | `constexpr` | 编译期常量 | | 结构化绑定 | `auto [x, y] = getPosition();` | | smart pointers | `std::unique_ptr` / `std::shared_ptr` 管理资源 | ### X-Macro 的使用 `NAVI_ACTION_TYPES(X)` 宏用于生成枚举和字符串映射。这种模式可以接受,但应: - 在宏定义处添加注释解释用途 - 确保使用 `#undef` 清理临时宏 ## 9. 魔法数字 cpp-algo 中散布大量硬编码阈值(`0.43`、`4.5`、`0.85`、`0.55` 等)。 ### 规则 - **所有阈值** 必须定义为 `constexpr` 命名常量,带 `k` 前缀 - 常量定义集中放在对应模块的 config 结构体或头文件顶部 - 必须附带注释说明物理含义和调优依据 ```cpp // 错误 if (score < 0.55) { return false; } // 正确 constexpr double kGlobalSearchPassThreshold = 0.55; // 全局搜索及格线,容忍 UI 遮挡 + 光影 if (score < kGlobalSearchPassThreshold) { return false; } ``` ## 10. CMake 规范 ### 禁止 `file(GLOB_RECURSE)` 当前 `source/CMakeLists.txt` 使用 `file(GLOB_RECURSE)` 自动收集源文件。CMake 官方文档明确不推荐此做法(新增/删除文件不会触发重新配置)。 应改为显式列出源文件: ```cmake target_sources(cpp-algo PRIVATE main.cpp MapLocator/MapLocator.cpp MapLocator/MapLocateAction.cpp # ... ) ``` ### 清理未使用变量 `${cpp_algo_header}` 从未定义却被引用,应清除。 ## 11. 文件命名 | 元素 | 风格 | 示例 | | ------------- | -------------------------------------- | ---------------------------------------- | | 类对应的文件 | PascalCase | `MapLocator.h`, `MapLocator.cpp` | | 工具/非类文件 | snake_case | `controller_type_utils.h`, `navi_math.h` | | 目录 | PascalCase(模块)/ snake_case(工具) | `MapLocator/`, `Backend/Adb/` | 当前 `my_reco_1/` 是示例模板目录,如果保留应重命名为有意义的名称。 ## 12. 注释语言 - 代码注释使用 **中文** 或 **英文** 均可,但单个文件内保持一致 - 对外接口(`.h` 中的 public 方法)建议英文注释 - 算法实现细节(`.cpp` 中)用中文注释解释"为什么"是可以的(当前做得好的部分) ## 审查清单 修改 cpp-algo 代码时,对照检查: - [ ] 命名风格是否符合上表 - [ ] 是否引入了重复代码(检查是否已有公共工具) - [ ] OpenCV 是否通过 `NoWarningCV.hpp` 引入 - [ ] 日志级别是否合理,是否避免了高频大量输出 - [ ] 新常量是否有 `k` 前缀和注释 - [ ] 错误路径是否有日志和合理返回值 - [ ] 新文件是否加入了 CMakeLists.txt 的显式列表(如已迁移) 详细的命名对照和重构示例见 [reference.md](reference.md)。
عرض على GitHub