Skip to content

Architecture

qingchenyouforcc edited this page Mar 11, 2026 · 6 revisions

架构概览 / Architecture

本页面介绍 NeurolingsCE 的整体代码架构和核心组件。

This page provides an overview of the NeurolingsCE codebase architecture and core components.

目录结构 / Directory Structure

NeurolingsCE/
├── src/app/                  # Qt 应用层(按职责分为 core/runtime/ui 三层)
│   ├── core/                 # 基础能力:资源加载、音效、HTTP API、压缩包导入、shijima引擎
│   ├── runtime/              # 运行时:环境同步、导入流程、生命周期、管理器
│   └── ui/                   # 界面:管理器窗口、托盘、桌宠窗口、对话框
├── src/platform/Platform/    # 平台抽象层(Windows/Linux/macOS)
├── include/shijima-qt/       # 公共头文件 + 嵌套UI转发头文件
├── src/app/core/shijima-engine/ # 集成看板娘模拟引擎(原libshijima)
├── libshimejifinder/         # [子模块] 资源包归档解压
├── cpp-httplib/              # [子模块] HTTP 服务器(header-only)
├── cmake/                    # CMake 辅助脚本(BundleDefaultMascot, GenerateLicenses)
├── src/assets/               # 内置默认看板娘精灵图 + XML 配置
├── src/packaging/            # 桌面入口、图标、.app 骨架
├── src/tools/                # Shell 辅助脚本
├── src/docs/                 # HTTP API 文档
├── src/resources/            # Windows 资源文件(.rc)
├── licenses/                 # 第三方许可证文本(构建时嵌入)
├── dev-docker/               # Fedora Docker 镜像(Windows 交叉编译)
└── .github/workflows/        # CI: debug (push/PR) + release (手动触发)

NeurolingsCE/ ├── src/app/ # Qt 应用层(按职责分为 core/runtime/ui 三层) │ ├── core/ # 基础能力:资源加载、音效、HTTP API、压缩包导入 │ ├── runtime/ # 运行时:环境同步、导入流程、生命周期、管理器 │ └── ui/ # 界面:管理器窗口、托盘、桌宠窗口、对话框 ├── src/platform/Platform/ # 平台抽象层(Windows/Linux/macOS) ├── include/shijima-qt/ # 公共头文件(与 src/app/ 结构对应) ├── libshijima/ # [子模块] 核心看板娘模拟引擎 ├── libshimejifinder/ # [子模块] 资源包导入解压 ├── cpp-httplib/ # [子模块] HTTP 服务器(header-only) ├── miniz/ # 轻量级 ZIP 库(用于 SimpleZipImporter) ├── cmake/ # CMake 辅助脚本(BundleDefaultMascot, GenerateLicenses) ├── translations/ # i18n 翻译文件 ├── src/assets/ # 内置默认看板娘精灵图 + XML 配置 ├── src/packaging/ # 桌面入口、图标、.app 骨架 ├── src/tools/ # Shell 辅助脚本 ├── src/docs/ # HTTP API 文档 ├── src/resources/ # Windows 资源文件(.rc)+ Qt 资源(.qrc) ├── licenses/ # 第三方许可证文本(构建时嵌入) ├── dev-docker/ # Fedora Docker 镜像(Windows 交叉编译) └── .github/workflows/ # CI: debug (push/PR) + release (手动触发)


## 核心类图 / Core Class Diagram

┌─────────────────────────────────────────────────────────────────┐ │ main.cc │ │ QApplication → 单实例检查 → ShijimaManager::defaultManager() │ └────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ ShijimaManager │ │ (PlatformWidget 单例) │ │ │ │ 职责 / Responsibilities: │ │ ├── 管理看板娘生命周期(生成、销毁、tick 循环) │ │ ├── 管理已加载的看板娘资源包 (MascotData) │ │ ├── 同步多屏幕环境信息 (environment) │ │ ├── 处理拖放导入 │ │ ├── 语言切换 │ │ └── 协调 HTTP API 和窗口观察器 │ │ │ │ 关键成员 / Key Members: │ │ ├── m_mascots: list<ShijimaWidget*> ← 活跃的看板娘实例 │ │ ├── m_loadedMascots: QMap<名称, MascotData*> │ │ ├── m_httpApi: ShijimaHttpApi ← HTTP REST API │ │ ├── m_windowObserver: ActiveWindowObserver ← 窗口追踪 │ │ ├── m_factory: shijima::mascot::factory ← 看板娘工厂 │ │ └── m_env: QMap<QScreen*, environment> ← 每屏幕环境 │ └──────┬──────────┬──────────┬──────────┬────────────────────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌────────────┐ ┌────────┐ ┌──────────┐ ┌────────────────────┐ │ShijimaWidget│ │MascotData│ │ShijimaHttpApi│ │ActiveWindowObserver│ │(看板娘窗口) │ │(资源数据) │ │(HTTP API) │ │(窗口追踪) │ └────────────┘ └────────┘ └──────────┘ └────────────────────┘


## 核心组件详解 / Core Components

### 1. ShijimaManager(看板娘管理器)

**文件**: `src/app/runtime/` 目录下的 Manager*.cc 文件 + `include/shijima-qt/ShijimaManager.hpp`

实现分散在多个职责切片文件中:
- `ManagerWindowSetup.cc` — 管理器窗口初始化与设置
- `ManagerLifecycle.cc` — 看板娘生命周期管理(spawn, kill)
- `ManagerMascotRuntime.cc` — 看板娘运行时调度
- `ManagerEnvironmentSync.cc` — 屏幕环境同步
- `ManagerImportWorkflow.cc` — 资源包导入流程
- `ManagerTickLoop.cc` — 主循环定时器

全局单例,通过 `ShijimaManager::defaultManager()` 访问。继承自 `PlatformWidget<QMainWindow>`。

**核心功能 / Key Functions:**

| 方法 | 说明 |
|------|------|
| `spawn(name)` | 生成指定名称的看板娘实例 |
| `killAll()` | 销毁所有看板娘 |
| `killAllButOne(widget/name)` | 保留一只,销毁其余 |
| `updateEnvironment()` | 同步所有屏幕的环境信息(位置、大小、工作区域) |
| `tick()` | 主循环回调,驱动所有看板娘的帧更新 |
| `import(path)` | 导入看板娘资源包 |
| `onTickSync(callback)` | 线程安全回调(HTTP API 线程使用) |

**Tick 循环 / Tick Loop:**
- 以 **25 FPS** 运行(硬编码在 libshijima 设计中)
- 通过 `QBasicTimer` 的 `timerEvent()` 驱动
- 每帧:更新环境 → tick 所有看板娘 → 处理跨线程回调

**线程安全 / Thread Safety:**
- `std::mutex` + `std::condition_variable` 保护跨线程操作
- HTTP API 在独立线程运行,通过 `onTickSync()` 安全地在主线程执行回调

### 2. ShijimaWidget(看板娘窗口)

**文件**: `src/app/ui/mascot/` 目录下的 MascotWidget*.cc 文件 + `include/shijima-qt/ShijimaWidget.hpp`

实现分散在多个职责切片文件中:
- `MascotWidgetRendering.cc` — 渲染与绘制
- `MascotWidgetInteraction.cc` — 鼠标交互与右键菜单
- `MascotWidgetTick.cc` — 帧更新与状态推进

继承自 `PlatformWidget<QWidget>`。每个看板娘实例对应一个透明无边框窗口。

**核心功能:**

| 功能 | 实现 |
|------|------|
| 渲染 | `paintEvent()` — 绘制当前帧精灵图,支持镜像 |
| 鼠标交互 | `mousePressEvent()` / `mouseReleaseEvent()` — 拖拽和右键菜单 |
| 帧更新 | `tick()` — 推进 libshijima 模拟状态,更新位置和图像 |
| Hit 测试 | `pointInside()` — 判断屏幕坐标是否在看板娘图像内 |
| 检查器 | `showInspector()` — 打开调试信息对话框 |

**Fall-Through 机制:**
- 追踪看板娘坠落距离(`m_fallTracking`)
- 当坠落超过 700 像素时启用 "穿越模式"(`m_fallThroughMode`),看板娘会落到屏幕最底部而非停在任务栏

**缩放 / Scaling:**
- `m_drawScale` — 绘制缩放比例
- 用户可通过管理器设置自定义缩放

### 3. MascotData(看板娘数据)

**文件**: `src/app/core/mascot/MascotData.cc` + `include/shijima-qt/MascotData.hpp`

封装单个看板娘资源包的数据:

| 属性 | 说明 |
|------|------|
| `name` | 看板娘名称(目录名) |
| `path` | 资源包路径 |
| `behaviorsXML` | 行为定义 XML |
| `actionsXML` | 动作定义 XML |
| `imgRoot` | 图片根目录 |
| `preview` | 预览图标 |
| `deletable` | 是否可删除(默认看板娘不可删除) |
| `id` | 唯一整数 ID |

### 4. AssetLoader(资源加载器)

**文件**: `src/app/core/assets/AssetLoader.cc` + `include/shijima-qt/AssetLoader.hpp`

单例模式,管理看板娘精灵图的加载和缓存。

| 方法 | 说明 |
|------|------|
| `loadAsset(path)` | 加载并缓存图片资源,返回 `Asset` 引用 |
| `unloadAssets(root)` | 卸载指定根目录下的所有缓存资源 |

### 5. Asset(精灵图资源)

**文件**: `src/app/core/assets/Asset.cc` + `include/shijima-qt/Asset.hpp`

封装单个精灵图帧:
- `m_image` / `m_mirrored` — 原始和镜像图像
- `m_offset` — 裁剪偏移
- `m_mask` / `m_mirroredMask` — Linux 上用于窗口区域遮罩的 `QBitmap`

### 6. ShijimaHttpApi(HTTP API)

**文件**: `src/app/core/http/ShijimaHttpApi.cc` + `include/shijima-qt/ShijimaHttpApi.hpp`

在独立线程启动 HTTP 服务器(默认 `127.0.0.1:32456`),提供 REST API 接口。

详细 API 文档见 [HTTP API](HTTP-API)。

### 7. ShijimaContextMenu(右键菜单)

**文件**: `src/app/ui/menus/ShijimaContextMenu.cc` + `ContextMenuActions.cc` + `include/shijima-qt/ShijimaContextMenu.hpp`

右键点击看板娘时弹出的上下文菜单,提供暂停、检查、分裂、关闭等操作。

### 8. SimpleZipImporter(ZIP 导入器)

**文件**: `src/app/core/import/SimpleZipImporter.cc` + `include/shijima-qt/SimpleZipImporter.hpp`

轻量级 ZIP 看板娘包导入器,基于 miniz。在 MSVC 构建中用于替代 libshimejifinder。

支持的布局:
1. **根级** — `actions.xml` + `behaviors.xml` + `img/` 直接在 ZIP 根目录
2. **Shimeji-ee** — 包含 `shimeji-ee.jar` + `conf/` + `img/<name>/`
3. **子目录** — `<name>/conf/actions.xml` + `img/`
4. **纯图片** — 只有 `shime1.png` ~ `shime46.png`(使用内置默认 XML)

### 9. SoundEffectManager(音效管理器)

**文件**: `src/app/core/audio/SoundEffectManager.cc` + `include/shijima-qt/SoundEffectManager.hpp`

可选功能(需要 `SHIJIMA_USE_QTMULTIMEDIA=1`),管理看板娘的音效播放。

### 10. PlatformWidget(平台窗口模板)

**文件**: `include/shijima-qt/PlatformWidget.hpp`

CRTP 模板类,为 `QWidget` / `QMainWindow` 添加跨平台行为:
- `ShowOnAllDesktops` — 确保窗口在所有虚拟桌面上可见
- 通过 `QTimer` 延迟调用 `Platform::showOnAllDesktops()`

```cpp
// 用法
class ShijimaManager : public PlatformWidget<QMainWindow> { ... };
class ShijimaWidget : public PlatformWidget<QWidget> { ... };

数据流 / Data Flow

启动流程 / Startup Flow

main()
  │
  ├── argc > 1? → shijimaRunCli()  // CLI 模式
  │
  ├── Platform::initialize()        // 平台初始化
  ├── QApplication 创建
  │
  ├── HTTP ping 127.0.0.1:32456    // 单实例检查
  │   ├── 响应成功 → 报错退出
  │   └── 无响应 → 继续
  │
  ├── ShijimaManager::defaultManager()->show()
  │   ├── 加载默认看板娘 (DefaultMascot.cc)
  │   ├── 扫描 mascots/ 目录加载已有资源包
  │   ├── 启动 HTTP API 服务器
  │   ├── 启动窗口观察器定时器
  │   └── 启动 tick 定时器 (25 FPS)
  │
  └── app.exec()  // Qt 事件循环

Tick 循环 / Tick Loop

timerEvent() (每 40ms = 25 FPS)
  │
  ├── updateEnvironment()           // 更新屏幕/窗口信息
  │   └── m_windowObserver.tick()   // 轮询前台窗口
  │
  ├── for each ShijimaWidget:
  │   └── widget->tick()
  │       ├── m_mascot->tick()      // libshijima 状态推进
  │       ├── updateOffsets()       // 计算绘制位置
  │       └── repaint()            // 触发 paintEvent
  │
  └── 处理 tickCallbacks           // HTTP API 的线程安全回调
      └── m_tickCallbackCompletion.notify_all()

资源包导入流程 / Mascot Import Flow

用户拖拽 .zip → dropEvent()
  │
  ├── SimpleZipImporter::import()    // 或 libshimejifinder
  │   ├── 解压 ZIP
  │   ├── 识别资源包布局
  │   └── 复制到 mascots/<name>/
  │
  ├── loadData(MascotData*)          // 解析 XML 注册到工厂
  │   └── m_factory.load_template()  // libshijima 加载模板
  │
  └── refreshListWidget()            // 刷新 UI 列表

子模块关系 / Submodule Relations

NeurolingsCE (Qt App)
  │
  ├── shijima-engine (集成引擎 / Integrated)
  │   ├── 看板娘行为模拟引擎
  │   ├── XML 解析 (rapidxml)
  │   ├── JavaScript 脚本 (duktape)
  │   └── shijima::mascot::manager / factory / environment
  │
  ├── libshimejifinder [子模块 / Submodule]
  │   ├── 资源包归档解压
  │   └── 依赖 libunarr + libarchive
  │
  └── cpp-httplib [子模块 / Submodule]
      └── HTTP 服务器/客户端 (header-only)

注意 / Note:

  • libshijima 上游不接受外部贡献(其 README 中明确声明)。本项目将引擎代码集成在 src/app/core/shijima-engine/ 中,本地修复直接在此目录进行。
  • 引擎使用 #include <shijima/...> 路径包含

代码组织约定 / Code Organization Conventions

分层结构 / Layered Structure

src/app/ 按职责分为三层:

层级 路径 职责
core src/app/core/ 基础能力:资源加载、音效、HTTP API、压缩包导入
runtime src/app/runtime/ 运行时逻辑:环境同步、导入流程、生命周期、管理器
ui src/app/ui/ 界面:管理器窗口、托盘、页面构建、桌宠窗口、对话框

实现文件命名 / Implementation File Naming

采用 "主体 + 职责" 的命名方式,将大型类拆分为多个职责切片:

命名模式 示例 说明
Manager*.cc ManagerImportWorkflow.cc ShijimaManager 的职责切片
MascotWidget*.cc MascotWidgetRendering.cc ShijimaWidget 的职责切片
ShijimaWindow*.cc ShijimaWindowBuilder.cc ShijimaManager 窗口相关

这种命名方式便于按文件名直接定位业务边界,避免单文件过大。

CLI 模式 / CLI Mode

文件: src/app/cli.cc

当传入命令行参数时 (argc > 1),程序进入 CLI 模式,通过 HTTP API 与正在运行的实例通信:

# 调用正在运行实例的 API
./NeurolingsCE <command> [args...]
NeurolingsCE (Qt App)
  │
  ├── libshijima (只读依赖 / Read-only)
  │   ├── 看板娘行为模拟引擎
  │   ├── XML 解析 (rapidxml)
  │   ├── JavaScript 脚本 (duktape)
  │   └── shijima::mascot::manager / factory / environment
  │
  ├── libshimejifinder (只读依赖 / Read-only)
  │   ├── 资源包归档解压
  │   └── 依赖 libunarr + libarchive
  │
  └── cpp-httplib (只读依赖 / Read-only)
      └── HTTP 服务器/客户端 (header-only)

注意 / Note: libshijima 不接受外部贡献(其 README 中明确声明)。作为只读依赖使用。

条件编译 / Conditional Compilation

宏 / Macro 说明
SHIJIMA_USE_QTMULTIMEDIA =1 启用音效,=0 禁用
SHIJIMA_WITH_SHIMEJIFINDER =1 启用 libshimejifinder 导入,=0 禁用
NEUROLINGSCE_VERSION 版本号字符串(如 "0.1.0"
WIN32 Windows 平台
__linux__ Linux 平台
__APPLE__ macOS 平台
NOMINMAX / WIN32_LEAN_AND_MEAN Windows 头文件精简

相关页面 / Related Pages

Clone this wiki locally