Skip to content

1.3.4.5

Choose a tag to compare

@ShirosakiMio ShirosakiMio released this 07 Nov 02:00
· 20 commits to main since this release

中文

✨ 新功能

  1. 文件下载并行续传 (#1960):单流读循环新增并行续传钩子,复用 BMCLAPI 慢速节点切换同款的 10 秒速度窗口——单连接持续低于 128KB/s 且剩余量按当前速度还需超过一个窗口时,自动切换多连接分块拉取剩余区间,突破网盘直链等按连接数限速的慢速源(修复 Cleanroom alist 镜像 50KB/s 下载缓慢);触发前零额外请求,快服务器完全不受影响。链路:1 字节 Range 探测(核对 206 响应与总大小,不支持则维持单流)→ 剩余区间按 ≥2MB/块均分最多 8 连接 → 按绝对偏移 FileChannel 写入同一临时文件(保留已完成前缀)→ 复用原有落盘/ZIP 校验/缓存流程;分块读超时放宽至 30 秒且在 resolveConnection 之后设置(按连接限速的服务器数据间歇性滴流,常规 10 秒会反复掐断正常工作的分块连接);分块失败按轮次统一重试(retry 轮 + 轮间退避),续传请求从已写偏移发 Range 只补未完成区间;全局进度 = 已完成前缀 + Σ(分块已写偏移),严格单调,修复分块重试重复计字节把进度顶破 100% 导致整轮报废、进度条反复跑满清零的问题;BMCLAPI 链路原慢速节点切换优先级不变(同命中时仍优先换节点,仅末次尝试由并行接管);并行续传完成后按最终文件重算校验摘要,修复带完整性校验或 BMCLAPI 兜底哈希的下载触发并行后校验必失败的问题
  2. 整合包补全自动恢复前弹窗确认 (#1990):整合包版本每次启动都会执行补全任务,清单内缺失的文件(含被用户主动删除/更新的模组)会被静默装回,无任何提示;现启动补全前先本地探测将被恢复的缺失文件,非空则弹窗列出,可选「继续补全 / 跳过本次 / 不再自动补全」——跳过本次下次启动再询问,不再自动补全持久化到版本设置(版本设置中可随时改回);探测按 Provider 类型分派并用具体 TypeToken 重读清单(规避 ModpackConfiguration<?> 通配反序列化得到 LinkedTreeMap 的坑),清单源与各补全任务对齐(Curse 读版本根目录 manifest.json、Modrinth 读 modrinth.index.json、Mcbbs/Server 读 modpack.cfg),清单缺失或 Server 的 fileApi 为空时与补全任务同样空转、不弹窗,任何探测异常兜底返回空表,绝不阻断启动
  3. 皮肤模型设置菜单改双指点击触发,新增点击音效:主界面皮肤模型设置菜单的触发方式由双击改为双指点击(两指几乎同时按下且未移动才触发,避免与旋转/缩放手势冲突),首次使用时显示引导提示「双指点击皮肤模型打开设置菜单」;点击模型新增音效反馈,可在皮肤设置中关闭

⚡ 优化

  1. 启动流程重构为协程驱动 (#1877):LauncherHelper 迁移至 Kotlin,启动流程由多层 thenComposeAsync 任务链改为单个协程线性执行(版本解析 → mod 扫描 → Java 检查 → 依赖补全 → 解包内置 jar → 登录 → 启动前检查 → 主线程拉起 JVMActivity);检查与登录弹窗改为挂起式 awaitChoice / awaitLoginChoice,协程取消时一并关闭停留的弹窗;认证失败可反复重试,重试期间保留微软登录进度;启动弹窗以六阶段任务列表展示,阶段按实际进入顺序打勾,跳过依赖补全时不错位;fclcore 任务(游戏文件与整合包补全、GameVerificationFixTask)经 runTracked 接入 TaskExecutor,复用弹窗下载进度展示,协程取消与执行器取消双向级联;TaskDialog 换绑执行器或重设阶段列表时摘除旧监听并释放旧列表,避免监听与视图树残留

🐛 修复

  1. 输入法双倍抬升画面致黑屏、软键盘开关需点两次 (#1997):三个相关但独立的问题一并修复——(a) 画面抬升与放大镜遮挡高度改读 IME insets 真值(共用 getImeOccludedHeight 工具),矮键盘不再漏判、悬浮键盘(inset 为 0)不再误抬,API 26–29 无专用通道沿用原可视区估算;(b) SDL 编辑框固定左上角 1px、忽略游戏传入的文本输入区域矩形,焦点不再落在键盘覆盖区,系统不再平推窗口,消除「系统平推 + JVMActivity 画面平移」叠加的双倍抬升黑屏(偶发性源于编辑框位置随呼出方漂移);(c) 接通移植时丢失的 notifyImeVisibilityChanged 真实显隐上报(JVMActivity 布局回调轮询),SdlImeController 缓存标志不再漂移,软键盘开关恢复一次点击生效,「通道关闭时 IME 自行弹出强制按回」安全网随之生效
  2. 背景图息屏启动后比例拉伸:背景图原先按加载时刻定格的视图尺寸裁出固定 Bitmap,息屏启动等视图尺寸变化后比例错误;新增 CenterCropDrawable 在绘制时按当前 bounds 实时等比缩放居中裁剪,旋转、折叠等尺寸变化场景同样保持正确比例(ImageUtil.loadInto 移除 Glide)
  3. 版本列表切换选中版本时异常动画:条目入场动画原先在整行重绑时无条件重播,切换选中版本的局部刷新(PAYLOAD_CONTENT 重绑)会让可见条目整体横滑一遍;现入场动画每个条目视图只播一次(tag 标记),并关闭列表 itemAnimator,避免局部刷新被 DefaultItemAnimator 转成 move 动画表现为整列上下弹跳

English

✨ New Features

  1. Parallel download resumption (#1960): The single-stream read loop gained a parallel-resumption hook reusing the same 10-second speed window as BMCLAPI's slow-node switching — when one connection stays under 128KB/s and the remaining data would take more than one window at the current speed, the remaining range is automatically split into chunks fetched over multiple connections, breaking through per-connection speed caps of slow sources such as net-disk direct links (fixes the 50KB/s downloads from the Cleanroom alist mirror); no extra requests are made before triggering, and fast servers are completely unaffected. The chain: a 1-byte Range probe (verifying the 206 response and total size, falling back to a single stream if unsupported) → the remaining range split into chunks of ≥2MB each over up to 8 connections → written by absolute offset into the same temp file with FileChannel (preserving the completed prefix) → the existing finalize/ZIP-check/cache flow reused; chunk read timeouts are relaxed to 30 seconds and set after resolveConnection (per-connection-capped servers trickle intermittently, and the regular 10-second timeout would repeatedly kill working chunk connections); failed chunks are retried uniformly per round (retry round + inter-round backoff), and resumption requests send Range from the written offset to fetch only unfinished ranges; global progress = completed prefix + Σ(chunk written offsets), strictly monotonic, fixing chunk retries double-counting bytes and pushing progress past 100%, which scrapped the whole round and made the progress bar repeatedly fill and reset; BMCLAPI's slow-node switching keeps its priority (still preferred when both trigger, with parallel takeover only on the last attempt); after parallel resumption completes, the checksum is recomputed over the final file, fixing downloads with integrity checks or BMCLAPI fallback hashes always failing once parallel was triggered
  2. Confirmation dialog before modpack auto-restore (#1990): Modpack versions run a completion task on every launch that silently reinstalls files missing from the manifest (including mods the user deliberately deleted or updated) with no prompt; a pre-launch local check now lists the files that would be restored and shows a confirmation dialog when non-empty, with three options — "Continue" (restore as usual), "Skip this time" (asked again on the next launch), or "Never auto-restore" (persisted into version settings, changeable anytime); the check dispatches by provider type and re-reads the manifest with concrete TypeTokens (avoiding the LinkedTreeMap pitfall of wildcard ModpackConfiguration<?> deserialization), aligned with each completion task's manifest source (Curse reads manifest.json in the version root, Modrinth reads modrinth.index.json, Mcbbs/Server read modpack.cfg); a missing manifest or an empty Server fileApi idles just like the completion task and shows no dialog, and any check failure falls back to an empty list, never blocking launch
  3. Skin model settings menu now opens with a two-finger tap, with a new tap sound: The main-screen skin model's settings menu is now triggered by a two-finger tap instead of a double-click (two fingers pressed nearly simultaneously without moving, avoiding conflicts with rotate/zoom gestures), with a first-use guide hint "Tap with two fingers on the skin model to open its settings"; tapping the model now plays a sound effect that can be turned off in the skin settings

⚡ Improvements

  1. Launch flow refactored to be coroutine-driven (#1877): LauncherHelper was migrated to Kotlin and the launch flow changed from a multi-layer thenComposeAsync task chain to a single coroutine executing linearly (version resolution → mod scan → Java check → dependency completion → unpacking built-in jars → login → pre-launch checks → launching JVMActivity on the main thread); check and login dialogs became suspending awaitChoice / awaitLoginChoice, closing leftover dialogs when the coroutine is cancelled; authentication failures can be retried repeatedly, keeping Microsoft login progress across retries; the launch dialog shows a six-stage task list with stages checked off in actual entry order, staying aligned even when dependency completion is skipped; fclcore tasks (game file and modpack completion, GameVerificationFixTask) are wired into the TaskExecutor via runTracked, reusing the dialog download-progress display with two-way cancellation cascading between coroutine and executor; TaskDialog detaches old listeners and releases old lists when re-binding an executor or resetting stages, avoiding listener and view-tree leftovers

🐛 Bug Fixes

  1. Input method shifting the screen up twice (black screen) and the keyboard toggle needing two taps (#1997): Three related but independent issues fixed together — (a) the screen shift and magnifier occlusion height now read the true IME insets (via a shared getImeOccludedHeight utility), so short keyboards are no longer missed and floating keyboards (0 inset) no longer shift the screen, while APIs 26–29 without the dedicated channel keep the old visible-area estimate; (b) the SDL input field is pinned to a 1px point at the top-left, ignoring the text input rectangle passed by the game, so focus no longer lands under the keyboard, the system no longer pans the window, and the "system pan + JVMActivity shift" double-shift black screen is gone (the intermittency came from the field's position drifting depending on who opened the keyboard); (c) the notifyImeVisibilityChanged true-visibility reporting lost during the port is reconnected (polled from JVMActivity layout callbacks), so SdlImeController's cached flag no longer drifts, the keyboard toggle works on the first tap again, and the "force Enter when the channel is off but the IME pops up by itself" safety net takes effect
  2. Background image stretched after launching with the screen off: The background was cropped into a fixed Bitmap at the view size frozen at load time, so the ratio broke after size changes such as launching while the screen had been off; the new CenterCropDrawable scales and center-crops proportionally to the current bounds at draw time, staying correct across rotation, folding and other size changes (Glide removed from ImageUtil.loadInto)
  3. Abnormal animation when switching the selected version in the version list: The per-item entrance animation used to replay unconditionally on every full rebind, so the partial refresh from switching the selected version (PAYLOAD_CONTENT rebinding) made all visible items slide horizontally as a whole; the entrance animation now plays once per item view (marked with a tag), and the list's itemAnimator is disabled so partial refreshes are no longer turned into move animations by DefaultItemAnimator, which showed as the whole list bouncing vertically