diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a060dd..32f5114 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,8 @@ qt_add_executable(QtDesktopPet src/character/CharacterPackage.cpp src/character/CharacterPackageLoader.h src/character/CharacterPackageLoader.cpp + src/character/CharacterPackageRepository.h + src/character/CharacterPackageRepository.cpp src/character/FrameAnimator.h src/character/FrameAnimator.cpp src/config/AIConfig.h diff --git a/README.md b/README.md index 6f51e05..f71f14c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ QtDesktopPet 是一个基于 Qt Widgets / C++17 的 Windows 桌面宠物原型 - 鼠标拖动 - 右键菜单退出和状态测试 - 置顶切换 -- `shiroko` 角色包读取 +- `resources/characters/shiroko` 默认角色包读取 - PNG 序列帧动画播放 - `idle` / `talk` / `think` / `sleep` / `happy` / `drag` / `error` 状态 - 托盘显示、隐藏、退出 @@ -74,13 +74,13 @@ cmake --build build/mingw-debug 当前默认角色包位于: ```text -shiroko/ +resources/characters/shiroko/ ``` -基本结构: +角色包按 `resources/characters//` 组织,后续新增角色包时放在同级子目录。基本结构: ```text -shiroko/ +resources/characters/shiroko/ character.json preview.png idle/ @@ -94,12 +94,6 @@ shiroko/ 当前素材版本为 `2.1.0-stable`,所有帧使用 512x512 透明画布。当前实现会加载当前角色包的各状态帧并按 `character.json` 中的 FPS 播放。 -后续计划将默认角色包位置整理为: - -```text -resources/characters/shiroko/ -``` - ## 配置和日志 应用配置保存到 Qt 标准配置目录: diff --git a/docs/Qt_DesktopPet_开发文档.md b/docs/Qt_DesktopPet_开发文档.md index cf291a2..550b2b8 100644 --- a/docs/Qt_DesktopPet_开发文档.md +++ b/docs/Qt_DesktopPet_开发文档.md @@ -203,7 +203,7 @@ DesktopPet/ ├── resources/ │ ├── icons/ │ └── characters/ - │ └── default_pet/ + │ └── / │ ├── character.json │ ├── preview.png │ ├── idle/ @@ -566,8 +566,8 @@ PNG 图片序列 + character.json 示例: ```text -characters/ - └── default_pet/ +resources/characters/ + └── / ├── character.json ├── preview.png ├── idle/ @@ -600,7 +600,7 @@ characters/ ```json { "schemaVersion": 1, - "id": "default_pet", + "id": "shiroko", "displayName": "默认桌宠", "author": "DesktopPet", "version": "1.0.0", @@ -1207,7 +1207,7 @@ conversation_history.json "locked": false }, "character": { - "current": "default_pet" + "current": "shiroko" }, "performance": { "mode": "standard", @@ -1471,7 +1471,7 @@ void Example::run() ```text 1. 创建 CharacterPackage 2. 创建 CharacterPackageLoader -3. 读取 resources/characters/default_pet/character.json +3. 读取 resources/characters/shiroko/character.json 4. 解析 states 5. 加载 idle 状态帧 6. 校验资源包 @@ -1684,7 +1684,6 @@ MIT License 开源 ```text 1. 设置页内 AI 连通性测试 2. 对话历史内存上限和可选持久化 -3. character.json 中 base、anchor、bubble offset 的解析与应用 -4. 角色包位置整理和角色切换 -5. 发布前素材授权确认与打包验证 +3. 角色包导入和角色切换 +4. 发布前素材授权确认与打包验证 ``` diff --git a/docs/implementation_plan.md b/docs/implementation_plan.md index 753ad3d..36acd49 100644 --- a/docs/implementation_plan.md +++ b/docs/implementation_plan.md @@ -84,12 +84,12 @@ cmake -S . -B build/mingw-debug -G Ninja ` ## 3. 角色包约定 -`shiroko` 目录作为当前默认角色包。 +`resources/characters/shiroko` 目录作为当前默认角色包。角色包按 `resources/characters//` 组织,后续新增角色包时放在同级子目录。 已检查到的结构: ```text -shiroko/ +resources/characters/shiroko/ ├── character.json ├── preview.png ├── README.md @@ -150,7 +150,7 @@ error :20 帧 2. 创建 CMakeLists.txt 3. 创建 main.cpp 4. 创建 src/、resources/ 等基础目录 -5. 决定 shiroko 是否移动到 resources/characters/shiroko +5. 建立 resources/characters/ 角色包目录约定 6. 创建最小 README.md 7. 确认 LICENSE 是否采用 MIT ``` @@ -169,7 +169,7 @@ error :20 帧 ```text 1. 是否创建 .gitignore 2. 是否创建 MIT LICENSE -3. 是否将 shiroko 移动到 resources/characters/shiroko +3. 是否将默认角色包作为文件型内置资源保留在 resources/characters/shiroko 4. 是否立即创建最小 Qt 工程 ``` @@ -236,7 +236,7 @@ error :20 帧 ```text 1. CharacterPackage 2. CharacterPackageLoader -3. 读取 shiroko/character.json +3. 读取 resources/characters/shiroko/character.json 4. 校验 schemaVersion 5. 校验 defaultState 6. 校验 states @@ -261,7 +261,7 @@ error :20 帧 验收标准: ```text -1. 能读取 shiroko/character.json +1. 能读取 resources/characters/shiroko/character.json 2. 能获取 idle 状态帧路径列表 3. 能显示 idle 第一帧 4. 不在 paintEvent 中加载图片 @@ -531,7 +531,7 @@ error :20 帧 3. 阶段 2A 角色包最小读取: 已有 CharacterPackage / CharacterPackageLoader - 能读取 shiroko/character.json 并收集状态帧路径 + 能读取 resources/characters/shiroko/character.json 并收集状态帧路径 4. 阶段 2B idle 帧动画: 已新增 AnimationClip / FrameAnimator @@ -574,11 +574,9 @@ error :20 帧 当前实现与计划仍存在差异: ```text -1. shiroko 角色包仍位于项目根目录 shiroko/,尚未移动到 resources/characters/shiroko -2. SettingsDialog 仍是最小设置界面,尚未包含 AI 测试按钮、角色选择和更完整的分区布局 -3. CharacterPackage 尚未解析并应用 character.json 中的 base、anchor、bubble offset -4. ConversationManager 请求上下文会截取最近 12 条历史,但内存中的 m_history 尚未做最大长度裁剪 -5. README 和开发文档已开始同步当前进度,但仍需随功能继续维护 +1. SettingsDialog 仍是最小设置界面,尚未包含完整角色切换流程和更完整的分区布局 +2. ConversationManager 请求上下文会截取最近 12 条历史,但内存中的 m_history 尚未做最大长度裁剪 +3. README 和开发文档已开始同步当前进度,但仍需随功能继续维护 ``` --- @@ -612,10 +610,8 @@ error :20 帧 ```text 1. 完善设置界面: - AI 配置和测试 - - 角色包路径和角色切换 -2. 解析并应用角色包 base / anchor / bubble 配置 -3. 评估是否移动 shiroko 到 resources/characters/shiroko -4. 补一轮可重复的稳定性与性能测试记录 + - 角色包导入和角色切换 +2. 补一轮可重复的稳定性与性能测试记录 ``` --- @@ -625,8 +621,7 @@ error :20 帧 后续开始写代码前,需要逐项确认: ```text -1. 是否把 shiroko 移动到 resources/characters/shiroko -2. shiroko 素材是否允许作为正式开源发布素材继续保留在仓库中 -3. 设置页下一步先做 AI 测试入口,还是先做角色包配置 -4. 是否需要把对话历史持久化保存,还是第一版只保留内存会话 +1. shiroko 素材是否允许作为正式开源发布素材继续保留在仓库中 +2. 设置页下一步先做 AI 测试入口,还是先做角色包配置 +3. 是否需要把对话历史持久化保存,还是第一版只保留内存会话 ``` diff --git a/resources/characters/.gitkeep b/resources/characters/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/resources/characters/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/shiroko/README.md b/resources/characters/shiroko/README.md similarity index 82% rename from shiroko/README.md rename to resources/characters/shiroko/README.md index 1d6c978..77d2d32 100644 --- a/shiroko/README.md +++ b/resources/characters/shiroko/README.md @@ -2,6 +2,6 @@ 按动画素材规范重新整理:所有帧均为 512x512 透明画布,未裁切角色本体;帧编号连续。 -帧数:idle 30,talk 30,think 30,sleep 30,drag 30,happy 20,error 20。 +帧数:idle 30,talk 20,think 30,sleep 30,drag 30,happy 20,error 20。 说明:本版采用稳定坐标系与关键帧扩展方式生成,用于动画调试和桌宠加载器测试。 diff --git a/shiroko/character.json b/resources/characters/shiroko/character.json similarity index 100% rename from shiroko/character.json rename to resources/characters/shiroko/character.json diff --git a/shiroko/drag/000.png b/resources/characters/shiroko/drag/000.png similarity index 100% rename from shiroko/drag/000.png rename to resources/characters/shiroko/drag/000.png diff --git a/shiroko/drag/001.png b/resources/characters/shiroko/drag/001.png similarity index 100% rename from shiroko/drag/001.png rename to resources/characters/shiroko/drag/001.png diff --git a/shiroko/drag/002.png b/resources/characters/shiroko/drag/002.png similarity index 100% rename from shiroko/drag/002.png rename to resources/characters/shiroko/drag/002.png diff --git a/shiroko/drag/003.png b/resources/characters/shiroko/drag/003.png similarity index 100% rename from shiroko/drag/003.png rename to resources/characters/shiroko/drag/003.png diff --git a/shiroko/drag/004.png b/resources/characters/shiroko/drag/004.png similarity index 100% rename from shiroko/drag/004.png rename to resources/characters/shiroko/drag/004.png diff --git a/shiroko/drag/005.png b/resources/characters/shiroko/drag/005.png similarity index 100% rename from shiroko/drag/005.png rename to resources/characters/shiroko/drag/005.png diff --git a/shiroko/drag/006.png b/resources/characters/shiroko/drag/006.png similarity index 100% rename from shiroko/drag/006.png rename to resources/characters/shiroko/drag/006.png diff --git a/shiroko/drag/007.png b/resources/characters/shiroko/drag/007.png similarity index 100% rename from shiroko/drag/007.png rename to resources/characters/shiroko/drag/007.png diff --git a/shiroko/drag/008.png b/resources/characters/shiroko/drag/008.png similarity index 100% rename from shiroko/drag/008.png rename to resources/characters/shiroko/drag/008.png diff --git a/shiroko/drag/009.png b/resources/characters/shiroko/drag/009.png similarity index 100% rename from shiroko/drag/009.png rename to resources/characters/shiroko/drag/009.png diff --git a/shiroko/drag/010.png b/resources/characters/shiroko/drag/010.png similarity index 100% rename from shiroko/drag/010.png rename to resources/characters/shiroko/drag/010.png diff --git a/shiroko/drag/011.png b/resources/characters/shiroko/drag/011.png similarity index 100% rename from shiroko/drag/011.png rename to resources/characters/shiroko/drag/011.png diff --git a/shiroko/drag/012.png b/resources/characters/shiroko/drag/012.png similarity index 100% rename from shiroko/drag/012.png rename to resources/characters/shiroko/drag/012.png diff --git a/shiroko/drag/013.png b/resources/characters/shiroko/drag/013.png similarity index 100% rename from shiroko/drag/013.png rename to resources/characters/shiroko/drag/013.png diff --git a/shiroko/drag/014.png b/resources/characters/shiroko/drag/014.png similarity index 100% rename from shiroko/drag/014.png rename to resources/characters/shiroko/drag/014.png diff --git a/shiroko/drag/015.png b/resources/characters/shiroko/drag/015.png similarity index 100% rename from shiroko/drag/015.png rename to resources/characters/shiroko/drag/015.png diff --git a/shiroko/drag/016.png b/resources/characters/shiroko/drag/016.png similarity index 100% rename from shiroko/drag/016.png rename to resources/characters/shiroko/drag/016.png diff --git a/shiroko/drag/017.png b/resources/characters/shiroko/drag/017.png similarity index 100% rename from shiroko/drag/017.png rename to resources/characters/shiroko/drag/017.png diff --git a/shiroko/drag/018.png b/resources/characters/shiroko/drag/018.png similarity index 100% rename from shiroko/drag/018.png rename to resources/characters/shiroko/drag/018.png diff --git a/shiroko/drag/019.png b/resources/characters/shiroko/drag/019.png similarity index 100% rename from shiroko/drag/019.png rename to resources/characters/shiroko/drag/019.png diff --git a/shiroko/drag/020.png b/resources/characters/shiroko/drag/020.png similarity index 100% rename from shiroko/drag/020.png rename to resources/characters/shiroko/drag/020.png diff --git a/shiroko/drag/021.png b/resources/characters/shiroko/drag/021.png similarity index 100% rename from shiroko/drag/021.png rename to resources/characters/shiroko/drag/021.png diff --git a/shiroko/drag/022.png b/resources/characters/shiroko/drag/022.png similarity index 100% rename from shiroko/drag/022.png rename to resources/characters/shiroko/drag/022.png diff --git a/shiroko/drag/023.png b/resources/characters/shiroko/drag/023.png similarity index 100% rename from shiroko/drag/023.png rename to resources/characters/shiroko/drag/023.png diff --git a/shiroko/drag/024.png b/resources/characters/shiroko/drag/024.png similarity index 100% rename from shiroko/drag/024.png rename to resources/characters/shiroko/drag/024.png diff --git a/shiroko/drag/025.png b/resources/characters/shiroko/drag/025.png similarity index 100% rename from shiroko/drag/025.png rename to resources/characters/shiroko/drag/025.png diff --git a/shiroko/drag/026.png b/resources/characters/shiroko/drag/026.png similarity index 100% rename from shiroko/drag/026.png rename to resources/characters/shiroko/drag/026.png diff --git a/shiroko/drag/027.png b/resources/characters/shiroko/drag/027.png similarity index 100% rename from shiroko/drag/027.png rename to resources/characters/shiroko/drag/027.png diff --git a/shiroko/drag/028.png b/resources/characters/shiroko/drag/028.png similarity index 100% rename from shiroko/drag/028.png rename to resources/characters/shiroko/drag/028.png diff --git a/shiroko/drag/029.png b/resources/characters/shiroko/drag/029.png similarity index 100% rename from shiroko/drag/029.png rename to resources/characters/shiroko/drag/029.png diff --git a/shiroko/error/000.png b/resources/characters/shiroko/error/000.png similarity index 100% rename from shiroko/error/000.png rename to resources/characters/shiroko/error/000.png diff --git a/shiroko/error/001.png b/resources/characters/shiroko/error/001.png similarity index 100% rename from shiroko/error/001.png rename to resources/characters/shiroko/error/001.png diff --git a/shiroko/error/002.png b/resources/characters/shiroko/error/002.png similarity index 100% rename from shiroko/error/002.png rename to resources/characters/shiroko/error/002.png diff --git a/shiroko/error/003.png b/resources/characters/shiroko/error/003.png similarity index 100% rename from shiroko/error/003.png rename to resources/characters/shiroko/error/003.png diff --git a/shiroko/error/004.png b/resources/characters/shiroko/error/004.png similarity index 100% rename from shiroko/error/004.png rename to resources/characters/shiroko/error/004.png diff --git a/shiroko/error/005.png b/resources/characters/shiroko/error/005.png similarity index 100% rename from shiroko/error/005.png rename to resources/characters/shiroko/error/005.png diff --git a/shiroko/error/006.png b/resources/characters/shiroko/error/006.png similarity index 100% rename from shiroko/error/006.png rename to resources/characters/shiroko/error/006.png diff --git a/shiroko/error/007.png b/resources/characters/shiroko/error/007.png similarity index 100% rename from shiroko/error/007.png rename to resources/characters/shiroko/error/007.png diff --git a/shiroko/error/008.png b/resources/characters/shiroko/error/008.png similarity index 100% rename from shiroko/error/008.png rename to resources/characters/shiroko/error/008.png diff --git a/shiroko/error/009.png b/resources/characters/shiroko/error/009.png similarity index 100% rename from shiroko/error/009.png rename to resources/characters/shiroko/error/009.png diff --git a/shiroko/error/010.png b/resources/characters/shiroko/error/010.png similarity index 100% rename from shiroko/error/010.png rename to resources/characters/shiroko/error/010.png diff --git a/shiroko/error/011.png b/resources/characters/shiroko/error/011.png similarity index 100% rename from shiroko/error/011.png rename to resources/characters/shiroko/error/011.png diff --git a/shiroko/error/012.png b/resources/characters/shiroko/error/012.png similarity index 100% rename from shiroko/error/012.png rename to resources/characters/shiroko/error/012.png diff --git a/shiroko/error/013.png b/resources/characters/shiroko/error/013.png similarity index 100% rename from shiroko/error/013.png rename to resources/characters/shiroko/error/013.png diff --git a/shiroko/error/014.png b/resources/characters/shiroko/error/014.png similarity index 100% rename from shiroko/error/014.png rename to resources/characters/shiroko/error/014.png diff --git a/shiroko/error/015.png b/resources/characters/shiroko/error/015.png similarity index 100% rename from shiroko/error/015.png rename to resources/characters/shiroko/error/015.png diff --git a/shiroko/error/016.png b/resources/characters/shiroko/error/016.png similarity index 100% rename from shiroko/error/016.png rename to resources/characters/shiroko/error/016.png diff --git a/shiroko/error/017.png b/resources/characters/shiroko/error/017.png similarity index 100% rename from shiroko/error/017.png rename to resources/characters/shiroko/error/017.png diff --git a/shiroko/error/018.png b/resources/characters/shiroko/error/018.png similarity index 100% rename from shiroko/error/018.png rename to resources/characters/shiroko/error/018.png diff --git a/shiroko/error/019.png b/resources/characters/shiroko/error/019.png similarity index 100% rename from shiroko/error/019.png rename to resources/characters/shiroko/error/019.png diff --git a/shiroko/happy/000.png b/resources/characters/shiroko/happy/000.png similarity index 100% rename from shiroko/happy/000.png rename to resources/characters/shiroko/happy/000.png diff --git a/shiroko/happy/001.png b/resources/characters/shiroko/happy/001.png similarity index 100% rename from shiroko/happy/001.png rename to resources/characters/shiroko/happy/001.png diff --git a/shiroko/happy/002.png b/resources/characters/shiroko/happy/002.png similarity index 100% rename from shiroko/happy/002.png rename to resources/characters/shiroko/happy/002.png diff --git a/shiroko/happy/003.png b/resources/characters/shiroko/happy/003.png similarity index 100% rename from shiroko/happy/003.png rename to resources/characters/shiroko/happy/003.png diff --git a/shiroko/happy/004.png b/resources/characters/shiroko/happy/004.png similarity index 100% rename from shiroko/happy/004.png rename to resources/characters/shiroko/happy/004.png diff --git a/shiroko/happy/005.png b/resources/characters/shiroko/happy/005.png similarity index 100% rename from shiroko/happy/005.png rename to resources/characters/shiroko/happy/005.png diff --git a/shiroko/happy/006.png b/resources/characters/shiroko/happy/006.png similarity index 100% rename from shiroko/happy/006.png rename to resources/characters/shiroko/happy/006.png diff --git a/shiroko/happy/007.png b/resources/characters/shiroko/happy/007.png similarity index 100% rename from shiroko/happy/007.png rename to resources/characters/shiroko/happy/007.png diff --git a/shiroko/happy/008.png b/resources/characters/shiroko/happy/008.png similarity index 100% rename from shiroko/happy/008.png rename to resources/characters/shiroko/happy/008.png diff --git a/shiroko/happy/009.png b/resources/characters/shiroko/happy/009.png similarity index 100% rename from shiroko/happy/009.png rename to resources/characters/shiroko/happy/009.png diff --git a/shiroko/happy/010.png b/resources/characters/shiroko/happy/010.png similarity index 100% rename from shiroko/happy/010.png rename to resources/characters/shiroko/happy/010.png diff --git a/shiroko/happy/011.png b/resources/characters/shiroko/happy/011.png similarity index 100% rename from shiroko/happy/011.png rename to resources/characters/shiroko/happy/011.png diff --git a/shiroko/happy/012.png b/resources/characters/shiroko/happy/012.png similarity index 100% rename from shiroko/happy/012.png rename to resources/characters/shiroko/happy/012.png diff --git a/shiroko/happy/013.png b/resources/characters/shiroko/happy/013.png similarity index 100% rename from shiroko/happy/013.png rename to resources/characters/shiroko/happy/013.png diff --git a/shiroko/happy/014.png b/resources/characters/shiroko/happy/014.png similarity index 100% rename from shiroko/happy/014.png rename to resources/characters/shiroko/happy/014.png diff --git a/shiroko/happy/015.png b/resources/characters/shiroko/happy/015.png similarity index 100% rename from shiroko/happy/015.png rename to resources/characters/shiroko/happy/015.png diff --git a/shiroko/happy/016.png b/resources/characters/shiroko/happy/016.png similarity index 100% rename from shiroko/happy/016.png rename to resources/characters/shiroko/happy/016.png diff --git a/shiroko/happy/017.png b/resources/characters/shiroko/happy/017.png similarity index 100% rename from shiroko/happy/017.png rename to resources/characters/shiroko/happy/017.png diff --git a/shiroko/happy/018.png b/resources/characters/shiroko/happy/018.png similarity index 100% rename from shiroko/happy/018.png rename to resources/characters/shiroko/happy/018.png diff --git a/shiroko/happy/019.png b/resources/characters/shiroko/happy/019.png similarity index 100% rename from shiroko/happy/019.png rename to resources/characters/shiroko/happy/019.png diff --git a/shiroko/idle/000.png b/resources/characters/shiroko/idle/000.png similarity index 100% rename from shiroko/idle/000.png rename to resources/characters/shiroko/idle/000.png diff --git a/shiroko/idle/001.png b/resources/characters/shiroko/idle/001.png similarity index 100% rename from shiroko/idle/001.png rename to resources/characters/shiroko/idle/001.png diff --git a/shiroko/idle/002.png b/resources/characters/shiroko/idle/002.png similarity index 100% rename from shiroko/idle/002.png rename to resources/characters/shiroko/idle/002.png diff --git a/shiroko/idle/003.png b/resources/characters/shiroko/idle/003.png similarity index 100% rename from shiroko/idle/003.png rename to resources/characters/shiroko/idle/003.png diff --git a/shiroko/idle/004.png b/resources/characters/shiroko/idle/004.png similarity index 100% rename from shiroko/idle/004.png rename to resources/characters/shiroko/idle/004.png diff --git a/shiroko/idle/005.png b/resources/characters/shiroko/idle/005.png similarity index 100% rename from shiroko/idle/005.png rename to resources/characters/shiroko/idle/005.png diff --git a/shiroko/idle/006.png b/resources/characters/shiroko/idle/006.png similarity index 100% rename from shiroko/idle/006.png rename to resources/characters/shiroko/idle/006.png diff --git a/shiroko/idle/007.png b/resources/characters/shiroko/idle/007.png similarity index 100% rename from shiroko/idle/007.png rename to resources/characters/shiroko/idle/007.png diff --git a/shiroko/idle/008.png b/resources/characters/shiroko/idle/008.png similarity index 100% rename from shiroko/idle/008.png rename to resources/characters/shiroko/idle/008.png diff --git a/shiroko/idle/009.png b/resources/characters/shiroko/idle/009.png similarity index 100% rename from shiroko/idle/009.png rename to resources/characters/shiroko/idle/009.png diff --git a/shiroko/idle/010.png b/resources/characters/shiroko/idle/010.png similarity index 100% rename from shiroko/idle/010.png rename to resources/characters/shiroko/idle/010.png diff --git a/shiroko/idle/011.png b/resources/characters/shiroko/idle/011.png similarity index 100% rename from shiroko/idle/011.png rename to resources/characters/shiroko/idle/011.png diff --git a/shiroko/idle/012.png b/resources/characters/shiroko/idle/012.png similarity index 100% rename from shiroko/idle/012.png rename to resources/characters/shiroko/idle/012.png diff --git a/shiroko/idle/013.png b/resources/characters/shiroko/idle/013.png similarity index 100% rename from shiroko/idle/013.png rename to resources/characters/shiroko/idle/013.png diff --git a/shiroko/idle/014.png b/resources/characters/shiroko/idle/014.png similarity index 100% rename from shiroko/idle/014.png rename to resources/characters/shiroko/idle/014.png diff --git a/shiroko/idle/015.png b/resources/characters/shiroko/idle/015.png similarity index 100% rename from shiroko/idle/015.png rename to resources/characters/shiroko/idle/015.png diff --git a/shiroko/idle/016.png b/resources/characters/shiroko/idle/016.png similarity index 100% rename from shiroko/idle/016.png rename to resources/characters/shiroko/idle/016.png diff --git a/shiroko/idle/017.png b/resources/characters/shiroko/idle/017.png similarity index 100% rename from shiroko/idle/017.png rename to resources/characters/shiroko/idle/017.png diff --git a/shiroko/idle/018.png b/resources/characters/shiroko/idle/018.png similarity index 100% rename from shiroko/idle/018.png rename to resources/characters/shiroko/idle/018.png diff --git a/shiroko/idle/019.png b/resources/characters/shiroko/idle/019.png similarity index 100% rename from shiroko/idle/019.png rename to resources/characters/shiroko/idle/019.png diff --git a/shiroko/idle/020.png b/resources/characters/shiroko/idle/020.png similarity index 100% rename from shiroko/idle/020.png rename to resources/characters/shiroko/idle/020.png diff --git a/shiroko/idle/021.png b/resources/characters/shiroko/idle/021.png similarity index 100% rename from shiroko/idle/021.png rename to resources/characters/shiroko/idle/021.png diff --git a/shiroko/idle/022.png b/resources/characters/shiroko/idle/022.png similarity index 100% rename from shiroko/idle/022.png rename to resources/characters/shiroko/idle/022.png diff --git a/shiroko/idle/023.png b/resources/characters/shiroko/idle/023.png similarity index 100% rename from shiroko/idle/023.png rename to resources/characters/shiroko/idle/023.png diff --git a/shiroko/idle/024.png b/resources/characters/shiroko/idle/024.png similarity index 100% rename from shiroko/idle/024.png rename to resources/characters/shiroko/idle/024.png diff --git a/shiroko/idle/025.png b/resources/characters/shiroko/idle/025.png similarity index 100% rename from shiroko/idle/025.png rename to resources/characters/shiroko/idle/025.png diff --git a/shiroko/idle/026.png b/resources/characters/shiroko/idle/026.png similarity index 100% rename from shiroko/idle/026.png rename to resources/characters/shiroko/idle/026.png diff --git a/shiroko/idle/027.png b/resources/characters/shiroko/idle/027.png similarity index 100% rename from shiroko/idle/027.png rename to resources/characters/shiroko/idle/027.png diff --git a/shiroko/idle/028.png b/resources/characters/shiroko/idle/028.png similarity index 100% rename from shiroko/idle/028.png rename to resources/characters/shiroko/idle/028.png diff --git a/shiroko/idle/029.png b/resources/characters/shiroko/idle/029.png similarity index 100% rename from shiroko/idle/029.png rename to resources/characters/shiroko/idle/029.png diff --git a/shiroko/preview.png b/resources/characters/shiroko/preview.png similarity index 100% rename from shiroko/preview.png rename to resources/characters/shiroko/preview.png diff --git a/shiroko/sleep/000.png b/resources/characters/shiroko/sleep/000.png similarity index 100% rename from shiroko/sleep/000.png rename to resources/characters/shiroko/sleep/000.png diff --git a/shiroko/sleep/001.png b/resources/characters/shiroko/sleep/001.png similarity index 100% rename from shiroko/sleep/001.png rename to resources/characters/shiroko/sleep/001.png diff --git a/shiroko/sleep/002.png b/resources/characters/shiroko/sleep/002.png similarity index 100% rename from shiroko/sleep/002.png rename to resources/characters/shiroko/sleep/002.png diff --git a/shiroko/sleep/003.png b/resources/characters/shiroko/sleep/003.png similarity index 100% rename from shiroko/sleep/003.png rename to resources/characters/shiroko/sleep/003.png diff --git a/shiroko/sleep/004.png b/resources/characters/shiroko/sleep/004.png similarity index 100% rename from shiroko/sleep/004.png rename to resources/characters/shiroko/sleep/004.png diff --git a/shiroko/sleep/005.png b/resources/characters/shiroko/sleep/005.png similarity index 100% rename from shiroko/sleep/005.png rename to resources/characters/shiroko/sleep/005.png diff --git a/shiroko/sleep/006.png b/resources/characters/shiroko/sleep/006.png similarity index 100% rename from shiroko/sleep/006.png rename to resources/characters/shiroko/sleep/006.png diff --git a/shiroko/sleep/007.png b/resources/characters/shiroko/sleep/007.png similarity index 100% rename from shiroko/sleep/007.png rename to resources/characters/shiroko/sleep/007.png diff --git a/shiroko/sleep/008.png b/resources/characters/shiroko/sleep/008.png similarity index 100% rename from shiroko/sleep/008.png rename to resources/characters/shiroko/sleep/008.png diff --git a/shiroko/sleep/009.png b/resources/characters/shiroko/sleep/009.png similarity index 100% rename from shiroko/sleep/009.png rename to resources/characters/shiroko/sleep/009.png diff --git a/shiroko/sleep/010.png b/resources/characters/shiroko/sleep/010.png similarity index 100% rename from shiroko/sleep/010.png rename to resources/characters/shiroko/sleep/010.png diff --git a/shiroko/sleep/011.png b/resources/characters/shiroko/sleep/011.png similarity index 100% rename from shiroko/sleep/011.png rename to resources/characters/shiroko/sleep/011.png diff --git a/shiroko/sleep/012.png b/resources/characters/shiroko/sleep/012.png similarity index 100% rename from shiroko/sleep/012.png rename to resources/characters/shiroko/sleep/012.png diff --git a/shiroko/sleep/013.png b/resources/characters/shiroko/sleep/013.png similarity index 100% rename from shiroko/sleep/013.png rename to resources/characters/shiroko/sleep/013.png diff --git a/shiroko/sleep/014.png b/resources/characters/shiroko/sleep/014.png similarity index 100% rename from shiroko/sleep/014.png rename to resources/characters/shiroko/sleep/014.png diff --git a/shiroko/sleep/015.png b/resources/characters/shiroko/sleep/015.png similarity index 100% rename from shiroko/sleep/015.png rename to resources/characters/shiroko/sleep/015.png diff --git a/shiroko/sleep/016.png b/resources/characters/shiroko/sleep/016.png similarity index 100% rename from shiroko/sleep/016.png rename to resources/characters/shiroko/sleep/016.png diff --git a/shiroko/sleep/017.png b/resources/characters/shiroko/sleep/017.png similarity index 100% rename from shiroko/sleep/017.png rename to resources/characters/shiroko/sleep/017.png diff --git a/shiroko/sleep/018.png b/resources/characters/shiroko/sleep/018.png similarity index 100% rename from shiroko/sleep/018.png rename to resources/characters/shiroko/sleep/018.png diff --git a/shiroko/sleep/019.png b/resources/characters/shiroko/sleep/019.png similarity index 100% rename from shiroko/sleep/019.png rename to resources/characters/shiroko/sleep/019.png diff --git a/shiroko/sleep/020.png b/resources/characters/shiroko/sleep/020.png similarity index 100% rename from shiroko/sleep/020.png rename to resources/characters/shiroko/sleep/020.png diff --git a/shiroko/sleep/021.png b/resources/characters/shiroko/sleep/021.png similarity index 100% rename from shiroko/sleep/021.png rename to resources/characters/shiroko/sleep/021.png diff --git a/shiroko/sleep/022.png b/resources/characters/shiroko/sleep/022.png similarity index 100% rename from shiroko/sleep/022.png rename to resources/characters/shiroko/sleep/022.png diff --git a/shiroko/sleep/023.png b/resources/characters/shiroko/sleep/023.png similarity index 100% rename from shiroko/sleep/023.png rename to resources/characters/shiroko/sleep/023.png diff --git a/shiroko/sleep/024.png b/resources/characters/shiroko/sleep/024.png similarity index 100% rename from shiroko/sleep/024.png rename to resources/characters/shiroko/sleep/024.png diff --git a/shiroko/sleep/025.png b/resources/characters/shiroko/sleep/025.png similarity index 100% rename from shiroko/sleep/025.png rename to resources/characters/shiroko/sleep/025.png diff --git a/shiroko/sleep/026.png b/resources/characters/shiroko/sleep/026.png similarity index 100% rename from shiroko/sleep/026.png rename to resources/characters/shiroko/sleep/026.png diff --git a/shiroko/sleep/027.png b/resources/characters/shiroko/sleep/027.png similarity index 100% rename from shiroko/sleep/027.png rename to resources/characters/shiroko/sleep/027.png diff --git a/shiroko/sleep/028.png b/resources/characters/shiroko/sleep/028.png similarity index 100% rename from shiroko/sleep/028.png rename to resources/characters/shiroko/sleep/028.png diff --git a/shiroko/sleep/029.png b/resources/characters/shiroko/sleep/029.png similarity index 100% rename from shiroko/sleep/029.png rename to resources/characters/shiroko/sleep/029.png diff --git a/shiroko/talk/000.png b/resources/characters/shiroko/talk/000.png similarity index 100% rename from shiroko/talk/000.png rename to resources/characters/shiroko/talk/000.png diff --git a/shiroko/talk/001.png b/resources/characters/shiroko/talk/001.png similarity index 100% rename from shiroko/talk/001.png rename to resources/characters/shiroko/talk/001.png diff --git a/shiroko/talk/002.png b/resources/characters/shiroko/talk/002.png similarity index 100% rename from shiroko/talk/002.png rename to resources/characters/shiroko/talk/002.png diff --git a/shiroko/talk/003.png b/resources/characters/shiroko/talk/003.png similarity index 100% rename from shiroko/talk/003.png rename to resources/characters/shiroko/talk/003.png diff --git a/shiroko/talk/004.png b/resources/characters/shiroko/talk/004.png similarity index 100% rename from shiroko/talk/004.png rename to resources/characters/shiroko/talk/004.png diff --git a/shiroko/talk/005.png b/resources/characters/shiroko/talk/005.png similarity index 100% rename from shiroko/talk/005.png rename to resources/characters/shiroko/talk/005.png diff --git a/shiroko/talk/006.png b/resources/characters/shiroko/talk/006.png similarity index 100% rename from shiroko/talk/006.png rename to resources/characters/shiroko/talk/006.png diff --git a/shiroko/talk/007.png b/resources/characters/shiroko/talk/007.png similarity index 100% rename from shiroko/talk/007.png rename to resources/characters/shiroko/talk/007.png diff --git a/shiroko/talk/008.png b/resources/characters/shiroko/talk/008.png similarity index 100% rename from shiroko/talk/008.png rename to resources/characters/shiroko/talk/008.png diff --git a/shiroko/talk/009.png b/resources/characters/shiroko/talk/009.png similarity index 100% rename from shiroko/talk/009.png rename to resources/characters/shiroko/talk/009.png diff --git a/shiroko/talk/010.png b/resources/characters/shiroko/talk/010.png similarity index 100% rename from shiroko/talk/010.png rename to resources/characters/shiroko/talk/010.png diff --git a/shiroko/talk/011.png b/resources/characters/shiroko/talk/011.png similarity index 100% rename from shiroko/talk/011.png rename to resources/characters/shiroko/talk/011.png diff --git a/shiroko/talk/012.png b/resources/characters/shiroko/talk/012.png similarity index 100% rename from shiroko/talk/012.png rename to resources/characters/shiroko/talk/012.png diff --git a/shiroko/talk/013.png b/resources/characters/shiroko/talk/013.png similarity index 100% rename from shiroko/talk/013.png rename to resources/characters/shiroko/talk/013.png diff --git a/shiroko/talk/014.png b/resources/characters/shiroko/talk/014.png similarity index 100% rename from shiroko/talk/014.png rename to resources/characters/shiroko/talk/014.png diff --git a/shiroko/talk/015.png b/resources/characters/shiroko/talk/015.png similarity index 100% rename from shiroko/talk/015.png rename to resources/characters/shiroko/talk/015.png diff --git a/shiroko/talk/016.png b/resources/characters/shiroko/talk/016.png similarity index 100% rename from shiroko/talk/016.png rename to resources/characters/shiroko/talk/016.png diff --git a/shiroko/talk/017.png b/resources/characters/shiroko/talk/017.png similarity index 100% rename from shiroko/talk/017.png rename to resources/characters/shiroko/talk/017.png diff --git a/shiroko/talk/018.png b/resources/characters/shiroko/talk/018.png similarity index 100% rename from shiroko/talk/018.png rename to resources/characters/shiroko/talk/018.png diff --git a/shiroko/talk/019.png b/resources/characters/shiroko/talk/019.png similarity index 100% rename from shiroko/talk/019.png rename to resources/characters/shiroko/talk/019.png diff --git a/shiroko/think/000.png b/resources/characters/shiroko/think/000.png similarity index 100% rename from shiroko/think/000.png rename to resources/characters/shiroko/think/000.png diff --git a/shiroko/think/001.png b/resources/characters/shiroko/think/001.png similarity index 100% rename from shiroko/think/001.png rename to resources/characters/shiroko/think/001.png diff --git a/shiroko/think/002.png b/resources/characters/shiroko/think/002.png similarity index 100% rename from shiroko/think/002.png rename to resources/characters/shiroko/think/002.png diff --git a/shiroko/think/003.png b/resources/characters/shiroko/think/003.png similarity index 100% rename from shiroko/think/003.png rename to resources/characters/shiroko/think/003.png diff --git a/shiroko/think/004.png b/resources/characters/shiroko/think/004.png similarity index 100% rename from shiroko/think/004.png rename to resources/characters/shiroko/think/004.png diff --git a/shiroko/think/005.png b/resources/characters/shiroko/think/005.png similarity index 100% rename from shiroko/think/005.png rename to resources/characters/shiroko/think/005.png diff --git a/shiroko/think/006.png b/resources/characters/shiroko/think/006.png similarity index 100% rename from shiroko/think/006.png rename to resources/characters/shiroko/think/006.png diff --git a/shiroko/think/007.png b/resources/characters/shiroko/think/007.png similarity index 100% rename from shiroko/think/007.png rename to resources/characters/shiroko/think/007.png diff --git a/shiroko/think/008.png b/resources/characters/shiroko/think/008.png similarity index 100% rename from shiroko/think/008.png rename to resources/characters/shiroko/think/008.png diff --git a/shiroko/think/009.png b/resources/characters/shiroko/think/009.png similarity index 100% rename from shiroko/think/009.png rename to resources/characters/shiroko/think/009.png diff --git a/shiroko/think/010.png b/resources/characters/shiroko/think/010.png similarity index 100% rename from shiroko/think/010.png rename to resources/characters/shiroko/think/010.png diff --git a/shiroko/think/011.png b/resources/characters/shiroko/think/011.png similarity index 100% rename from shiroko/think/011.png rename to resources/characters/shiroko/think/011.png diff --git a/shiroko/think/012.png b/resources/characters/shiroko/think/012.png similarity index 100% rename from shiroko/think/012.png rename to resources/characters/shiroko/think/012.png diff --git a/shiroko/think/013.png b/resources/characters/shiroko/think/013.png similarity index 100% rename from shiroko/think/013.png rename to resources/characters/shiroko/think/013.png diff --git a/shiroko/think/014.png b/resources/characters/shiroko/think/014.png similarity index 100% rename from shiroko/think/014.png rename to resources/characters/shiroko/think/014.png diff --git a/shiroko/think/015.png b/resources/characters/shiroko/think/015.png similarity index 100% rename from shiroko/think/015.png rename to resources/characters/shiroko/think/015.png diff --git a/shiroko/think/016.png b/resources/characters/shiroko/think/016.png similarity index 100% rename from shiroko/think/016.png rename to resources/characters/shiroko/think/016.png diff --git a/shiroko/think/017.png b/resources/characters/shiroko/think/017.png similarity index 100% rename from shiroko/think/017.png rename to resources/characters/shiroko/think/017.png diff --git a/shiroko/think/018.png b/resources/characters/shiroko/think/018.png similarity index 100% rename from shiroko/think/018.png rename to resources/characters/shiroko/think/018.png diff --git a/shiroko/think/019.png b/resources/characters/shiroko/think/019.png similarity index 100% rename from shiroko/think/019.png rename to resources/characters/shiroko/think/019.png diff --git a/shiroko/think/020.png b/resources/characters/shiroko/think/020.png similarity index 100% rename from shiroko/think/020.png rename to resources/characters/shiroko/think/020.png diff --git a/shiroko/think/021.png b/resources/characters/shiroko/think/021.png similarity index 100% rename from shiroko/think/021.png rename to resources/characters/shiroko/think/021.png diff --git a/shiroko/think/022.png b/resources/characters/shiroko/think/022.png similarity index 100% rename from shiroko/think/022.png rename to resources/characters/shiroko/think/022.png diff --git a/shiroko/think/023.png b/resources/characters/shiroko/think/023.png similarity index 100% rename from shiroko/think/023.png rename to resources/characters/shiroko/think/023.png diff --git a/shiroko/think/024.png b/resources/characters/shiroko/think/024.png similarity index 100% rename from shiroko/think/024.png rename to resources/characters/shiroko/think/024.png diff --git a/shiroko/think/025.png b/resources/characters/shiroko/think/025.png similarity index 100% rename from shiroko/think/025.png rename to resources/characters/shiroko/think/025.png diff --git a/shiroko/think/026.png b/resources/characters/shiroko/think/026.png similarity index 100% rename from shiroko/think/026.png rename to resources/characters/shiroko/think/026.png diff --git a/shiroko/think/027.png b/resources/characters/shiroko/think/027.png similarity index 100% rename from shiroko/think/027.png rename to resources/characters/shiroko/think/027.png diff --git a/shiroko/think/028.png b/resources/characters/shiroko/think/028.png similarity index 100% rename from shiroko/think/028.png rename to resources/characters/shiroko/think/028.png diff --git a/shiroko/think/029.png b/resources/characters/shiroko/think/029.png similarity index 100% rename from shiroko/think/029.png rename to resources/characters/shiroko/think/029.png diff --git a/src/character/CharacterPackageRepository.cpp b/src/character/CharacterPackageRepository.cpp new file mode 100644 index 0000000..b5f895a --- /dev/null +++ b/src/character/CharacterPackageRepository.cpp @@ -0,0 +1,89 @@ +#include "CharacterPackageRepository.h" + +#include +#include + +namespace +{ +bool isValidCharacterId(const QString &characterId) +{ + const QString trimmed = characterId.trimmed(); + return !trimmed.isEmpty() + && trimmed != QStringLiteral(".") + && trimmed != QStringLiteral("..") + && !trimmed.contains(QLatin1Char('/')) + && !trimmed.contains(QLatin1Char('\\')); +} +} + +QString CharacterPackageRepository::charactersRootPath() +{ + return QDir::cleanPath(QStringLiteral(PET_SOURCE_DIR) + QStringLiteral("/resources/characters")); +} + +QString CharacterPackageRepository::defaultCharacterId() +{ + return QStringLiteral("shiroko"); +} + +QString CharacterPackageRepository::defaultPackagePath() +{ + return packagePath(defaultCharacterId()); +} + +QString CharacterPackageRepository::defaultPreviewPath() +{ + return previewPath(defaultCharacterId()); +} + +QString CharacterPackageRepository::packagePath(const QString &characterId) +{ + const QString trimmed = characterId.trimmed(); + if (!isValidCharacterId(trimmed)) + { + return {}; + } + + return QDir(charactersRootPath()).filePath(trimmed); +} + +QString CharacterPackageRepository::previewPath(const QString &characterId) +{ + const QString path = packagePath(characterId); + if (path.isEmpty()) + { + return {}; + } + + return QDir(path).filePath(QStringLiteral("preview.png")); +} + +QStringList CharacterPackageRepository::availablePackageIds() +{ + const QDir rootDirectory(charactersRootPath()); + if (!rootDirectory.exists()) + { + return {}; + } + + const QFileInfoList entries = rootDirectory.entryInfoList( + QDir::Dirs | QDir::NoDotAndDotDot, + QDir::Name); + + QStringList packageIds; + for (const QFileInfo &entry : entries) + { + if (!isValidCharacterId(entry.fileName())) + { + continue; + } + + const QFileInfo manifest(QDir(entry.absoluteFilePath()).filePath(QStringLiteral("character.json"))); + if (manifest.isFile()) + { + packageIds.append(entry.fileName()); + } + } + + return packageIds; +} diff --git a/src/character/CharacterPackageRepository.h b/src/character/CharacterPackageRepository.h new file mode 100644 index 0000000..87eff7c --- /dev/null +++ b/src/character/CharacterPackageRepository.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +class CharacterPackageRepository +{ +public: + static QString charactersRootPath(); + static QString defaultCharacterId(); + static QString defaultPackagePath(); + static QString defaultPreviewPath(); + static QString packagePath(const QString &characterId); + static QString previewPath(const QString &characterId); + static QStringList availablePackageIds(); +}; diff --git a/src/tray/TrayController.cpp b/src/tray/TrayController.cpp index e4a8776..4c21e5f 100644 --- a/src/tray/TrayController.cpp +++ b/src/tray/TrayController.cpp @@ -1,5 +1,6 @@ #include "TrayController.h" +#include "../character/CharacterPackageRepository.h" #include "../ui/PetWindow.h" #include @@ -9,14 +10,9 @@ namespace { -QString trayIconPath() -{ - return QStringLiteral(PET_SOURCE_DIR) + QStringLiteral("/shiroko/preview.png"); -} - QIcon loadTrayIcon() { - const QPixmap pixmap(trayIconPath()); + const QPixmap pixmap(CharacterPackageRepository::defaultPreviewPath()); if (!pixmap.isNull()) { return QIcon(pixmap); diff --git a/src/ui/PetWindow.cpp b/src/ui/PetWindow.cpp index 1daeec3..8c82d8f 100644 --- a/src/ui/PetWindow.cpp +++ b/src/ui/PetWindow.cpp @@ -4,6 +4,7 @@ #include "../ai/ConversationManager.h" #include "../ai/ConversationStore.h" #include "../character/CharacterPackageLoader.h" +#include "../character/CharacterPackageRepository.h" #include "../config/ConfigManager.h" #include "../util/Logger.h" #include "ChatBubble.h" @@ -34,16 +35,6 @@ namespace { -QString characterPackagePath() -{ - return QStringLiteral(PET_SOURCE_DIR) + QStringLiteral("/shiroko"); -} - -QString previewImagePath() -{ - return QStringLiteral(PET_SOURCE_DIR) + QStringLiteral("/shiroko/preview.png"); -} - constexpr int MaxUserMessageLength = 4000; constexpr int ChatInputLowerOffsetY = 48; constexpr int StreamBubbleUpdateIntervalMs = 80; @@ -737,7 +728,7 @@ void PetWindow::mouseReleaseEvent(QMouseEvent *event) void PetWindow::loadInitialImage() { QString loadError; - m_characterPackage = CharacterPackageLoader::load(characterPackagePath(), &loadError); + m_characterPackage = CharacterPackageLoader::load(CharacterPackageRepository::defaultPackagePath(), &loadError); if (!loadError.isEmpty()) { Logger::warning(QStringLiteral("Character package load failed: ") + loadError); @@ -751,7 +742,7 @@ void PetWindow::loadInitialImage() return; } - setDisplayImage(previewImagePath(), true); + setDisplayImage(CharacterPackageRepository::defaultPreviewPath(), true); } void PetWindow::buildAnimationClips() diff --git a/src/ui/SettingsDialog.cpp b/src/ui/SettingsDialog.cpp index d879f9e..8416dde 100644 --- a/src/ui/SettingsDialog.cpp +++ b/src/ui/SettingsDialog.cpp @@ -2,6 +2,7 @@ #include "../ai/AIProviderFactory.h" #include "../ai/LLMTypes.h" +#include "../character/CharacterPackageRepository.h" #include "../config/SecretStore.h" #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -259,7 +261,23 @@ SettingsDialog::SettingsDialog( auto *chatPage = new QWidget(this); chatPage->setLayout(chatPageLayout); - m_characterComboBox->addItem(QStringLiteral("shiroko"), QStringLiteral("shiroko")); + QStringList characterIds = CharacterPackageRepository::availablePackageIds(); + if (characterIds.isEmpty()) + { + characterIds.append(CharacterPackageRepository::defaultCharacterId()); + } + + for (const QString &characterId : characterIds) + { + m_characterComboBox->addItem(characterId, characterId); + } + + const int defaultCharacterIndex = m_characterComboBox->findData(CharacterPackageRepository::defaultCharacterId()); + if (defaultCharacterIndex >= 0) + { + m_characterComboBox->setCurrentIndex(defaultCharacterIndex); + } + m_characterComboBox->setEnabled(false); m_characterComboBox->setToolTip(QStringLiteral("角色选择将在多角色资源配置接入后启用。"));