彻底重构:模块化包架构、统一连接器工厂、78 测试、Muon+Lion 训练 - #154
Open
HDAnzz wants to merge 273 commits into
Open
Conversation
- Fix: base_dir (tools/) -> parent (cannotmax/) -> parent (src/) -> parent (root) - DATA_DIR now correctly points to project_root/data
- Fix: data_file path from 'arknights.csv' to 'data/arknights.csv' - FIELD_FEATURE_COUNT is correctly set to 0 in config/constants.py
- Remove terrain feature fields (6 features removed) - Dataset now only contains monster units (34L + 34R + Result + ImgPath) - Align with current data format in data/arknights.csv
- Move: src/cannotmax/utils/winrt_capture.py → src/cannotmax/core/winrt_connector.py - Update imports in recognize.py, main_window.py - Update __init__.py exports (remove from utils, add to core) - Align with maa_adb_connector.py structure (both are platform connectors) Now core/ contains all platform abstraction layers (ADB, WinRT)
- Update WinRTScreenCapture import in legacy/loadData.py - Remove resolve_maafw_path usage (no longer exists) - Fix field_recognition.py model path to use relative path
- Rename src/cannotmax/data → src/cannotmax/analytics - Update imports in main_window.py, simular_history_match_ui.py - Avoid naming conflict with data/ directory (arknights.csv) Now: data/ is for CSV/images, analytics/ is for analysis code
- Create src/cannotmax/models/ directory - Split transformer.py into: - dataset.py: ArknightsDataset, TOTAL_FEATURE_COUNT - transformer.py: UnitAwareTransformer only - Update imports in train.py, val.py, predict.py - Models are now framework-agnostic (no training logic) Structure: models/ ├── __init__.py ├── dataset.py # Data loading └── transformer.py # Model definition train.py now imports from .models instead of defining classes
- Move train.py → training/trainer.py - Move val.py → training/evaluator.py - Create training/__init__.py with exports - Update relative imports (from .config → from ..config) - Remove standalone train.py and val.py from root Now: training/trainer.py contains training loop, training/evaluator.py contains validation logic
- Remove ArknightsDataset class (moved to models/dataset.py) - Remove UnitAwareTransformer class (moved to models/transformer.py) - trainer.py now only contains: - Training utilities (train_one_epoch, evaluate) - Data preprocessing (preprocess_data) - Main training loop (main) - Uses relative imports: from ..models import UnitAwareTransformer, ArknightsDataset
- Update Quick Start with CLI commands (train, eval, convert) - Add new directory structure (models/, training/, pipelines/, cli/, console.py) - Update Entry Points with console.py and module entry points - Update Capture Modes: winrt_capture.py → winrt_connector.py - Add Key Files for models/, training/ modules - Update MAA Integration: remove Win32Controller section, note auto-loaded binaries - Update Common Agent Pitfalls: remove 3rdparty/maafw, add model loading/data paths notes - Update Current Phase: Phase 9 - Module Separation (Complete) - Remove Phase 9 import standardization section (completed)
- Rename src/cannotmax/cli.py → console.py (CLI entry point) - Update pyproject.toml: cannotmax entry → console:main - Add src/cannotmax/training/__main__.py for python -m entry - Update src/cannotmax/pipelines/merge_data.py paths - CLI now uses argparse with subcommands: train, eval, convert Entry points: - cannotmax train - cannotmax eval - cannotmax convert -i model.pth -o model.onnx - python -m src.cannotmax.training
- Add src/cannotmax/config/paths.py with Path objects for common directories: - PROJECT_ROOT, DATA_DIR, DATA_CSV - IMAGES_DIR, TMP_IMAGES_DIR - MODELS_DIR, DEFAULT_MODEL_FILE, DEFAULT_ONNX_FILE - MONSTER_DATA_CSV, TEMP_DIR Import pattern: from ..config.paths import DATA_CSV, MODELS_DIR
- Remove os.path.join() in favor of Path division operator - Replace os.path.exists() with Path.exists() - Replace os.remove() with Path.unlink() - Replace os.makedirs() with Path.mkdir(parents=True, exist_ok=True) - Replace os.walk() with Path.rglob() in data_washer_new.py - Remove unused 'import os' from 8 files - Keep os.environ and os.cpu_count() where actively used Files modified: - cli/HumanDataCheck.py, pipelines/data_cleaning*.py, pipelines/data_washer_new.py - core/recognize.py, core/predict_onnx.py, core/field_recognition.py - core/maa_adb_connector.py, legacy/loadData.py
- Use csv.DictReader instead of csv.reader with index lookups
- Load both '原始名称' and '名称' columns in single pass
- Build id -> {primary, alt} mapping dictionary
- Eliminate O(n²) CSV re-reading inside loop (was O(n×m))
- Simplified fallback logic with unified try-fallback loop
- Complexity: O(n+m) instead of O(n×m)
- Default to GUI when running 'uv run cannotmax' without arguments - Keep train/eval/convert subcommands for CLI operations - Use PyQt6 QApplication with high DPI scaling enabled
…_EnableHighDpiScaling
- PyQt6 enables High DPI scaling by default - Removed unnecessary setAttribute call
- Corrected class name from MainWindow to ArknightsApp - MainWindow does not exist in gui/main_window.py
- OCR returns string 'number' but arrays expect int16 - Added int() conversion with safety checks in recognize_and_predict - Added int() conversion in fill_data method - Added int() conversion in get_image_name method - Prevents CUDA device-side assert from string/int type mismatch
- Move cli/convert_model.py -> tools/convert_model.py - Move cli/HumanDataCheck.py -> tools/human_data_check.py (snake_case) - Update console.py import path for convert_model - CLI now only contains console.py (entry point) - Tools contain standalone utilities (convert_model, human_data_check) Rationale: - convert_model and HumanDataCheck are utility scripts, not CLI commands - console.py is the only true CLI entry point with argparse subcommands
- Changed .cli import to .console (module renamed) - Fixes 'No name main in module cannotmax.cli' error
- auto_fetch.py: State machine for automated battle data collection - field_recognition.py: ONNX/PyTorch-based terrain recognition - maa_adb_connector.py: MAA Framework wrapper (ADB, input, OCR, emulators) - predict_onnx.py: ONNX fallback inference engine - predict.py: Primary PyTorch inference with CUDA support - recognize.py: Template matching + OCR monster recognition - winrt_connector.py: Windows.Graphics.Capture adapter (已有文档) - __init__.py: Module overview with component descriptions
- Create core/connector/ package with BaseConnector abstract class - AdbConnector: ADB emulator support with MAA Framework auto-detection - MAA mode: post_screencap/post_click (background) - Legacy mode: ADB screencap/input tap - PcConnector: PC client support with MAA Framework auto-detection - MAA mode: FramePool + SendMessageWithCursorPos (background) - Legacy mode: WinRT capture + SendInput (foreground) - Remove legacy/loadData.py (replaced by connector module) - Update gui/main_window.py: AdbConnectorAdapter -> AdbConnector - Update core/__init__.py: export new connectors Both connectors inherit from BaseConnector with unified interface: - is_connected, screen_width, screen_height - connect(), capture_screenshot(), click(), get_device_list() MAA Framework is optional - connectors degrade gracefully if unavailable.
- Fix maa_adb_connector.py: import AdbConnector from .connector instead of ..legacy - Fix main_window.py: update docstring reference from loadData.AdbConnector - Remove legacy/loadData.py import from auto_fetch.py (comment only) All references now use core.connector.AdbConnector/PcConnector
- Rename winrt_connector.py -> winrt_capture.py (Not a connector, just WinRT screenshot + SendInput utility) - Update pc_connector.py import WinRTScreenCapture is a helper class, not BaseConnector subclass.
- Delete maa_adb_connector.py (AdbConnectorAdapter deprecated) - Create core/connector/maa_registry.py with: - MaaFrameworkDetector: Singleton availability checker - ConnectionTypeRegistry: Emulator default addresses (LDPlayer, MuMu, etc.) - InputMethodRegistry: Input method enums (maatouch, adb_shell, etc.) - MaaAvailability: Enum for MAA states - Update gui/main_window.py: import from maa_registry instead of maa_adb_connector Functionality preserved: - ConnectionTypeRegistry: GUI dropdown options for emulator types - InputMethodRegistry: GUI dropdown options for input methods - MaaFrameworkDetector: Status indicator in GUI Removed: - AdbConnectorAdapter: Replaced by AdbConnector (MAA auto-detect) - MaaAdbConnector: Replaced by AdbConnector._init_maa() - MaaConnectionConfig/AdapterState: No longer needed
… WinRT - Update recognize.py to use PcConnector.capture_screenshot() instead of WinRTScreenCapture - PcConnector now supports optional ROI parameter for efficient cropping - RecognizeMonster.__init__: Initialize PcConnector and call connect() - RecognizeMonster.run_loop: Use PcConnector.capture_screenshot() for background image - RecognizeMonster.capture_screenshot: Use PcConnector with roi=bbox for region crop Benefits: - Unified screenshot interface (MAA/WinRT auto-detect) - Cleaner separation: recognize.py doesn't depend on WinRT implementation details - PcConnector handles MAA Framework fallback automatically
- Split recognize.py into modular components: - recognize.py: Core recognition logic (template matching + OCR) - roi_selector.py: Interactive ROI selection with OpenCV - screenshot_helper.py: Screenshot capture with auto-detection - RecognizeMonster now composes ROISelector and ScreenshotHelper - Helper functions (preprocess, find_best_match, etc.) remain in recognize.py - Maintain backward compatibility: RecognizeMonster API unchanged Benefits: - Separation of concerns: recognition vs. input (ROI/screenshot) - Reusable components: ROISelector and ScreenshotHelper available independently - Cleaner code structure: recognize.py focused on core algorithm
- Fix AdbController initialization: use named argument 'address' instead of positional - Fix Win32Controller initialization: ensure proper cleanup on failure - Add finally blocks to clean up temporary MAA objects - Prevent AttributeError in MAA Controller.__del__ by ensuring objects are either fully initialized or not stored in instance variables Fixes: - 'AdbController' object has no attribute '_handle' (MAA bug workaround) - AdbController.__init__() missing 1 required positional argument: 'address'
- Remove hardcoded relative_regions and relative_regions_nums - Load from config.get_relative_regions() and get_relative_regions_nums() - RecognizeMonster stores them as instance attributes in __init__ - Config values match existing hardcoded values exactly: - monsters: 6 zones (0.00-0.13, 0.12-0.25, 0.24-0.37, 0.63-0.76, 0.75-0.88, 0.87-1.00) - numbers: 6 zones (0.03-0.14, 0.16-0.27, 0.29-0.40, 0.61-0.72, 0.73-0.84, 0.86-0.97) Benefits: - Single source of truth in config/settings.py - Support custom recognition zones via config/recognition_zones.json - Consistent with DEFAULT_RECOGNITION_ZONES structure
…r three-package structure
…test_predict, add cannotsim hidden imports - recognize.py: zones = RECOGNITION_PARAMS.get(mode) if mode != 'WIN' else None prevents KeyError for WIN; add results=[] before if/else splits; detect zones for all modes but only use detected_zones for WIN region split - test_predict.py: .model → .session (ONNX uses session not model attr) - dialogs/__init__.py: explicit re-export to fix F401 unused import - cannotmax.spec: add cannotsim to hiddenimports for packaged subprocess call - main_window.py: use -m cannotsim.main_sim in subprocess (already correct)
liemark
force-pushed
the
main
branch
3 times, most recently
from
May 4, 2026 23:24
e41373c to
33706c0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概况
彻底架构重构,将 CannotMax 从平铺脚本集合改造为标准 Python 包(
src/cannotmax/),包含 10 个子包、统一连接器工厂、配置驱动识别、78 个自动化测试、预提交钩子和 CI 流水线。版本号 2.0.0-alpha.2。已完成的重构
包结构
src/cannotmax/,子包:config、core/connector、gui、models、training、pipelines、tools、simulator、utilsuv run cannotmax(原python main.py)uv run cannotmax tools <script>、uv run cannotmax pipelines <script>maafw/(约 50 MB 本地二进制),现由maafwPython 库提供(安装即附带二进制文件,无需额外配置)连接器架构
connector替代原有双连接器模式BaseConnector模板方法:ensure_connected()、_capture_internal()、_click_internal()core/connector/winrt_capture.py(重命名,未删除)识别系统
crop_ratio由config/app.json配置驱动,不再硬编码ROINotSelectedError错误类型、交互式ROISelectortools/select_crop_ratio.py:实现选择大致区域后自动计算怪物条 ROI 和六个怪物头像以及数字 ROI(相对原图比例的形式)模型与训练
embed_dim=256、num_heads=4、dropout=0.3GUI 改进
multi_instance.py):并行模拟器控制、崩溃检测、自动恢复测试
@pytest.mark.e2e(需模拟器)DevOps
package.py+cannotmax.spec已按重构后路径更新config/app.json集中管理运行时配置,缺失时自动从默认值创建Bug 修复
pc_3/4/5.png状态模板)class_to_idx.json加载(FIELD_FEATURE_COUNT=0),消除无关警告window_picker.py缺少 logger、pc_connector.pyexcept 缩进错误merge_data.py日期目录长度检查(19→20)console.py已内置_ensure_admin()自动提权)破坏性变更
main.py→uv run cannotmax(启动:uv run cannotmax)train.py→uv run cannotmax trainpython old_script.py直接运行不再可用maafw/目录已删除;pyproject.toml要求maafw>=5.10.2,安装时自动附带 MAA 二进制文件已知问题
pipelines/和tools/脚本从原分支直接移动,原分支也存在不适用最新版本的问题,本分支同样未修复测试结果