From 89dcaff5a93e8630936b15ed0344d7cd9982da60 Mon Sep 17 00:00:00 2001 From: laolarou Date: Fri, 22 Nov 2024 22:40:53 +0800 Subject: [PATCH] provide a unified impl for progress value --- .../ProjBobcat/Class/Helper/DownloadHelper.cs | 4 +- .../Class/Model/Downloading/DownloadFile.cs | 2 +- .../Class/Model/ProgressReportBase.cs | 2 +- .../ProjBobcat/Class/Model/ProgressValue.cs | 40 +++++++++++++++++++ .../DefaultResourceCompleter.cs | 8 ++-- .../Installer/FabricInstaller.cs | 8 ++-- .../HighVersionForgeInstaller.cs | 18 +++++---- .../ForgeInstaller/LegacyForgeInstaller.cs | 10 ++--- .../Installer/LiteLoaderInstaller.cs | 10 ++--- .../ModPackInstaller/CurseForgeInstaller.cs | 30 +++++++------- .../ModPackInstaller/ModPackInstallerBase.cs | 2 +- .../ModPackInstaller/ModrinthInstaller.cs | 10 +++-- .../Installer/OptifineInstaller.cs | 18 ++++----- .../Installer/QuiltInstaller.cs | 8 ++-- .../ResourceInfoResolver/AssetInfoResolver.cs | 25 ++++++------ .../LibraryInfoResolver.cs | 15 +++---- .../ResourceInfoResolver/ResolverBase.cs | 2 +- .../Service/ServerPingService.cs | 10 +++-- .../Event/DownloadFileChangedEventArgs.cs | 3 +- .../ForgeInstallStageChangedEventArgs.cs | 3 +- .../Event/GameResourceInfoResolveEventArgs.cs | 3 +- .../Event/InstallerStageChangedEventArgs.cs | 3 +- 22 files changed, 144 insertions(+), 90 deletions(-) create mode 100644 ProjBobcat/ProjBobcat/Class/Model/ProgressValue.cs diff --git a/ProjBobcat/ProjBobcat/Class/Helper/DownloadHelper.cs b/ProjBobcat/ProjBobcat/Class/Helper/DownloadHelper.cs index 346fd30..96e93e3 100644 --- a/ProjBobcat/ProjBobcat/Class/Helper/DownloadHelper.cs +++ b/ProjBobcat/ProjBobcat/Class/Helper/DownloadHelper.cs @@ -104,7 +104,7 @@ public static async Task DownloadData(DownloadFile downloadFile, DownloadSetting downloadFile.OnChanged( averageSpeed, - 1, + ProgressValue.FromDisplay(100), responseLength, responseLength); @@ -483,7 +483,7 @@ public static async Task MultiPartDownloadTaskAsync( if (downloadSettings.ShowDownloadProgressForPartialDownload) downloadFile.OnChanged( (double)addedAggregatedSpeed / addedAggregatedSpeedCount, - (double)addedBytesReceived / urlInfo.FileLength, + ProgressValue.Create(addedBytesReceived, urlInfo.FileLength), addedBytesReceived, urlInfo.FileLength); } diff --git a/ProjBobcat/ProjBobcat/Class/Model/Downloading/DownloadFile.cs b/ProjBobcat/ProjBobcat/Class/Model/Downloading/DownloadFile.cs index d386b6e..17f427d 100644 --- a/ProjBobcat/ProjBobcat/Class/Model/Downloading/DownloadFile.cs +++ b/ProjBobcat/ProjBobcat/Class/Model/Downloading/DownloadFile.cs @@ -55,7 +55,7 @@ public class DownloadFile /// public event EventHandler? Changed; - internal void OnChanged(double speed, double progress, long bytesReceived, long totalBytes) + internal void OnChanged(double speed, ProgressValue progress, long bytesReceived, long totalBytes) { this.Changed?.Invoke(this, new DownloadFileChangedEventArgs { diff --git a/ProjBobcat/ProjBobcat/Class/Model/ProgressReportBase.cs b/ProjBobcat/ProjBobcat/Class/Model/ProgressReportBase.cs index 0e2860a..dc69e2e 100644 --- a/ProjBobcat/ProjBobcat/Class/Model/ProgressReportBase.cs +++ b/ProjBobcat/ProjBobcat/Class/Model/ProgressReportBase.cs @@ -8,7 +8,7 @@ public class ProgressReportBase : IProgressReport { public event EventHandler? StageChangedEventDelegate; - protected void InvokeStatusChangedEvent(string currentStage, double progress) + protected void InvokeStatusChangedEvent(string currentStage, ProgressValue progress) { this.StageChangedEventDelegate?.Invoke(this, new StageChangedEventArgs { diff --git a/ProjBobcat/ProjBobcat/Class/Model/ProgressValue.cs b/ProjBobcat/ProjBobcat/Class/Model/ProgressValue.cs new file mode 100644 index 0000000..84b2664 --- /dev/null +++ b/ProjBobcat/ProjBobcat/Class/Model/ProgressValue.cs @@ -0,0 +1,40 @@ +using System; +using System.Globalization; + +namespace ProjBobcat.Class.Model; + +/// +/// A unified impl for the progress value +///
+/// Implicit convert this struct to will get the value of +///
+/// +public readonly record struct ProgressValue(double NormalizedValue) : IFormattable +{ + /// + /// Display value for the progress, range usually in 0-100 + /// + public double DisplayValue => this.NormalizedValue * 100; + + public static implicit operator double(ProgressValue value) => value.DisplayValue; + + public static ProgressValue Start => new (0); + public static ProgressValue Finished => new (1); + + /// + /// Create a new progress base on and + /// + /// + /// + /// + public static ProgressValue Create(double numerator, double denominator) => FromNormalized(numerator / denominator); + public static ProgressValue FromNormalized(double normalizedValue) => new (normalizedValue); + public static ProgressValue FromDisplay(double displayValue) => new (displayValue / 100); + + public string ToString(string? format, IFormatProvider? formatProvider) + { + return NormalizedValue.ToString(format, formatProvider); + } + + public override string ToString() => NormalizedValue.ToString(CultureInfo.CurrentCulture); +} \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/DefaultResourceCompleter.cs b/ProjBobcat/ProjBobcat/DefaultComponent/DefaultResourceCompleter.cs index 2d4d469..30c65c8 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/DefaultResourceCompleter.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/DefaultResourceCompleter.cs @@ -60,7 +60,7 @@ public class DefaultResourceCompleter : IResourceCompleter this.OnResolveComplete(this, new GameResourceInfoResolveEventArgs { - Progress = 0, + Progress = ProgressValue.Start, Status = "正在进行资源检查" }); @@ -104,7 +104,7 @@ void FireResolveEvent(object? sender, GameResourceInfoResolveEventArgs e) this.OnResolveComplete(this, new GameResourceInfoResolveEventArgs { - Progress = 100, + Progress = ProgressValue.Finished, Status = "资源检查完成" }); @@ -164,7 +164,7 @@ void OnCompleted(object? sender, DownloadFileCompletedEventArgs e) this.DownloadFileCompletedEvent?.Invoke(sender, e); } - void OnChanged(double progress, double speed) + void OnChanged(ProgressValue progress, double speed) { this.DownloadFileChangedEvent?.Invoke(this, new DownloadFileChangedEventArgs { @@ -183,7 +183,7 @@ void WhenCompleted(object? sender, DownloadFileCompletedEventArgs e) var downloaded = Interlocked.Increment(ref this._totalDownloaded); var needToDownload = Interlocked.Read(ref this._needToDownload); - this.OnChanged((double)downloaded / needToDownload, e.AverageSpeed); + this.OnChanged(ProgressValue.Create(downloaded, needToDownload), e.AverageSpeed); this.OnCompleted(sender, e); } } \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/FabricInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/FabricInstaller.cs index 6f0801b..700a54b 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/FabricInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/FabricInstaller.cs @@ -24,7 +24,7 @@ public string Install() public async Task InstallTaskAsync() { - this.InvokeStatusChangedEvent("开始安装", 0); + this.InvokeStatusChangedEvent("开始安装", ProgressValue.Start); if (string.IsNullOrEmpty(this.RootPath)) throw new NullReferenceException("RootPath 字段为空"); @@ -76,7 +76,7 @@ public async Task InstallTaskAsync() else DirectoryHelper.CleanDirectory(di.FullName); - this.InvokeStatusChangedEvent("生成版本总成", 70); + this.InvokeStatusChangedEvent("生成版本总成", ProgressValue.FromDisplay(70)); var resultModel = new RawVersionModel { @@ -93,11 +93,11 @@ public async Task InstallTaskAsync() var jsonContent = JsonSerializer.Serialize(resultModel, typeof(RawVersionModel), new RawVersionModelContext(JsonHelper.CamelCasePropertyNamesSettings())); - this.InvokeStatusChangedEvent("将版本 Json 写入文件", 90); + this.InvokeStatusChangedEvent("将版本 Json 写入文件", ProgressValue.FromDisplay(95)); await File.WriteAllTextAsync(jsonPath, jsonContent); - this.InvokeStatusChangedEvent("安装完成", 100); + this.InvokeStatusChangedEvent("安装完成", ProgressValue.Finished); return id; } diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs index 9b2230c..9f09326 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs @@ -72,7 +72,7 @@ public async Task InstallForgeTaskAsync() #region 解析 Version.json - this.InvokeStatusChangedEvent("解析 Version.json", 0.1); + this.InvokeStatusChangedEvent("解析 Version.json", ProgressValue.FromDisplay(10)); var versionJsonEntry = archive.Entries.FirstOrDefault(e => @@ -105,7 +105,7 @@ public async Task InstallForgeTaskAsync() #region 解析 Install_profile.json - this.InvokeStatusChangedEvent("解析 Install_profile.json", 0.2); + this.InvokeStatusChangedEvent("解析 Install_profile.json", ProgressValue.FromDisplay(20)); var installProfileEntry = archive.Entries.FirstOrDefault(e => @@ -124,7 +124,7 @@ public async Task InstallForgeTaskAsync() #region 解析 Lzma - this.InvokeStatusChangedEvent("解析 Lzma", 0.4); + this.InvokeStatusChangedEvent("解析 Lzma", ProgressValue.FromDisplay(40)); var serverLzma = archive.Entries.FirstOrDefault(e => e.Key?.Equals("data/server.lzma", StringComparison.OrdinalIgnoreCase) ?? false); @@ -174,7 +174,7 @@ public async Task InstallForgeTaskAsync() #region 解压 Forge Jar - this.InvokeStatusChangedEvent("解压 Forge Jar", 0.5); + this.InvokeStatusChangedEvent("解压 Forge Jar", ProgressValue.FromDisplay(50)); var forgeJar = archive.Entries.FirstOrDefault(e => e.Key?.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}.jar", @@ -272,7 +272,7 @@ public async Task InstallForgeTaskAsync() #region 解析 Processor - this.InvokeStatusChangedEvent("解析 Processor", 1); + this.InvokeStatusChangedEvent("解析 Processor", ProgressValue.Finished); string? ResolvePathRegex(string? val) { @@ -535,7 +535,8 @@ where lineSp[0].Equals("Main-Class", StringComparison.OrdinalIgnoreCase) logSb.AppendLine(args.Data); var data = args.Data; - var progress = (double)this._totalProcessed / this._needToProcess; + + var progress = ProgressValue.Create(this._totalProcessed, this._needToProcess); var dataStr = data.CropStr(40); this.InvokeStatusChangedEvent($"{dataStr} <安装信息> ( {this._totalProcessed} / {this._needToProcess} )", @@ -549,7 +550,7 @@ where lineSp[0].Equals("Main-Class", StringComparison.OrdinalIgnoreCase) errSb.AppendLine(args.Data); var data = args.Data ?? string.Empty; - var progress = (double)this._totalProcessed / this._needToProcess; + var progress = ProgressValue.Create(this._totalProcessed, this._needToProcess); var dataStr = data.CropStr(40); this.InvokeStatusChangedEvent($"{dataStr} <错误> ( {this._totalProcessed} / {this._needToProcess} )", @@ -619,7 +620,8 @@ void WhenCompleted(object? sender, DownloadFileCompletedEventArgs e) this._totalDownloaded++; - var progress = (double)this._totalDownloaded / this._needToDownload; + + var progress = ProgressValue.Create(this._totalDownloaded, this._needToDownload); var retryStr = file.RetryCount > 0 ? $"[重试 - {file.RetryCount}] " : string.Empty; this.InvokeStatusChangedEvent( diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs index cddbd5c..59da781 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs @@ -41,7 +41,7 @@ public async Task InstallForgeTaskAsync() { try { - this.InvokeStatusChangedEvent("解压安装文件", 0.05); + this.InvokeStatusChangedEvent("解压安装文件", ProgressValue.Start); using var reader = ArchiveFactory.Open(this.ForgeExecutablePath); var profileEntry = @@ -76,18 +76,18 @@ public async Task InstallForgeTaskAsync() Succeeded = false }; - this.InvokeStatusChangedEvent("解压完成", 0.1); + this.InvokeStatusChangedEvent("解压完成", ProgressValue.FromDisplay(5)); await using var stream = profileEntry.OpenEntryStream(); - this.InvokeStatusChangedEvent("解析安装文档", 0.35); + this.InvokeStatusChangedEvent("解析安装文档", ProgressValue.FromDisplay(35)); var profileModel = await JsonSerializer.DeserializeAsync(stream, LegacyForgeInstallProfileContext.Default.LegacyForgeInstallProfile); if (profileModel == null) throw new ArgumentNullException(nameof(profileModel)); - this.InvokeStatusChangedEvent("解析完成", 0.75); + this.InvokeStatusChangedEvent("解析完成", ProgressValue.FromDisplay(75)); var id = string.IsNullOrEmpty(this.CustomId) ? profileModel.VersionInfo.Id : this.CustomId; @@ -121,7 +121,7 @@ public async Task InstallForgeTaskAsync() new LegacyForgeInstallVersionInfoContext(JsonHelper.CamelCasePropertyNamesSettings())); await File.WriteAllTextAsync(jsonPath, versionJsonString); - this.InvokeStatusChangedEvent("文件写入完成", 1); + this.InvokeStatusChangedEvent("文件写入完成", ProgressValue.Finished); return new ForgeInstallResult { diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/LiteLoaderInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/LiteLoaderInstaller.cs index d56d5bf..56cbed9 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/LiteLoaderInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/LiteLoaderInstaller.cs @@ -37,12 +37,12 @@ public async Task InstallTaskAsync() if (this.VersionModel == null) throw new NullReferenceException("VersionModel 不能为 null"); - this.InvokeStatusChangedEvent("开始安装 LiteLoader", 0); + this.InvokeStatusChangedEvent("开始安装 LiteLoader", ProgressValue.Start); var vl = new DefaultVersionLocator(this.RootPath, Guid.Empty); var rawVersion = vl.ParseRawVersion(this.VersionModel.McVersion); - this.InvokeStatusChangedEvent("解析版本", 10); + this.InvokeStatusChangedEvent("解析版本", ProgressValue.FromDisplay(10)); if (rawVersion == null) throw new UnknownGameNameException(this.VersionModel.McVersion); @@ -57,7 +57,7 @@ public async Task InstallTaskAsync() var timeStamp = long.TryParse(this.VersionModel.Build.Timestamp, out var timeResult) ? timeResult : 0; var time = TimeHelper.Unix11ToDateTime(timeStamp); - this.InvokeStatusChangedEvent("解析 Libraries", 30); + this.InvokeStatusChangedEvent("解析 Libraries", ProgressValue.FromDisplay(30)); var libraries = new List { @@ -77,7 +77,7 @@ public async Task InstallTaskAsync() libraries.AddRange(this.VersionModel.Build.Libraries); - this.InvokeStatusChangedEvent("Libraries 解析完成", 60); + this.InvokeStatusChangedEvent("Libraries 解析完成", ProgressValue.FromDisplay(60)); const string mainClass = "net.minecraft.launchwrapper.Launch"; var resultModel = new RawVersionModel @@ -119,7 +119,7 @@ public async Task InstallTaskAsync() await File.WriteAllTextAsync(jsonPath, jsonContent); - this.InvokeStatusChangedEvent("LiteLoader 安装完成", 100); + this.InvokeStatusChangedEvent("LiteLoader 安装完成", ProgressValue.Finished); return id; } diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs index a8c1faa..3e3f5a5 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs @@ -6,9 +6,11 @@ using System.Linq; using System.Net.Http; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; using ProjBobcat.Class.Helper; +using ProjBobcat.Class.Model; using ProjBobcat.Class.Model.CurseForge; using ProjBobcat.Class.Model.Downloading; using ProjBobcat.Exceptions; @@ -33,7 +35,7 @@ public async Task InstallTaskAsync() ArgumentException.ThrowIfNullOrEmpty(this.GameId); ArgumentException.ThrowIfNullOrEmpty(this.RootPath); - this.InvokeStatusChangedEvent("开始安装", 0); + this.InvokeStatusChangedEvent("开始安装", ProgressValue.Start); var manifest = await this.ReadManifestTask(); @@ -78,18 +80,18 @@ public async Task InstallTaskAsync() urlBags.Add(downloadFile); - this.TotalDownloaded++; - this.NeedToDownload++; - - var progress = (double)this.TotalDownloaded / this.NeedToDownload * 100; + var addedTotalDownloaded = Interlocked.Increment(ref this.TotalDownloaded); + var addedNeedToDownload = Interlocked.Increment(ref this.NeedToDownload); + var progress = ProgressValue.Create(addedTotalDownloaded, addedNeedToDownload); this.InvokeStatusChangedEvent($"成功解析 MOD [{t.Item1}] 的下载地址", progress); } catch (CurseForgeModResolveException e) { - this.InvokeStatusChangedEvent($"MOD [{t.Item1}] 的下载地址解析失败,尝试手动拼接", - 114514); + this.InvokeStatusChangedEvent( + $"MOD [{t.Item1}] 的下载地址解析失败,尝试手动拼接", + ProgressValue.FromDisplay(50)); var (guessed, df) = await this.TryGuessModDownloadLink(t.Item2, di.FullName); @@ -119,10 +121,9 @@ public async Task InstallTaskAsync() urlBags.Add(df); - this.TotalDownloaded++; - this.NeedToDownload++; - - var progress = (double)this.TotalDownloaded / this.NeedToDownload * 100; + var addedTotalDownloaded = Interlocked.Increment(ref this.TotalDownloaded); + var addedNeedToDownload = Interlocked.Increment(ref this.NeedToDownload); + var progress = ProgressValue.Create(addedTotalDownloaded, addedNeedToDownload); this.InvokeStatusChangedEvent($"成功解析 MOD [{t.Item1}] 的下载地址", progress); @@ -185,8 +186,9 @@ public async Task InstallTaskAsync() ? $"...{subPath[(subPathLength - 15)..]}" : subPath; - this.InvokeStatusChangedEvent($"解压缩安装文件:{subPathName}", - (double)this.TotalDownloaded / this.NeedToDownload * 100); + var progress = ProgressValue.Create(this.TotalDownloaded, this.NeedToDownload); + + this.InvokeStatusChangedEvent($"解压缩安装文件:{subPathName}", progress); await using var fs = File.OpenWrite(path); entry.WriteTo(fs); @@ -194,7 +196,7 @@ public async Task InstallTaskAsync() this.TotalDownloaded++; } - this.InvokeStatusChangedEvent("安装完成", 100); + this.InvokeStatusChangedEvent("安装完成", ProgressValue.Finished); } public async Task ReadManifestTask() diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModPackInstallerBase.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModPackInstallerBase.cs index fbc96b3..7696379 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModPackInstallerBase.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModPackInstallerBase.cs @@ -16,7 +16,7 @@ protected void WhenCompleted(object? sender, DownloadFileCompletedEventArgs e) this.TotalDownloaded++; - var progress = (double)this.TotalDownloaded / this.NeedToDownload * 100; + var progress = ProgressValue.Create(this.TotalDownloaded, this.NeedToDownload); var retryStr = file.RetryCount > 0 ? $"[重试 - {file.RetryCount}] " : string.Empty; var fileName = file.FileName.Length > 20 ? $"{file.FileName[..20]}..." diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs index 6fb18e1..b4a64f2 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs @@ -5,6 +5,7 @@ using System.Text.Json; using System.Threading.Tasks; using ProjBobcat.Class.Helper; +using ProjBobcat.Class.Model; using ProjBobcat.Class.Model.Downloading; using ProjBobcat.Class.Model.Modrinth; using ProjBobcat.Interface; @@ -48,7 +49,7 @@ public async Task InstallTaskAsync() if (string.IsNullOrEmpty(this.RootPath)) throw new ArgumentNullException(nameof(this.RootPath)); - this.InvokeStatusChangedEvent("开始安装", 0); + this.InvokeStatusChangedEvent("开始安装", ProgressValue.Start); var index = await this.ReadIndexTask(); @@ -134,8 +135,9 @@ public async Task InstallTaskAsync() ? $"...{subPath[(subPathLength - 15)..]}" : subPath; - this.InvokeStatusChangedEvent($"解压缩安装文件:{subPathName}", - (double)this.TotalDownloaded / this.NeedToDownload * 100); + var progress = ProgressValue.Create(this.TotalDownloaded, this.NeedToDownload); + + this.InvokeStatusChangedEvent($"解压缩安装文件:{subPathName}", progress); await using var fs = File.OpenWrite(path); entry.WriteTo(fs); @@ -143,6 +145,6 @@ public async Task InstallTaskAsync() this.TotalDownloaded++; } - this.InvokeStatusChangedEvent("安装完成", 100); + this.InvokeStatusChangedEvent("安装完成", ProgressValue.Finished); } } \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs index fcdadee..97b0e20 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs @@ -36,7 +36,7 @@ public async Task InstallTaskAsync() if (this.OptifineDownloadVersion == null) throw new NullReferenceException("未指定 Optifine 下载信息"); - this.InvokeStatusChangedEvent("开始安装 Optifine", 0); + this.InvokeStatusChangedEvent("开始安装 Optifine", ProgressValue.Start); var mcVersion = this.OptifineDownloadVersion.McVersion; var edition = this.OptifineDownloadVersion.Type; var release = this.OptifineDownloadVersion.Patch; @@ -51,7 +51,7 @@ public async Task InstallTaskAsync() if (!di.Exists) di.Create(); - this.InvokeStatusChangedEvent("读取 Optifine 数据", 20); + this.InvokeStatusChangedEvent("读取 Optifine 数据", ProgressValue.FromDisplay(20)); using var archive = ArchiveFactory.Open(this.OptifineJarPath); var entries = archive.Entries; @@ -70,7 +70,7 @@ public async Task InstallTaskAsync() var launchWrapperEntry = entries.FirstOrDefault(x => x.Key?.Equals($"launchwrapper-of-{launchWrapperVersion}.jar") ?? false); - this.InvokeStatusChangedEvent("生成版本总成", 40); + this.InvokeStatusChangedEvent("生成版本总成", ProgressValue.FromDisplay(40)); var versionModel = new RawVersionModel { @@ -115,7 +115,7 @@ public async Task InstallTaskAsync() launchWrapperVersion); var libDi = new DirectoryInfo(librariesPath); - this.InvokeStatusChangedEvent("写入 Optifine 数据", 60); + this.InvokeStatusChangedEvent("写入 Optifine 数据", ProgressValue.FromDisplay(60)); if (!libDi.Exists) libDi.Create(); @@ -124,7 +124,7 @@ public async Task InstallTaskAsync() $"launchwrapper-of-{launchWrapperVersion}.jar"); if (!File.Exists(launchWrapperPath) && launchWrapperEntry != null) { - this.InvokeStatusChangedEvent($"解压 launcherwrapper-{launchWrapperVersion} 数据", 65); + this.InvokeStatusChangedEvent($"解压 launcherwrapper-{launchWrapperVersion} 数据", ProgressValue.FromDisplay(65)); await using var launchWrapperFs = File.OpenWrite(launchWrapperPath); launchWrapperEntry.WriteTo(launchWrapperFs); @@ -140,7 +140,7 @@ public async Task InstallTaskAsync() if (!optifineLibPathDi.Exists) optifineLibPathDi.Create(); - this.InvokeStatusChangedEvent("执行安装脚本", 80); + this.InvokeStatusChangedEvent("执行安装脚本", ProgressValue.FromDisplay(80)); var ps = new ProcessStartInfo(this.JavaExecutablePath) { @@ -165,7 +165,7 @@ public async Task InstallTaskAsync() void LogReceivedEvent(object sender, DataReceivedEventArgs args) { - this.InvokeStatusChangedEvent(args.Data ?? "loading...", 85); + this.InvokeStatusChangedEvent(args.Data ?? "loading...", ProgressValue.FromDisplay(85)); } p.OutputDataReceived += LogReceivedEvent; @@ -180,12 +180,12 @@ void LogReceivedEvent(object sender, DataReceivedEventArgs args) }; await p.WaitForExitAsync(); - this.InvokeStatusChangedEvent("安装即将完成", 90); + this.InvokeStatusChangedEvent("安装即将完成", ProgressValue.FromDisplay(95)); if (errList.Count > 0) throw new NullReferenceException(string.Join(Environment.NewLine, errList)); - this.InvokeStatusChangedEvent("Optifine 安装完成", 100); + this.InvokeStatusChangedEvent("Optifine 安装完成", ProgressValue.Finished); return id; } diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/QuiltInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/QuiltInstaller.cs index 2f19ad0..ca0932d 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/QuiltInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/QuiltInstaller.cs @@ -30,7 +30,7 @@ public string Install() public async Task InstallTaskAsync() { - this.InvokeStatusChangedEvent("开始安装", 0); + this.InvokeStatusChangedEvent("开始安装", ProgressValue.Start); var url = $"{DefaultMetaUrl}/v3/versions/loader/{this.MineCraftVersion}/{this.LoaderArtifact.Version}/profile/json"; @@ -46,7 +46,7 @@ public async Task InstallTaskAsync() }; var versionModel = await res.Content.ReadFromJsonAsync(new RawVersionModelContext(jsonOption).RawVersionModel); - this.InvokeStatusChangedEvent("生成版本总成", 70); + this.InvokeStatusChangedEvent("生成版本总成", ProgressValue.FromDisplay(50)); if (versionModel == null) throw new NullReferenceException(nameof(versionModel)); @@ -83,11 +83,11 @@ public async Task InstallTaskAsync() var jsonContent = JsonSerializer.Serialize(versionModel, typeof(RawVersionModel), new RawVersionModelContext(JsonHelper.CamelCasePropertyNamesSettings())); - this.InvokeStatusChangedEvent("将版本 Json 写入文件", 90); + this.InvokeStatusChangedEvent("将版本 Json 写入文件", ProgressValue.FromDisplay(90)); await File.WriteAllTextAsync(jsonPath, jsonContent); - this.InvokeStatusChangedEvent("安装完成", 100); + this.InvokeStatusChangedEvent("安装完成", ProgressValue.Finished); return id; } diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/AssetInfoResolver.cs b/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/AssetInfoResolver.cs index cfd32e9..0088c8d 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/AssetInfoResolver.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/AssetInfoResolver.cs @@ -34,14 +34,14 @@ public override async IAsyncEnumerable ResolveResourceAsync() { if (!this.CheckLocalFiles) yield break; - this.OnResolve("开始进行游戏资源(Asset)检查"); + this.OnResolve("开始进行游戏资源(Asset)检查", ProgressValue.Start); if (this.VersionInfo.AssetInfo == null) yield break; var versions = this.Versions; if ((this.Versions?.Count ?? 0) == 0) { - this.OnResolve("没有提供 Version Manifest, 开始下载"); + this.OnResolve("没有提供 Version Manifest, 开始下载", ProgressValue.Start); using var vmJsonRes = await HttpHelper.Get(DefaultVersionManifestUrl); var vm = await vmJsonRes.Content.ReadFromJsonAsync(VersionManifestContext.Default.VersionManifest); @@ -70,7 +70,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() var assetIndexesPath = Path.Combine(assetIndexesDi.FullName, $"{id}.json"); if (!File.Exists(assetIndexesPath)) { - this.OnResolve("没有发现 Asset Indexes 文件, 开始下载"); + this.OnResolve("没有发现 Asset Indexes 文件, 开始下载", ProgressValue.Start); var assetIndexDownloadUri = this.VersionInfo.AssetInfo?.Url; @@ -112,14 +112,14 @@ public override async IAsyncEnumerable ResolveResourceAsync() } catch (Exception e) { - this.OnResolve($"解析Asset Indexes 文件失败!原因:{e.Message}"); + this.OnResolve($"解析Asset Indexes 文件失败!原因:{e.Message}", ProgressValue.Start); yield break; } - this.OnResolve("Asset Indexes 文件下载完成", 100); + this.OnResolve("Asset Indexes 文件下载完成", ProgressValue.Finished); } - this.OnResolve("开始解析Asset Indexes 文件..."); + this.OnResolve("开始解析Asset Indexes 文件...", ProgressValue.Start); AssetObjectModel? assetObject; try @@ -130,7 +130,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() } catch (Exception ex) { - this.OnResolve($"解析Asset Indexes 文件失败!原因:{ex.Message}"); + this.OnResolve($"解析Asset Indexes 文件失败!原因:{ex.Message}", ProgressValue.Start); try { @@ -145,7 +145,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() if (assetObject == null) { - this.OnResolve("解析Asset Indexes 文件失败!原因:文件可能损坏或为空"); + this.OnResolve("解析Asset Indexes 文件失败!原因:文件可能损坏或为空", ProgressValue.Start); try { @@ -161,7 +161,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() var checkedObject = 0; var objectCount = assetObject.Objects.Count; - this.OnResolve("检索并验证 Asset 资源"); + this.OnResolve("检索并验证 Asset 资源", ProgressValue.Start); foreach (var (key, fi) in assetObject.Objects) { @@ -170,8 +170,9 @@ public override async IAsyncEnumerable ResolveResourceAsync() var path = Path.Combine(assetObjectsDi.FullName, twoDigitsHash); var filePath = Path.Combine(path, fi.Hash); - Interlocked.Increment(ref checkedObject); - var progress = (double)checkedObject / objectCount * 100; + var addedCheckedObject = Interlocked.Increment(ref checkedObject); + var progress = ProgressValue.Create(addedCheckedObject, objectCount); + this.OnResolve(key.CropStr(20), progress); if (File.Exists(filePath)) @@ -194,6 +195,6 @@ public override async IAsyncEnumerable ResolveResourceAsync() }; } - this.OnResolve("Assets 解析完成", 100); + this.OnResolve("Assets 解析完成", ProgressValue.Finished); } } \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/LibraryInfoResolver.cs b/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/LibraryInfoResolver.cs index 4a563a7..7d45ae8 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/LibraryInfoResolver.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/LibraryInfoResolver.cs @@ -24,7 +24,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() { if (!this.CheckLocalFiles) yield break; - this.OnResolve("开始进行游戏资源(Library)检查"); + this.OnResolve("开始进行游戏资源(Library)检查", ProgressValue.Start); if (this.VersionInfo.Natives.Count == 0 && this.VersionInfo.Libraries.Count == 0) yield break; @@ -41,8 +41,8 @@ public override async IAsyncEnumerable ResolveResourceAsync() var libPath = GamePathHelper.GetLibraryPath(lib.Path!); var filePath = Path.Combine(this.BasePath, libPath); - Interlocked.Increment(ref checkedLib); - var progress = (double)checkedLib / libCount * 100; + var addedCheckedLib = Interlocked.Increment(ref checkedLib); + var progress = ProgressValue.Create(addedCheckedLib, libCount); this.OnResolve(string.Empty, progress); @@ -59,7 +59,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() yield return this.GetDownloadFile(lib); } - this.OnResolve("检索并验证 Library"); + this.OnResolve("检索并验证 Library", ProgressValue.Start); checkedLib = 0; libCount = this.VersionInfo.Natives.Count; @@ -74,8 +74,9 @@ public override async IAsyncEnumerable ResolveResourceAsync() { if (string.IsNullOrEmpty(native.FileInfo.Sha1)) continue; - Interlocked.Increment(ref checkedLib); - var progress = (double)checkedLib / libCount * 100; + var addedCheckedLib = Interlocked.Increment(ref checkedLib); + var progress = ProgressValue.Create(addedCheckedLib, libCount); + this.OnResolve(string.Empty, progress); await using var fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); @@ -87,7 +88,7 @@ public override async IAsyncEnumerable ResolveResourceAsync() yield return this.GetDownloadFile(native.FileInfo); } - this.OnResolve("检查Library完成", 100); + this.OnResolve("检查Library完成", ProgressValue.Finished); } LibraryDownloadInfo GetDownloadFile(FileInfo lL) diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/ResolverBase.cs b/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/ResolverBase.cs index 5b905a6..f043ceb 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/ResolverBase.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/ResourceInfoResolver/ResolverBase.cs @@ -35,7 +35,7 @@ public void Dispose() GC.SuppressFinalize(this); } - public virtual void OnResolve(string currentStatus, double progress = 0) + public virtual void OnResolve(string currentStatus, ProgressValue progress) { var eventList = this._listEventDelegates; var @event = (EventHandler)eventList[ResolveEventKey]!; diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Service/ServerPingService.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Service/ServerPingService.cs index 569332d..496f166 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Service/ServerPingService.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Service/ServerPingService.cs @@ -54,18 +54,18 @@ public override string ToString() throw new OperationCanceledException($"服务器 {this} 连接失败,连接超时 ({timeOut.Seconds}s)。", cts.Token); } - this.InvokeStatusChangedEvent("正在连接到服务器...", 10); + this.InvokeStatusChangedEvent("正在连接到服务器...", ProgressValue.FromDisplay(10)); if (!client.Connected) { - this.InvokeStatusChangedEvent("无法连接到服务器", 10); + this.InvokeStatusChangedEvent("无法连接到服务器", ProgressValue.Finished); return null; } this._buffer = []; this._stream = client.GetStream(); - this.InvokeStatusChangedEvent("发送请求...", 30); + this.InvokeStatusChangedEvent("发送请求...", ProgressValue.FromDisplay(30)); /* * Send a "Handshake" packet @@ -118,7 +118,7 @@ public override string ToString() var packet = this.ReadVarInt(buffer); var jsonLength = this.ReadVarInt(buffer); - this.InvokeStatusChangedEvent($"收到包 0x{packet:X2} , 长度为 {length}", 80); + this.InvokeStatusChangedEvent($"收到包 0x{packet:X2} , 长度为 {length}", ProgressValue.FromDisplay(80)); var json = this.ReadString(buffer, jsonLength); var ping = JsonSerializer.Deserialize(json, PingPayloadContext.Default.PingPayload); @@ -126,6 +126,8 @@ public override string ToString() if (ping == null) return null; + this.InvokeStatusChangedEvent("查询完成", ProgressValue.Finished); + return new ServerPingResult { Latency = latency, diff --git a/ProjBobcat/ProjBobcat/Event/DownloadFileChangedEventArgs.cs b/ProjBobcat/ProjBobcat/Event/DownloadFileChangedEventArgs.cs index ad92f5e..79a0a14 100644 --- a/ProjBobcat/ProjBobcat/Event/DownloadFileChangedEventArgs.cs +++ b/ProjBobcat/ProjBobcat/Event/DownloadFileChangedEventArgs.cs @@ -1,11 +1,12 @@ using System; +using ProjBobcat.Class.Model; namespace ProjBobcat.Event; public class DownloadFileChangedEventArgs : EventArgs { public double Speed { get; init; } - public double ProgressPercentage { get; init; } + public ProgressValue ProgressPercentage { get; init; } public long BytesReceived { get; init; } public long? TotalBytes { get; init; } } \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/Event/ForgeInstallStageChangedEventArgs.cs b/ProjBobcat/ProjBobcat/Event/ForgeInstallStageChangedEventArgs.cs index a92a4f8..e3d8520 100644 --- a/ProjBobcat/ProjBobcat/Event/ForgeInstallStageChangedEventArgs.cs +++ b/ProjBobcat/ProjBobcat/Event/ForgeInstallStageChangedEventArgs.cs @@ -1,9 +1,10 @@ using System; +using ProjBobcat.Class.Model; namespace ProjBobcat.Event; public class ForgeInstallStageChangedEventArgs : EventArgs { public required string CurrentStage { get; init; } - public double Progress { get; init; } + public ProgressValue Progress { get; init; } } \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/Event/GameResourceInfoResolveEventArgs.cs b/ProjBobcat/ProjBobcat/Event/GameResourceInfoResolveEventArgs.cs index 401da3d..49cfa9f 100644 --- a/ProjBobcat/ProjBobcat/Event/GameResourceInfoResolveEventArgs.cs +++ b/ProjBobcat/ProjBobcat/Event/GameResourceInfoResolveEventArgs.cs @@ -1,9 +1,10 @@ using System; +using ProjBobcat.Class.Model; namespace ProjBobcat.Event; public class GameResourceInfoResolveEventArgs : EventArgs { - public required double Progress { get; init; } + public required ProgressValue Progress { get; init; } public string? Status { get; init; } } \ No newline at end of file diff --git a/ProjBobcat/ProjBobcat/Event/InstallerStageChangedEventArgs.cs b/ProjBobcat/ProjBobcat/Event/InstallerStageChangedEventArgs.cs index 0857dbb..934bdc9 100644 --- a/ProjBobcat/ProjBobcat/Event/InstallerStageChangedEventArgs.cs +++ b/ProjBobcat/ProjBobcat/Event/InstallerStageChangedEventArgs.cs @@ -1,9 +1,10 @@ using System; +using ProjBobcat.Class.Model; namespace ProjBobcat.Event; public class StageChangedEventArgs : EventArgs { public required string CurrentStage { get; init; } - public required double Progress { get; init; } + public required ProgressValue Progress { get; init; } } \ No newline at end of file