fix(app): M45 r1 两条 P2(向导拒装文案 + 处理器段进度满格)
P2-1:wizard.slint 的 Forge/NeoForge 提示还写着「需要 installer processors:本轮请用 ull install」, 改成「需要 installer processors(首装会外调 java,约 1–3 分钟)」;全仓再扫一遍 「ull install / 显式拒装 / 终端跑」等措辞,user-facing 文案已无残留(余下命中全是 OptiFine/LiteLoader 的正确说明与测试注释)。 P2-2:进度条在处理器依赖库下完那一刻就满格(36/36),随后加载器库的 29 个文件才被计入 → 100% 回落再涨回,且 bytes_total 用 .max() 与文件数对不上。 - Meter 新增 expect(files, bytes):文件数与字节都 saturating_add; - install_loader 在处理器段之前就把加载器库的文件/字节一次预记账(两段之和), 加载器库阶段只剩切阶段文案,不再记账; - Reporter::expect 改为委托 Meter::expect,处理器依赖库沿用同一条曲线; - 回归测试钉住:预记账后 files_total=95、bytes_total=17MB、ratio 不再满格, 处理器库下完仍是中间态,加载器库下完才到 100%。 真机重截 + 识图:D:/tmp/ull-m45-shots/forge-mid-fixed-25s.png —— 同一时刻面板 36/65 文件、3.4 MB/15.3 MB、进度条只填了约一半(旧图 36/36 + 满格)。
This commit is contained in:
1 parent
3d9372029e
commit
d95c9664c6
5 files changed
+85
-8
No files matched your search
@@ -304,6 +304,13 @@ fn install_loader(
|
||||
vanilla.loader = LoaderKind::Vanilla;
|
||||
install_vanilla(job, engine, &vanilla)?;
|
||||
}
|
||||
// 两段(加载器库 + 处理器依赖库)在动手前一次预记账:进度条只走一条单调曲线,
|
||||
// 处理器依赖库下完不会先满格、再在加载器库开始时回落到一半。
|
||||
{
|
||||
let mut guard = job.meter.lock().map_err(|_| "进度锁失效".to_string())?;
|
||||
let (bytes, _) = plan.install.total_bytes();
|
||||
guard.expect(plan.files().len(), bytes);
|
||||
}
|
||||
// Forge/NeoForge:installer processors 必须先跑完,`execute` 才允许写版本 JSON。
|
||||
if release.requires_installer() {
|
||||
let input = StageInput {
|
||||
@@ -327,9 +334,6 @@ fn install_loader(
|
||||
}
|
||||
{
|
||||
let mut guard = job.meter.lock().map_err(|_| "进度锁失效".to_string())?;
|
||||
guard.progress.files_total += u64::try_from(plan.files().len()).unwrap_or(u64::MAX);
|
||||
let (bytes, _) = plan.install.total_bytes();
|
||||
guard.progress.bytes_total = guard.progress.bytes_total.max(bytes);
|
||||
guard.stage(
|
||||
InstallStage::Downloading,
|
||||
&format!("开始下载加载器库({} 个文件)…", plan.files().len()),
|
||||
|
||||
@@ -146,9 +146,7 @@ impl Reporter<'_> {
|
||||
let Ok(mut guard) = self.meter.lock() else {
|
||||
return;
|
||||
};
|
||||
let files = u64::try_from(files).unwrap_or(u64::MAX);
|
||||
guard.progress.files_total = guard.progress.files_total.saturating_add(files);
|
||||
guard.progress.bytes_total = guard.progress.bytes_total.saturating_add(bytes);
|
||||
guard.expect(files, bytes);
|
||||
}
|
||||
|
||||
/// 失败留痕(文案由调用方决定怎么呈现;这里只保证日志里有一条)。
|
||||
|
||||
@@ -69,6 +69,71 @@ fn request(loader: LoaderKind, version: &str) -> CreateRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/// 一个「刚下完」的文件结局(记账用)。
|
||||
fn downloaded(bytes: u64) -> FileOutcome {
|
||||
FileOutcome {
|
||||
role: FileRole::Library,
|
||||
name: "lib.jar".to_string(),
|
||||
dest: PathBuf::from("lib.jar"),
|
||||
status: FileStatus::Downloaded,
|
||||
bytes,
|
||||
source: None,
|
||||
failure: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn progress_is_pre_accounted_across_segments_so_the_bar_never_snaps_to_full() {
|
||||
// M45 r1 P2-2 的回归:处理器依赖库下完那一刻,面板曾显示 36/36 满格 + 3.4MB/10MB,
|
||||
// 之后加载器库的 29 个文件才被计入 → 进度条从 100% 回落到 55% 再涨回去。
|
||||
let request = request(LoaderKind::Forge, "1.20.1");
|
||||
let mut meter = Meter::new(&request);
|
||||
|
||||
// 原版段:30 个文件全下完(install_vanilla 对总量是赋值,不是累加)
|
||||
meter.progress.files_total = 30;
|
||||
meter.progress.bytes_total = 3_000_000;
|
||||
for _ in 0..30 {
|
||||
meter.note(&downloaded(100_000));
|
||||
}
|
||||
assert!((meter.progress.ratio() - 1.0).abs() < f32::EPSILON);
|
||||
|
||||
// install_loader 的顺序:加载器库与处理器依赖库都在动手前一次预记账
|
||||
meter.expect(29, 10_000_000);
|
||||
meter.expect(36, 4_000_000);
|
||||
assert_eq!(meter.progress.files_total, 95, "两段之和一次到位");
|
||||
assert_eq!(
|
||||
meter.progress.bytes_total, 17_000_000,
|
||||
"字节是相加不是取最大"
|
||||
);
|
||||
assert!(
|
||||
meter.progress.ratio() < 0.7,
|
||||
"预记账后不能还停在满格:{}",
|
||||
meter.progress.ratio()
|
||||
);
|
||||
|
||||
// 处理器依赖库 36 个下完 → 仍没满格(加载器库还在后面)
|
||||
for _ in 0..36 {
|
||||
meter.note(&downloaded(110_000));
|
||||
}
|
||||
let ratio = meter.progress.ratio();
|
||||
assert!(
|
||||
(0.6..1.0).contains(&ratio),
|
||||
"回落到中间态而不是满格:{ratio}"
|
||||
);
|
||||
assert!(
|
||||
meter.progress.bytes_done < meter.progress.bytes_total,
|
||||
"字节总量要覆盖已下载量:{}/{}",
|
||||
meter.progress.bytes_done,
|
||||
meter.progress.bytes_total
|
||||
);
|
||||
|
||||
// 加载器库也下完 → 这时候才该是满格
|
||||
for _ in 0..29 {
|
||||
meter.note(&downloaded(340_000));
|
||||
}
|
||||
assert!((meter.progress.ratio() - 1.0).abs() < f32::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loader_support_matrix_is_explicit() {
|
||||
// M45 语义变更:Forge/NeoForge 从「GUI 显式拒装」扩进受支持集合(走 installer processors)。
|
||||
|
||||
@@ -37,6 +37,16 @@ impl Meter {
|
||||
self.previous = None;
|
||||
}
|
||||
|
||||
/// 预记账一段待下载的文件(文件数 + 字节)。
|
||||
///
|
||||
/// 一次安装可能分几段(原版 / 处理器依赖库 / 加载器库):每段开工前都先记账,
|
||||
/// 整条进度曲线才是单调的——某一段下完不会先到 100%,再因为下一段的文件被计入而回落。
|
||||
pub(super) fn expect(&mut self, files: usize, bytes: u64) {
|
||||
let files = u64::try_from(files).unwrap_or(u64::MAX);
|
||||
self.progress.files_total = self.progress.files_total.saturating_add(files);
|
||||
self.progress.bytes_total = self.progress.bytes_total.saturating_add(bytes);
|
||||
}
|
||||
|
||||
/// 记账一个文件的结局。
|
||||
pub(super) fn note(&mut self, outcome: &FileOutcome) {
|
||||
self.progress.files_done += 1;
|
||||
|
||||
@@ -196,8 +196,8 @@ export component NewInstanceWizard inherits Rectangle {
|
||||
LoaderChoice { index: 0; label: "原版(Vanilla)"; hint: "不装加载器,最快最稳"; picked => { PageState.wizard-select-loader(0); } }
|
||||
LoaderChoice { index: 1; label: "Fabric"; hint: "轻量模组加载器(GUI 可直接装)"; picked => { PageState.wizard-select-loader(1); } }
|
||||
LoaderChoice { index: 2; label: "Quilt"; hint: "Fabric 的分支(GUI 可直接装)"; picked => { PageState.wizard-select-loader(2); } }
|
||||
LoaderChoice { index: 3; label: "Forge"; hint: "需要 installer processors:本轮请用 ull install"; picked => { PageState.wizard-select-loader(3); } }
|
||||
LoaderChoice { index: 4; label: "NeoForge"; hint: "需要 installer processors:本轮请用 ull install"; picked => { PageState.wizard-select-loader(4); } }
|
||||
LoaderChoice { index: 3; label: "Forge"; hint: "需要 installer processors(首装会外调 java,约 1–3 分钟)"; picked => { PageState.wizard-select-loader(3); } }
|
||||
LoaderChoice { index: 4; label: "NeoForge"; hint: "需要 installer processors(首装会外调 java,约 1–3 分钟)"; picked => { PageState.wizard-select-loader(4); } }
|
||||
}
|
||||
|
||||
// ③ 名字
|
||||
|
||||
Reference in new issue
Block a user