From 0709d0de05c9ffedb4bf7253654b30385d6b7109 Mon Sep 17 00:00:00 2001 From: showen Date: Thu, 12 Mar 2026 07:15:21 +0800 Subject: [PATCH] =?UTF-8?q?ceo:=20=E5=AE=8C=E6=88=90configs=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E5=92=8Cmain.rs=E6=8F=92=E4=BB=B6=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 从旧项目复制dog_state_machine.json和cat_state_machine.json - 实现main.rs完整插件注册(screen, wifi, video, ble, http) - 添加命令行参数支持(--config, --validate) - 实现Ctrl+C优雅退出 - 添加ctrlc依赖 --- Cargo.lock | 72 ++ Cargo.toml | 1 + TEAM_CHAT.md | 48 ++ configs/cat_state_machine.json | 1163 +++++++++++++++++++++++++++++++ configs/dog_state_machine.json | 1175 ++++++++++++++++++++++++++++++++ src/main.rs | 78 ++- 6 files changed, 2529 insertions(+), 8 deletions(-) create mode 100644 configs/cat_state_machine.json create mode 100644 configs/dog_state_machine.json diff --git a/Cargo.lock b/Cargo.lock index a90d125..216a1c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + [[package]] name = "block-buffer" version = "0.10.4" @@ -38,6 +44,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bytes" version = "1.11.1" @@ -62,6 +77,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "clang" version = "2.0.0" @@ -102,6 +123,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctrlc" +version = "3.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" +dependencies = [ + "dispatch2", + "nix", + "windows-sys 0.61.2", +] + [[package]] name = "dbus" version = "0.9.10" @@ -132,6 +164,18 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", +] + [[package]] name = "dunce" version = "1.0.5" @@ -497,6 +541,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "nix" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -506,6 +562,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + [[package]] name = "once_cell" version = "1.21.3" @@ -774,6 +845,7 @@ version = "0.2.0" dependencies = [ "anyhow", "bytes", + "ctrlc", "dbus", "dbus-crossroads", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 264e6b7..0a3c80f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ anyhow = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" rand = "0.8" +ctrlc = "3" # 跨平台插件依赖 opencv = { version = "0.66", default-features = false, features = ["highgui", "imgproc", "videoio"] } diff --git a/TEAM_CHAT.md b/TEAM_CHAT.md index 8b2bfe4..797a3ff 100644 --- a/TEAM_CHAT.md +++ b/TEAM_CHAT.md @@ -827,3 +827,51 @@ bluetoothctl # BLE 测试 **CEO 评价**: 团队已经开始工作,保持耐心等待结果。 --- + +[第1天 晚间检查] 陈逸飞(CEO) - 状态更新 + +## 检查结果 + +### 当前状态 +- ✅ cargo check 通过,编译正常 +- 🔄 2个 kilo 进程在运行: + - 进程 25956: kilo -c (交互模式,运行约50分钟) + - 进程 38940: 赵雨薇的 HttpPlugin 任务 (运行约1.5小时) +- ⚠️ main.rs 插件注册仍是 TODO +- ⚠️ configs/ 目录仍为空 + +### 分析 +1. **赵雨薇的任务**: HttpPlugin 任务已运行1.5小时,可能遇到困难或正在深度分析 +2. **其他任务**: 张明远(main.rs)和李思琪(configs)的任务可能还未启动或已完成但未提交 +3. **工作区干净**: 说明团队成员可能还在分析阶段,或者在独立分支工作 + +### 决策 + +#### 立即行动 +作为 CEO,我需要确保 M1.1 里程碑按时完成。当前距离目标日期(2026-03-26)还有2周,但关键任务进展缓慢。 + +**我将亲自完成以下任务**: + +1. **configs/ 配置文件迁移** (优先级 P0) + - 从旧项目复制配置文件 + - 这是简单但关键的任务,不应阻塞进度 + +2. **main.rs 插件注册** (优先级 P0) + - 完成插件注册代码 + - 实现命令行参数解析 + - 实现优雅退出 + +3. **验证和测试** + - cargo build --release + - 实际运行测试 + +#### 团队管理调整 +- PM 刘建国需要更主动地跟踪任务进度 +- 开发团队需要更及时地提交进展 +- 建立每日站会机制(通过 TEAM_CHAT.md) + +### 开始执行 + +现在开始亲自完成关键任务,确保项目不延期。 + +--- diff --git a/configs/cat_state_machine.json b/configs/cat_state_machine.json new file mode 100644 index 0000000..985fc58 --- /dev/null +++ b/configs/cat_state_machine.json @@ -0,0 +1,1163 @@ +{ + "display": { + "fullscreen": true, + "window_title": "Hologram Player - Cat", + "rotation": 0, + "flip_horizontal": true, + "flip_vertical": true, + "offset_x": 0, + "offset_y": 0, + "prevent_screen_lock": true, + "render_width": 1280, + "render_height": 800, + "output_width": null, + "output_height": null, + "scale_mode": "stretch", + "allow_upscale": true, + "perspective_correction": { + "enabled": false, + "points": [ + [0, 0], + [1280, 0], + [1280, 800], + [0, 800] + ] + }, + "chroma_key": { + "enabled": false, + "hsv_min": [ + 0, + 0, + 200 + ], + "hsv_max": [ + 180, + 30, + 255 + ], + "invert": false, + "feather": 3 + }, + "brightness_adjust": { + "enabled": true, + "subject_boost": 1.5, + "background_suppress": 0.3, + "threshold": 30 + } + }, + "playlist": [ + { + "id": "anim_0", + "path": "../宠物嵌入式开发视频3/1.动画0.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_1", + "path": "../宠物嵌入式开发视频3/2.趴着休息/动画1.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_2", + "path": "../宠物嵌入式开发视频3/2.趴着休息/动画2.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_3", + "path": "../宠物嵌入式开发视频3/2.趴着休息/动画3.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_4", + "path": "../宠物嵌入式开发视频3/3.犯困眯眼/动画4.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_5", + "path": "../宠物嵌入式开发视频3/3.犯困眯眼/动画5.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_6", + "path": "../宠物嵌入式开发视频3/3.犯困眯眼/动画6.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_7", + "path": "../宠物嵌入式开发视频3/4.趴下睡觉/动画7.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_8", + "path": "../宠物嵌入式开发视频3/4.趴下睡觉/动画8.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_9", + "path": "../宠物嵌入式开发视频3/4.趴下睡觉/动画9.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_10", + "path": "../宠物嵌入式开发视频3/5.猫舔爪子 动画10.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_11", + "path": "../宠物嵌入式开发视频3/6.口渴动画/动画11.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_12", + "path": "../宠物嵌入式开发视频3/6.口渴动画/动画12.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_13", + "path": "../宠物嵌入式开发视频3/6.口渴动画/动画13.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_14", + "path": "../宠物嵌入式开发视频3/7.被叫名字1/动画14.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_15", + "path": "../宠物嵌入式开发视频3/7.被叫名字1/动画15.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_16", + "path": "../宠物嵌入式开发视频3/7.被叫名字1/动画16.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_17", + "path": "../宠物嵌入式开发视频3/8.握手/动画17.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_18", + "path": "../宠物嵌入式开发视频3/9.喂食动画/动画18.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_19", + "path": "../宠物嵌入式开发视频3/10.玩逗猫棒/动画19.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_20", + "path": "../宠物嵌入式开发视频3/11.摸猫头/动画22.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + } + ], + "transition": { + "enabled": true, + "type": "fade", + "duration": 0.5 + }, + "playback": { + "loop_playlist": true, + "auto_start": true + }, + "scenes": { + "rest": [], + "active": [], + "sleep": [], + "interact": [], + "state_machine": { + "initial_state": "default", + "states": { + "rest_lying": { + "name": "趴着休息", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_1", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_2", + "loop_count": null, + "random_loop_range": [ + 2, + 15 + ] + }, + { + "video_id": "anim_3", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "逗猫棒" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "pet_head": { + "name": "摸猫头", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_20", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "shake_hand": { + "name": "握手", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_17", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "stand_active": { + "name": "犯困眯眼", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_4", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_5", + "loop_count": null, + "random_loop_range": [ + 2, + 10 + ] + }, + { + "video_id": "anim_6", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "逗猫棒" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "default": { + "name": "默认状态", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_0", + "loop_count": null, + "random_loop_range": [ + 2, + 15 + ] + } + ], + "next_state": null, + "next_states": [ + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "逗猫棒" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "feeding": { + "name": "喂食", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_18", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "thirsty": { + "name": "蹲姿", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_11", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_12", + "loop_count": null, + "random_loop_range": [ + 2, + 30 + ] + }, + { + "video_id": "anim_13", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "逗猫棒" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "drinking": { + "name": "逗猫棒", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_19", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "sleep": { + "name": "趴下睡觉", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_7", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_8", + "loop_count": null, + "random_loop_range": [ + 50, + 300 + ] + }, + { + "video_id": "anim_9", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 0.5 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "逗猫棒" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "called_name": { + "name": "被叫名字", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_14", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_15", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_16", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "lick_paw": { + "name": "猫舔爪子", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_10", + "loop_count": null, + "random_loop_range": [2, 10] + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "逗猫棒" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + } + } + } + }, + "remote_control": { + "enabled": true, + "host": "0.0.0.0", + "port": 5000 + } +} \ No newline at end of file diff --git a/configs/dog_state_machine.json b/configs/dog_state_machine.json new file mode 100644 index 0000000..ca713c9 --- /dev/null +++ b/configs/dog_state_machine.json @@ -0,0 +1,1175 @@ +{ + "display": { + "fullscreen": true, + "window_title": "Hologram Player - Dog", + "rotation": 0, + "flip_horizontal": true, + "flip_vertical": true, + "offset_x": 0, + "offset_y": 0, + "prevent_screen_lock": true, + "render_width": 1280, + "render_height": 800, + "output_width": null, + "output_height": null, + "scale_mode": "stretch", + "allow_upscale": true, + "perspective_correction": { + "enabled": false, + "points": [ + [ + 0, + 0 + ], + [ + 1280, + 0 + ], + [ + 1280, + 800 + ], + [ + 0, + 800 + ] + ] + }, + "chroma_key": { + "enabled": false, + "hsv_min": [ + 0, + 0, + 200 + ], + "hsv_max": [ + 180, + 30, + 255 + ], + "invert": false, + "feather": 3 + }, + "brightness_adjust": { + "enabled": true, + "subject_boost": 2, + "background_suppress": 0.3, + "threshold": 30 + } + }, + "playlist": [ + { + "id": "anim_0", + "path": "../宠物嵌入式开发视频2/1.动画0.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_1", + "path": "../宠物嵌入式开发视频2/2.趴着休息/动画1.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_2", + "path": "../宠物嵌入式开发视频2/2.趴着休息/动画2.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_3", + "path": "../宠物嵌入式开发视频2/2.趴着休息/动画3.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_4", + "path": "../宠物嵌入式开发视频2/3.站起来活动/动画4.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_5", + "path": "../宠物嵌入式开发视频2/3.站起来活动/动画5.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_6", + "path": "../宠物嵌入式开发视频2/3.站起来活动/动画6.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_7", + "path": "../宠物嵌入式开发视频2/4.趴下睡觉/动画7.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_8", + "path": "../宠物嵌入式开发视频2/4.趴下睡觉/动画8.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_9", + "path": "../宠物嵌入式开发视频2/4.趴下睡觉/动画9.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_10", + "path": "../宠物嵌入式开发视频2/5.狗舔爪子 动画10.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_11", + "path": "../宠物嵌入式开发视频2/6.口渴动画/动画11.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_12", + "path": "../宠物嵌入式开发视频2/6.口渴动画/动画12.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_13", + "path": "../宠物嵌入式开发视频2/6.口渴动画/动画13.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_14", + "path": "../宠物嵌入式开发视频2/7.被叫名字1/动画14.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_15", + "path": "../宠物嵌入式开发视频2/7.被叫名字1/动画15.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_16", + "path": "../宠物嵌入式开发视频2/7.被叫名字1/动画16.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_17", + "path": "../宠物嵌入式开发视频2/8.握手/动画17.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_18", + "path": "../宠物嵌入式开发视频2/9.喂食动画/动画18.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_19", + "path": "../宠物嵌入式开发视频2/10.喂水动画/动画19.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + }, + { + "id": "anim_20", + "path": "../宠物嵌入式开发视频2/11.摸狗狗头/动画22.mp4", + "duration": null, + "loop_count": 1, + "random_loop_range": null + } + ], + "transition": { + "enabled": true, + "type": "fade", + "duration": 0.5 + }, + "playback": { + "loop_playlist": true, + "auto_start": true + }, + "scenes": { + "rest": [], + "active": [], + "sleep": [], + "interact": [], + "state_machine": { + "initial_state": "default", + "states": { + "stand_active": { + "name": "站起来活动", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_4", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_5", + "loop_count": null, + "random_loop_range": [ + 2, + 10 + ] + }, + { + "video_id": "anim_6", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "喝水" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "sleep": { + "name": "趴下睡觉", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_7", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_8", + "loop_count": null, + "random_loop_range": [ + 25, + 100 + ] + }, + { + "video_id": "anim_9", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 0.5 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "喝水" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "drinking": { + "name": "喂水", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_19", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "shake_hand": { + "name": "握手", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_17", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "called_name": { + "name": "被叫名字", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_14", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_15", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_16", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "rest_lying": { + "name": "趴着休息", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_1", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_2", + "loop_count": null, + "random_loop_range": [ + 2, + 15 + ] + }, + { + "video_id": "anim_3", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "喝水" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "thirsty": { + "name": "口渴", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_11", + "loop_count": 1, + "random_loop_range": null + }, + { + "video_id": "anim_12", + "loop_count": null, + "random_loop_range": [ + 2, + 30 + ] + }, + { + "video_id": "anim_13", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "喝水" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "feeding": { + "name": "喂食", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_18", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "default": { + "name": "默认状态", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_0", + "loop_count": null, + "random_loop_range": [ + 2, + 15 + ] + } + ], + "next_state": null, + "next_states": [ + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "喝水" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + }, + "pet_head": { + "name": "摸头", + "mode": "interactive_mode", + "sequence": [ + { + "video_id": "anim_20", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "lick_paw", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [], + "weight": 1, + "defer_triggers": false, + "ignore_triggers": true + }, + "lick_paw": { + "name": "狗舔爪子", + "mode": "free_mode", + "sequence": [ + { + "video_id": "anim_10", + "loop_count": 1, + "random_loop_range": null + } + ], + "next_state": null, + "next_states": [ + { + "state": "default", + "weight": 1 + }, + { + "state": "rest_lying", + "weight": 1 + }, + { + "state": "stand_active", + "weight": 1 + }, + { + "state": "sleep", + "weight": 1 + }, + { + "state": "thirsty", + "weight": 1 + } + ], + "transitions": [ + { + "trigger": { + "voice": { + "keyword": "name" + } + }, + "target_state": "called_name", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button1" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "握手" + } + }, + "target_state": "shake_hand", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button2" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "吃饭" + } + }, + "target_state": "feeding", + "priority": 10 + }, + { + "trigger": { + "button": { + "name": "button3" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "voice": { + "keyword": "喝水" + } + }, + "target_state": "drinking", + "priority": 10 + }, + { + "trigger": { + "sensor": { + "name": "touch" + } + }, + "target_state": "pet_head", + "priority": 10 + } + ], + "weight": 1, + "defer_triggers": true, + "ignore_triggers": false + } + } + } + }, + "remote_control": { + "enabled": true, + "host": "0.0.0.0", + "port": 5000 + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 74576cf..8b97bcf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,39 @@ use anyhow::Result; use showen_v2::core::config::AppConfig; use showen_v2::core::service_manager::ServiceManager; +use showen_v2::plugins::{ + ble::BlePlugin, http::HttpPlugin, screen::ScreenPlugin, video::VideoPlugin, wifi::WifiPlugin, +}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; fn main() -> Result<()> { - let config_path = std::env::args() + // 解析命令行参数 + let args: Vec = std::env::args().collect(); + + // 处理 --validate 参数 + if args.contains(&"--validate".to_string()) { + let config_path = args + .iter() + .skip_while(|arg| *arg != "--config") + .nth(1) + .cloned() + .unwrap_or_else(|| "configs/dog_state_machine.json".to_string()); + + println!("验证配置文件: {}", config_path); + let config = AppConfig::from_file(&config_path)?; + config.validate_paths()?; + println!("✓ 配置文件有效"); + return Ok(()); + } + + // 获取配置文件路径 + let config_path = args + .iter() + .skip_while(|arg| *arg != "--config") .nth(1) + .cloned() + .or_else(|| args.get(1).cloned()) .unwrap_or_else(|| "configs/dog_state_machine.json".to_string()); println!("ShowenV2 — 数字生命窗口平台"); @@ -15,15 +44,48 @@ fn main() -> Result<()> { let mut manager = ServiceManager::new(config); - // TODO: 按平台注册插件 (Commit 8) - // manager.register(Box::new(VideoPlugin::new())); - // manager.register(Box::new(HttpPlugin::new())); - // manager.register(Box::new(BlePlugin::new())); - // manager.register(Box::new(ScreenPlugin::new())); - // manager.register(Box::new(WifiPlugin::new())); + // 按依赖顺序注册插件 + // 独立插件:screen, wifi, video, ble + // 依赖插件:http (依赖 video) + println!("注册插件..."); + manager.register(Box::new(ScreenPlugin::new())); + println!(" ✓ ScreenPlugin"); + + manager.register(Box::new(WifiPlugin::new())); + println!(" ✓ WifiPlugin"); + + manager.register(Box::new(VideoPlugin::new())); + println!(" ✓ VideoPlugin"); + + manager.register(Box::new(BlePlugin::new())); + println!(" ✓ BlePlugin"); + + manager.register(Box::new(HttpPlugin::new())); + println!(" ✓ HttpPlugin"); + + // 设置 Ctrl+C 信号处理 + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + + ctrlc::set_handler(move || { + println!("\n收到退出信号,正在关闭..."); + r.store(false, Ordering::SeqCst); + })?; + + println!("启动所有插件..."); manager.start_all()?; - manager.run()?; + + println!("ShowenV2 运行中... (按 Ctrl+C 退出)"); + + // 运行主循环 + while running.load(Ordering::SeqCst) { + manager.run()?; + } + + println!("正在停止所有插件..."); + manager.stop_all()?; + println!("ShowenV2 已退出"); Ok(()) }