Skip to content

合并开发分支,自动构建#50

Merged
BlameTwo merged 41 commits intomasterfrom
development
Apr 6, 2026
Merged

合并开发分支,自动构建#50
BlameTwo merged 41 commits intomasterfrom
development

Conversation

@BlameTwo
Copy link
Copy Markdown
Collaborator

@BlameTwo BlameTwo commented Apr 6, 2026

  1. 重构V2核心
  2. 删除游戏增加二次确认对话框
  3. 增强异步性能

Copilot AI review requested due to automatic review settings April 6, 2026 16:28
@BlameTwo BlameTwo merged commit ccf0186 into master Apr 6, 2026
2 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 主要在现有启动器/工具中引入“V2 核心”与配套 UI(V2 游戏页、V2 选择目录对话框、删除资源二次确认/进度对话框),并在 Waves.Core 中新增事件发布/进度跟踪与新下载/解压相关实现,以提升异步性能与可维护性。

Changes:

  • 新增 V2 GameContext(Waves/Punish)及其 DI 注册、页面入口与导航项
  • 新增/调整下载、预下载、安装资源流程的事件发布与进度跟踪(GameEventPublisher / GameProgressTracker 等)
  • 安装/卸载流程增强:生成卸载快照、卸载时检测进程、删除资源对话框等

Reviewed changes

Copilot reviewed 104 out of 105 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/WutheringWavesTool/ViewModel/GameViewModels/KuroGameContextViewModelV2/KuroGameContextViewModelV2.StartGame.cs V2 启动/更新/预下载入口命令
src/WutheringWavesTool/ViewModel/GameViewModels/KuroGameContextViewModelV2/KuroGameContextViewModelV2.Predownloader.cs V2 预下载卡片与控制命令
src/WutheringWavesTool/ViewModel/GameViewModels/KuroGameContextViewModelV2/KuroGameContextViewModelV2.Downloader.cs V2 下载进度/暂停/取消/限速命令
src/WutheringWavesTool/ViewModel/GameViewModels/KuroGameContextViewModelV2/KuroGameContextViewModelV2.Common.cs V2 集合替换判定辅助方法
src/WutheringWavesTool/ViewModel/GameViewModels/KuroGameContextViewModel/KuroGameContextViewModel.Downloader.cs 旧 VM 下载事件类型适配(BottomText)
src/WutheringWavesTool/ViewModel/GameViewModels/GameContextsV2/WavesV2GameContextViewModel.cs Waves V2 页面 VM 壳
src/WutheringWavesTool/ViewModel/GameViewModels/GameContextsV2/PunishV2GameContextViewModel.cs Punish V2 页面 VM 壳
src/WutheringWavesTool/ViewModel/DialogViewModels/SelectGameFolderViewModelV2.cs V2 选择游戏 EXE + 磁盘信息展示
src/WutheringWavesTool/ViewModel/DialogViewModels/DeleteFileViewModel.cs 删除资源二次确认/进度 VM
src/WutheringWavesTool/Services/PageService.cs 注册 V2 游戏页与 VM
src/WutheringWavesTool/Services/DialogManager.cs 新增 V2 对话框入口与删除资源对话框;修复 _dialog 清理
src/WutheringWavesTool/Services/Contracts/IDialogManager.cs DialogManager 接口扩展(V2 + 删除资源)
src/WutheringWavesTool/Services/AppContext.cs 启动时初始化 V2 GameContext
src/WutheringWavesTool/Pages/ShellPage.xaml.cs 导航动画包含 V2 游戏页
src/WutheringWavesTool/Pages/ShellPage.xaml NavigationView 增加 V2 游戏入口项
src/WutheringWavesTool/Pages/GamePages/WavesV2GamePage.xaml.cs Waves V2 页面 code-behind
src/WutheringWavesTool/Pages/GamePages/PunishV2GamePage.xaml.cs Punish V2 页面 code-behind
src/WutheringWavesTool/Pages/Dialogs/SelectGameFolderDialogV2.xaml.cs 选择游戏目录 V2 对话框封装
src/WutheringWavesTool/Pages/Dialogs/SelectGameFolderDialogV2.xaml 选择游戏目录 V2 UI
src/WutheringWavesTool/Pages/Dialogs/SelectDownoadGameDialogV2.xaml.cs 选择下载目录 V2 对话框逻辑
src/WutheringWavesTool/Pages/Dialogs/SelectDownoadGameDialogV2.xaml 选择下载目录 V2 UI
src/WutheringWavesTool/Pages/Dialogs/DeleteFileDialog.xaml.cs 删除资源对话框封装
src/WutheringWavesTool/Pages/Dialogs/DeleteFileDialog.xaml 删除资源对话框 UI
src/WutheringWavesTool/Models/ServerDisplay.cs 增加 V2 服务器/上下文列表
src/WutheringWavesTool/Instance.cs DI 注册 V2 VM / V2 对话框 / 删除对话框
src/WutheringWavesTool/Haiyu.csproj 包版本调整与新增 XAML/资源编译项
src/WutheringWavesTool/Converter/DownloadState/StepConverter.cs 新增步骤 OK 颜色/可见性转换器
src/WutheringWavesTool/Controls/Styles/ToolTipStyle.xaml BOM/头部微调
src/WutheringWavesTool/Controls/Styles/StorageRing.xaml 引入 StorageRing 样式资源
src/WutheringWavesTool/Controls/Styles/NavigationView.xaml NavItem 模板支持 InfoBadge
src/WutheringWavesTool/Controls/StorageRing/ThicknessCheck.cs StorageRing 辅助枚举
src/WutheringWavesTool/Controls/StorageRing/StorageRing.Properties.cs StorageRing 依赖属性实现
src/WutheringWavesTool/Controls/StorageRing/RingShape/RingShape.Properties.cs RingShape 依赖属性实现
src/WutheringWavesTool/Common/StorageControlsHelpers.cs StorageRing/Bar 数学辅助函数
src/WutheringWavesTool/Behaviors/HoverOpenCloseFlyoutBehavior.cs Hover 打开/关闭 Flyout 行为
src/WutheringWavesTool/App.xaml 资源合并:引入 StorageRing,注释 ToolTipStyle
src/WutheringWavesTool.slnx 从解决方案移除 Haiyu.Run 项目
src/Waves.Core/Waves.cs DI 注册 V2 GameContext 与事件发布器
src/Waves.Core/Services/GameProgressTracker.cs 新增事件驱动的进度跟踪器
src/Waves.Core/Services/GameEventPublisher.cs 新增 Channel 分发的事件发布器
src/Waves.Core/Models/KrDiffDecompressResult.cs 新增 krdiff 解压结果数据结构
src/Waves.Core/Models/IProgressSetup.cs 新增步骤执行接口抽象
src/Waves.Core/Models/GameContextStatus.cs 调整字段顺序/保留预下载状态字段
src/Waves.Core/Models/GameContextOutputArgs.cs 扩展输出参数:步骤/单文件/预下载/ZipSpeed 等
src/Waves.Core/Models/Enums/InstallGameResourceType.cs 新增安装资源类型枚举
src/Waves.Core/Models/Enums/GameContextActionType.cs 调整/新增动作类型(BottomText/ZipDecompress/PublishStep 等)
src/Waves.Core/Models/DownloadUpdateFolderConfig.cs 新增更新下载目录配置模型
src/Waves.Core/Models/DownloadActiveItemItem.cs 新增活跃文件/步骤项模型
src/Waves.Core/INI/Ini.cs 字符串/注释行缩进调整(编码仍异常)
src/Waves.Core/Helpers/BuildFileHelper.cs 新增磁盘可用空间获取方法
src/Waves.Core/GameContext/KuroGameContextBase/KuroGameContextBase.Predownload.cs DownloadState CancelToken 类型适配
src/Waves.Core/GameContext/KuroGameContextBase/KuroGameContextBase.GameStart.cs 命名空间/结构整理与启动逻辑重排
src/Waves.Core/GameContext/KuroGameContextBase/KuroGameContextBase.Downloader.cs 删除阶段输出类型改为 BottomText
src/Waves.Core/GameContext/KuroGameContextBase/Commons/DownloadMethod.cs 调整 Md5 校验移动文件阶段输出类型
src/Waves.Core/GameContext/KuroGameContextBase/Commons/DownloadData.cs 移除 GetVerifyLimit(逻辑迁移/废弃)
src/Waves.Core/GameContext/KruoGameContextBaseV2/KuroGameContextBaseV2.Setup.cs V2 步骤列表占位
src/Waves.Core/GameContext/KruoGameContextBaseV2/KuroGameContextBaseV2.Launcher.cs V2 Launcher/资源索引拉取实现
src/Waves.Core/GameContext/KruoGameContextBaseV2/KuroGameContextBaseV2.Download.cs V2 下载/修复入口与 CDN 测试逻辑
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/WriteGameResourceConfig.cs 下载完成/取消后的配置写入
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/UIActionSetup.cs 删除空占位类
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/InstallUpdateResource.cs 安装更新资源占位
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/InstallKrZipResource.cs Zip 解压安装步骤实现
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/InstallKrdiffResource.cs krdiff 安装步骤实现
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/InstallKrdiffGroupResource.cs krdiff group 安装步骤实现
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/FilesAction/MoveFileResource.cs 批量移动文件步骤实现
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/FilesAction/DeleteFileResource.cs 批量删除文件步骤占位
src/Waves.Core/GameContext/KruoGameContextBaseV2/Common/DownloadAndVerifyResource.cs 并行下载+校验核心实现
src/Waves.Core/GameContext/GameContextFactory.cs 新增 V2 Context 工厂方法
src/Waves.Core/GameContext/ContextsV2/WavesMainGameContextV2.cs Waves V2 Context 定义
src/Waves.Core/GameContext/ContextsV2/PunishMainGameContextV2.cs Punish V2 Context 定义
src/Waves.Core/Contracts/IGameContextV2.cs V2 Context 接口定义
src/Waves.Core/Contracts/Events/IGameEventSubscription.cs 事件订阅 token 接口
src/Waves.Core/Contracts/Events/IGameEventPublisher.cs 事件发布器接口
src/Waves.Core/Common/ProcessScan.cs 清理 Debug 输出与注释
src/Waves.Core/Common/DownloadState.cs CancelToken 改为 CTS;暂停/恢复更新 IsActive
src/Waves.Core/Common/Downloads/VerifyTask.cs 新增/重构校验实现
src/Waves.Core/Common/Downloads/UnZipTask.cs 新增 Zip 解压实现与进度上报
src/Waves.Core/Common/Downloads/DownloadTask.cs 新增分片/全量下载实现与进度上报
src/Waves.Core/Common/Downloads/DiffDecompressTask.cs 新增 krdiff 解压任务封装
src/Waves.Core/Common/Downloads/DeleteFileTask.cs 删除任务占位
src/Waves.Core/Common/DownloadExtension.cs 新增参数校验/事件发布扩展(新语法)
src/Waves.Core/Common/DiffDecompressManagerV2.cs 新增共享内存驱动的 hpatchz 进度读取
src/Waves.Core/Common/CDNSpeedTester.cs CDN 测速能力增强与 API 调整
src/Setup/Project.WPFSetup/Views/UninstallView.xaml Loaded 触发命令(Behaviors)
src/Setup/Project.WPFSetup/ViewModels/UserViewModels/UninstallViewModel.cs 卸载完成提示 + Loaded 时检测并关闭进程
src/Setup/Project.WPFSetup/ViewModels/UserViewModels/InstallViewModel.cs 安装路径选择/创建目录逻辑优化
src/Setup/Project.WPFSetup/Project.WPFSetup.csproj 引入 System.Text.Json
src/Setup/Project.WPFSetup/Common/Setups/UninstallDeleteInstallFolderSetup.cs 卸载时按快照删除文件
src/Setup/Project.WPFSetup/Common/Setups/DeleteInstallFolderSetup.cs 删除安装目录逻辑改为按快照清理
src/Setup/Project.WPFSetup/Common/Setups/DecompressionSetup.cs 解压时生成卸载快照(unstall.dat)
src/Setup/Project.WPFSetup/Common/SetupProperty.cs HelpLink 指向 issues
src/Project.WPFUninstaller/MainWindow.xaml.cs code-behind 继承声明调整
src/KuroGameDownloadProgram/Program.cs 使用 V2 Context 的控制台下载/安装测试程序
src/KuroGameDownloadProgram/KuroGameDownloadProgram.csproj TFM 改为 net10.0-windows;复制 hpatchz.exe
src/Haiyu.Run/Program.cs 删除空项目入口
src/Haiyu.Run/Haiyu.Run.csproj 删除空项目工程文件

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

: base(config, name) { }

public override Type ContextType => typeof(WavesMainGameContextV2);
public override GameType GameType => GameType.Punish;
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WavesMainGameContextV2 的 GameType 返回了 GameType.Punish,这会导致“鸣潮V2”上下文被当成战双处理(例如启动参数、资源/配置选择、UI 展示)。这里应返回对应的 Waves 类型。

Suggested change
public override GameType GameType => GameType.Punish;
public override GameType GameType => GameType.Waves;

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +27
<ProgressBar
Grid.Row="1"
MaxHeight="{x:Bind ViewModel.MaxTotal, Mode=OneWay}"
HorizontalAlignment="Stretch"
Value="{x:Bind ViewModel.Current, Mode=OneWay}" />
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DeleteFileDialog 的 ProgressBar 使用了 MaxHeight 绑定 MaxTotal。MaxHeight 只影响控件布局高度,无法设置进度条上限,导致进度显示不会按总量变化。这里应绑定到 ProgressBar 的 Maximum(并按需设置 Height)。

Copilot uses AI. Check for mistakes.
Comment on lines +24 to 45
var uninstallDat =Path.Combine(installFolder, "unstall.dat");
if (File.Exists(uninstallDat))
{
try
var reader = File.OpenText(uninstallDat);
var list = JsonSerializer.Deserialize<List<string>>(await reader.ReadToEndAsync());
while (true)
{
if (!Directory.Exists(directoryPath))
{
Console.WriteLine("指定的目录不存在。");
return true;
}
foreach (
var file in Directory.GetFiles(
directoryPath,
"*.*",
SearchOption.TopDirectoryOnly
)
)
try
{
if (file.StartsWith(setupProperty.UninstallName))
{
continue;
}
try
{
File.Delete(file);
Console.WriteLine($"已删除文件: {file}");
}
catch (Exception ex)
foreach (var file in list)
{
Console.WriteLine($"无法删除文件 {file}: {ex.Message}");
if (File.Exists(file))
{
File.Delete(file);
}
}
break;
}
foreach (
var dir in Directory.GetDirectories(
directoryPath,
"*",
SearchOption.TopDirectoryOnly
)
)
catch
{
try
{
Directory.Delete(dir, true);
}
catch (Exception) { }
}
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里对 uninstall.dat 的删除采用 while(true)+空 catch 的方式:一旦遇到权限/占用等异常会无限重试并卡死卸载流程。同时 reader 未 Dispose 也可能导致文件一直被占用。建议改为有限次数重试/退避并在 finally 中释放 reader,必要时将失败项记录并继续。

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +65
if (status.IsPause || GameContext.ProdDownloadState.IsPaused)
{
await this.GameContext.ResumeDownloadAsync();
this.PreDownloadIcon = "\uE768";
}
else
{
await this.GameContext.PauseDownloadAsync();
this.PreDownloadIcon = "\uE768";
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StartDownloadProdGameResource 中暂停/恢复两条分支都把 PreDownloadIcon 设置为同一个 Glyph(\uE768)。这会导致 UI 无法反映当前状态(暂停 vs 恢复)。建议分别设置为对应的“暂停/播放”图标并与现有 Predownload 卡片逻辑保持一致。

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +63
if (!Param.CheckParam<string>("diffFolderPath", out var diffFolderPath))
{
return false;
}
if(!Param.CheckParam<string>("gameBaseFolder",out var gameBaseFolder))
this.krdiffs = krdiffs!;
this.diffFolderPath = diffFolderPath!;
this.gameBaseFolder = gameBaseFolder!;
return true;
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CheckAsync 里对 "gameBaseFolder" 的 CheckParam 缺少大括号并且没有在失败时 return false;当前写法会在参数不存在时仍继续赋值,导致 gameBaseFolder 为空并在后续磁盘空间检查/路径拼接时抛异常。请补齐条件块并在校验失败时返回。

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +121
public void SetParam(Dictionary<string, object> param, IGameEventPublisher gameEventPublisher)
{
this.Param = param;
this.GameEventPublisher = GameEventPublisher;
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetParam(Dictionary<string, object>, IGameEventPublisher) 中把 this.GameEventPublisher 赋值成了 GameEventPublisher(自身属性),而不是传入的 gameEventPublisher。这样会导致 Publish 调用时 publisher 仍为 null。应改为使用方法参数赋值。

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +42
public void SetParam(Dictionary<string, object> param, GameEventPublisher gameEventPublisher)
{
this.Param = param;
this.GameEventPublisher = GameEventPublisher;
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetParam(Dictionary<string, object>, GameEventPublisher) 中把 this.GameEventPublisher 赋值成了 GameEventPublisher(自身属性),导致注入的 publisher 丢失,后续 Publish 会是 null 或旧实例。这里应赋值为传入的 gameEventPublisher(并建议参数类型用 IGameEventPublisher 以保持一致)。

Copilot uses AI. Check for mistakes.
Comment on lines +184 to +188
public static double GetInterpolatedAngle(double startAngle, double endAngle, double valueAngle)
{
// Linear interpolation formula (lerp): GetInterpolatedAngle = (startAngle + valueAngle) * (endAngle - startAngle)
return (startAngle + valueAngle) * (endAngle - startAngle);
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetInterpolatedAngle 的线性插值公式实现不正确:当前返回 (startAngle + valueAngle) * (endAngle - startAngle),会随着 startAngle 增大而放大比例,且在 valueAngle=0 时不等于 startAngle。这里应使用标准 lerp 形式 startAngle + valueAngle * (endAngle - startAngle)。

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants