public async Task InstallTaskAsync() { InvokeStatusChangedEvent("开始安装", 0); var manifest = await ReadManifestTask(); var idPath = Path.Combine(RootPath, GamePathHelper.GetGamePath(GameId)); var downloadPath = Path.Combine(Path.GetFullPath(idPath), "mods"); var di = new DirectoryInfo(downloadPath); if (!di.Exists) { di.Create(); } _needToDownload = manifest.Files.Count; var urlBlock = new TransformManyBlock <IEnumerable <CurseForgeFileModel>, ValueTuple <long, long> >(urls => { return(urls.Select(file => (file.ProjectId, file.FileId))); }); var actionBlock = new ActionBlock <ValueTuple <long, long> >(async t => { var downloadUrlRes = await CurseForgeAPIHelper.GetAddonDownloadUrl(t.Item1, t.Item2); var d = downloadUrlRes.Trim('"'); var fn = Path.GetFileName(d); var downloadFile = new DownloadFile { Completed = (_, args) => { _totalDownloaded++; _isModAllDownloaded = _isModAllDownloaded && (args.Success ?? false); // if (!args.Success) // throw args.Error; var progress = (double)_totalDownloaded / _needToDownload * 100; InvokeStatusChangedEvent($"下载整合包中的 Mods - {fn} ({_totalDownloaded} / {_needToDownload})", progress); }, DownloadPath = di.FullName, DownloadUri = d, FileName = fn // Host = "proxy.freecdn.workers.dev" }; await DownloadHelper.DownloadData(downloadFile); }, new ExecutionDataflowBlockOptions { BoundedCapacity = 32, MaxDegreeOfParallelism = 32 }); var linkOptions = new DataflowLinkOptions { PropagateCompletion = true }; urlBlock.LinkTo(actionBlock, linkOptions); urlBlock.Post(manifest.Files); urlBlock.Complete(); await actionBlock.Completion; _totalDownloaded = 0; if (!_isModAllDownloaded) { throw new NullReferenceException("未能下载全部的 Mods"); } using var archive = ArchiveFactory.Open(Path.GetFullPath(ModPackPath)); _totalDownloaded = 0; _needToDownload = archive.Entries.Count(); foreach (var entry in archive.Entries) { if (!entry.Key.StartsWith(manifest.Overrides, StringComparison.OrdinalIgnoreCase)) { continue; } var subPath = entry.Key[(manifest.Overrides.Length + 1)..].Replace('/', '\\');