You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
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
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
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
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
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)
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