发行说明
重要提示 / Important Note: 本发行版包含更新器(
updater.exe)的更新。如果您仍在使用较早的 v1.2.0 系列版本,由于其自带的老版更新器无法获取到自身的新二进制,自动更新可能无法替换本组件——届时请手动替换updater.exe。
v1.3.0 — 存档管理重构、更新器自更新与 UI 优化(2026-09-12)
本发行版将存档管理重构为实例详情页的子选项卡,升级备份目录方案以避免冲突,使内置更新器能够自我更新,并优化了自定义标题栏和关于页面。
存档管理现在位于实例详情页内
“存档管理”以前是一个独立的全屏页面(SavesListPage),重复了实例详情侧边栏,并且必须通过 Mod 管理选项卡来路由导出/导入/浏览。现在它是实例详情页的二级选项卡,与游戏设置和 Mod 管理一致。
- 新增
savestabpage.{h,cpp}— 仅包含存档列表(loadSaves、双击saveSelected)。对象名savesTabPage。 instancedetailpage.{h,cpp}— 向其QStackedWidget添加第 4 个选项卡(存档管理);侧边栏“存档管理”按钮现在调用showSection(4);showSection增加了 idx=4 选择和loadSaves;新增saveSelected信号;移除了savesManageRequested信号。mainwindow.{h,cpp}— 移除了SavesListPage以及onSavesManageRequested/onSavesNavToDetail/onSavesModpackAction/onBackFromSavesList路由;InstanceDetailPage::saveSelected直接连接到onSaveSelected;onBackFromSaveDetail返回到实例详情页并停留在存档选项卡。- 导出/导入/浏览 — 在存档选项卡内就地触发,复用实例详情侧边栏的 ZIP/CKAN 和浏览菜单(同一个
ModpackController),无需切换选项卡。 - 移除
saveslistpage.{h,cpp};相应清理了CMakeLists.txt和dark/light.qss中的savesListPage规则。 - 测试 — 两个测试套件均可构建;UI 已手动验证:存档管理不会导航离开,导出/导入就地打开,从存档详情返回时回到存档选项卡。
备份目录升级(防冲突)
备份以前位于 backups/{instanceName}/{saveName}/*.zip;两个名称相似的实例如果具有相同存档名,可能会互相覆盖备份。现在第一级会附加实例 id 的前 8 个字符(第一个 UUID 段,例如 550e8400):backups/{instanceName-idPrefix}/{saveName}/*.zip。实例 id 全局唯一,并且重命名不会改变它,因此即使显式重命名后,备份仍可定位。
- 目录计算(
instancemanager_backup.cppgetBackupDirForSave)—sanitizeFileName(instanceName) + "-" + instanceId.left(8);存档名层级保持普通名称。空 id 会回退为仅使用实例名,以增强健壮性。 - 惰性迁移(
migrateLegacyBackups)— 两种旧布局(backups/{instanceName}/{saveName}和更早的单层backups/{saveName})在访问时迁移;如果目标已存在(名称冲突),则跳过迁移以保持幂等;迁移的*.zip文件会被移动,旧目录会被清空。 - 实例 id 传递 — 与备份相关的
InstanceManager接口(getBackupDirForSave/listBackups/createBackup/restoreBackup)新增了instanceId参数;saveSelected/setSavePath调用链savestabpage → instancedetailpage → mainwindow → savedetailpage会一路传递 id(savestabpage直接使用m_instance.id)。 - 备份 zip 文件命名不变 —
saveName[_note]_yyyyMMdd_HHmmss.zip;只有目录层级发生了变化。
内置更新器现在可以自我更新
更新器被排除在自身的保留列表之外(它在清理/移动期间总是跳过 updater.exe),因此无法替换自身。此前发行说明要求 v1.2.0 用户手动替换它。现在,当发行说明正文标记“本发行版附带更新后的内置更新器”时,更新会保留更新包 zip,重新启动后的新启动器会静默替换 updater.exe——无需手动步骤。
- 检测(
updatemanager.{h,cpp}bodyIndicatesUpdaterUpdate)— 匹配发行说明正文中的双语短语(中文“本 Release 含有更新器”或英文“ships an updated built-in updater”);命中后ReleaseInfo.updaterUpdate=true。 - 保留 zip(
updatemanager.cppapplyUpdate)— 在 Windows 上,如果updaterUpdate为真,则向.updater_update/写入updater_pending标记(包含 zip 文件名),并向更新器传递--keep-zip;src/updater/main.cpp解析--keep-zip,完成后不再删除.updater_update目录。 - 新启动器替换(
main.cpp,启动守卫之后,仅 Windows)—applyPendingUpdaterUpdate检测updater_pending→ 在保留的 zip 中按 basename 查找updater.exe(容忍单一顶层发布布局,大小写不敏感)→ 解压到临时文件 → 覆盖应用目录中的updater.exe→ 成功后完全删除.updater_update。失败时弹出对话框提供“重试 / 忽略”(忽略会调用cleanupPendingUpdaterUpdate);通常静默且非阻塞。 - Zip 条目 API(
updatemanager.{h,cpp})—findZipEntryByBaseName/extractZipEntry(基于 miniz),用于定位并解压任意深度的更新器条目。 - 翻译 — 新增 7 个 UI 字符串并完成 en_US 翻译(
556个全部已翻译),.qm已重建并同步到dist/translations。 - 测试 —
test_launcher新增updaterUpdateBodyDetection和zipUpdaterEntry(双语言检测、普通日志无误报、任意深度查找、大小写不敏感、缺失条目、解压内容匹配)。两个ctest套件均通过。
自定义标题栏边缘缩放已修复
Qt::FramelessWindowHint 会剥离启用窗口缩放的本地 WS_THICKFRAME 样式,因此无边框窗口无法从其边缘调整大小。
- 补丁(
mainwindow.{h,cpp}applyNativeFrameStyle,仅 Windows)— 保留无边框自定义绘制外观,然后在首次showEvent之后以及toggleMaximize中,通过SetWindowLongPtr(GWL_STYLE)重新添加WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,并调用SetWindowPos(SWP_FRAMECHANGED),以便系统重新计算非客户区。刻意不恢复WS_CAPTION,因此不会出现系统标题栏。 - 命中测试(
WM_NCHITTEST)— 边缘/角落抓取区域从 6px 加宽到 8px,以配合恢复的WS_THICKFRAME,实现平滑的原生缩放。 - 结果 — 在保留自定义绘制的无边框标题栏的同时,四条边均可自由、平滑地调整大小。
关于页面条目图标
- 鸣谢部分 — KSP-CKAN 团队(
ckan.png)、Hello Minecraft Launcher 项目(hmcl.png);两个镜像 gh-proxy.com 和 ghfast.top 共用 GitHub 图标(github.png)。 - 依赖部分 — Qt 6(
qt6.png)。 - 实现 — 4 个 PNG 注册到
resources/resources.qrc;aboutpage.cpp在其构造函数中加载QPixmap,并将其作为第 4 个参数传给makeLinkRow。
完整英文(en_US)本地化
源码包含 548 个 UI 字符串,但 translations/hello_ksp_launcher_en_US.ts 只有 506 个。使用 lupdate 重新提取(build/en_fresh.ts)并比较,以补全近期版本新增的 43 个缺失英文翻译(崩溃日志分析、整合包导入/导出、调试模式、推荐/建议对话框、批量与卸载进度、注册表锁提示、自更新 SHA256 等)。现在全部 548 个字符串都有翻译(lrelease 报告 0 个未完成);现有 506 个未改动。.qm 已重建并同步到 dist/translations。由于英文是默认语言,首次启动现在会显示完整的英文 UI。
技术栈
- 框架:Qt 6(Widgets、Svg、Network、Concurrent)
- 语言:C++17
- 构建:CMake ≥ 3.16;Windows 使用 Qt 自带的 mingw 工具链
- 测试:
test_libckan+test_launcher(全部通过)
完整变更日志:https://github.com/Zhuwenqian/Hello-KSP-Launcher/compare/v1.2.3...v1.3.0