Repository navigation
feat(resources): 添加资源更新回收站与单项、多选撤回 - #3647
HadesScience wants to merge 19 commits into
Conversation
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
AI-assisted implementation and verification using Codex (GPT-6). Submitted for human review.
审查者指南本 PR 引入了按实例游戏目录存储的资源更新回收站,以原子化文件移动、记录哈希校验和失败回滚支持单项及批量撤回;同时将该能力接入资源与存档数据包更新及 WPF 列表界面,并修复异步刷新、窄窗口布局和行按钮复用问题。 资源更新与撤回时序图sequenceDiagram
participant UI as Resource UI
participant Undo as ResourceUpdateUndo
participant Bin as ResourceUpdateRecycleBin
participant Disk as Game directory
UI->>Bin: Replace(originalPath, updatedPath, downloadedPath)
Bin->>Disk: Write update record with UpdatedHash
Bin->>Disk: Move originalPath to recycle backup
Bin->>Disk: Move downloadedPath to updatedPath
Bin-->>UI: Update complete
UI->>Undo: CreateButton(item, gameDirectory, refresh)
Undo->>Bin: CanUndo(item.Entry.path)
Bin->>Disk: Validate record, backup, and updated hash
Bin-->>Undo: Undo available
UI->>Bin: Undo(updatedPath)
Bin->>Disk: Move updated file to temporary path
Bin->>Disk: Move backup to original path
Bin->>Disk: Delete temporary updated file
Bin->>Disk: Delete update record
Bin-->>UI: Refresh resource list
批量资源撤回时序图sequenceDiagram
participant User as User
participant UI as Selection bar
participant Undo as ResourceUpdateUndo
participant Bin as ResourceUpdateRecycleBin
User->>UI: Click BtnSelectUndo
UI->>Undo: UndoSelectedAsync(gameDirectory, paths)
Undo->>Bin: UndoMany(paths)
loop Each distinct selected path
Bin->>Bin: CanUndo(path)
alt Eligible backup and matching updated file
Bin->>Bin: Undo(path)
Bin-->>Undo: Add to RestoredPaths
else No valid backup or record
Bin-->>Undo: Add to SkippedPaths
else Undo fails
Bin-->>Undo: Add to Failures
end
end
Undo-->>UI: Show restored, skipped, and failed counts
UI->>UI: Clear selection and reload list
文件级变更
可能相关的 Issue
提示和命令与 Sourcery 交互
自定义使用体验访问你的控制面板以:
获取帮助Original review guide in EnglishReviewer's Guide本 PR 引入了按实例游戏目录存储的资源更新回收站,以原子化文件移动、记录哈希校验和失败回滚支持单项及批量撤回;同时将该能力接入资源与存档数据包更新及 WPF 列表界面,并修复异步刷新、窄窗口布局和行按钮复用问题。 Sequence diagram for resource update and undosequenceDiagram
participant UI as Resource UI
participant Undo as ResourceUpdateUndo
participant Bin as ResourceUpdateRecycleBin
participant Disk as Game directory
UI->>Bin: Replace(originalPath, updatedPath, downloadedPath)
Bin->>Disk: Write update record with UpdatedHash
Bin->>Disk: Move originalPath to recycle backup
Bin->>Disk: Move downloadedPath to updatedPath
Bin-->>UI: Update complete
UI->>Undo: CreateButton(item, gameDirectory, refresh)
Undo->>Bin: CanUndo(item.Entry.path)
Bin->>Disk: Validate record, backup, and updated hash
Bin-->>Undo: Undo available
UI->>Bin: Undo(updatedPath)
Bin->>Disk: Move updated file to temporary path
Bin->>Disk: Move backup to original path
Bin->>Disk: Delete temporary updated file
Bin->>Disk: Delete update record
Bin-->>UI: Refresh resource list
Sequence diagram for bulk resource undosequenceDiagram
participant User as User
participant UI as Selection bar
participant Undo as ResourceUpdateUndo
participant Bin as ResourceUpdateRecycleBin
User->>UI: Click BtnSelectUndo
UI->>Undo: UndoSelectedAsync(gameDirectory, paths)
Undo->>Bin: UndoMany(paths)
loop Each distinct selected path
Bin->>Bin: CanUndo(path)
alt Eligible backup and matching updated file
Bin->>Bin: Undo(path)
Bin-->>Undo: Add to RestoredPaths
else No valid backup or record
Bin-->>Undo: Add to SkippedPaths
else Undo fails
Bin-->>Undo: Add to Failures
end
end
Undo-->>UI: Show restored, skipped, and failed counts
UI->>UI: Clear selection and reload list
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Keep automated regression tests in the existing PCL.Core.Test project. The WPF verification harness remains local-only and is excluded from the PR. AI-assisted update using Codex (GPT-6).
Rename the newly introduced private selection-margin and undo handlers to _PascalCase; update event bindings and call sites. Preserve existing file encodings. AI-assisted compliance review using Codex (GPT-6).
There was a problem hiding this comment.
嘿——我发现了 7 个问题
AI Agent 提示词
请处理本次代码审查中的评论:
## 单独评论
### 评论 1
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="228" />
<code_context>
+ private static string _GetContainedPath(string directory, string path)
+ {
+ path = Path.GetFullPath(path);
+ if (!path.StartsWith(directory + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ throw new ArgumentException("资源路径必须位于当前游戏目录内。", nameof(path));
+ return path;
</code_context>
<issue_to_address>
**文件可以逃逸出游戏目录**
当资源目录或回收站子目录是指向游戏目录外部的符号链接或 junction 时,`_GetContainedPath` 只检查规范化后的字符串前缀,因此 `Replace` 和 `Undo` 会跟随该链接,在预期目录之外移动或删除文件。
在允许文件操作前解析物理路径,或拒绝包含链接的路径组件。
</issue_to_address>
### 评论 2
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="76-80" />
<code_context>
+ try
+ {
+ File.WriteAllText(pendingRecordPath, JsonSerializer.Serialize(record));
+ File.Move(originalPath, backupPath);
+ backedUp = true;
+ File.Move(downloadedPath, updatedPath);
+ installed = true;
+ File.Move(pendingRecordPath, recordPath, true);
+ }
+ catch (Exception updateError)
</code_context>
<issue_to_address>
**中断的更新无法撤销**
当启动器或计算机在 `Replace` 或 `Undo` 执行文件移动期间终止时,异常处理程序无法在进程终止后回滚,并且启动时也不会恢复未完成的移动操作。原文件可能已经不存在,更新后的文件也可能仍以临时名称存在且没有可用记录,导致资源丢失或无法执行 Undo。
持久化可恢复的事务记录,并在启动时恢复未完成的 Replace 和 Undo 操作。
另见 `PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs:166-170`。
</issue_to_address>
### 评论 3
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="242-246" />
<code_context>
+
+ private static string _NormalizeResourcePath(string path)
+ {
+ while (path.EndsWith(".disabled", StringComparison.OrdinalIgnoreCase) ||
+ path.EndsWith(".old", StringComparison.OrdinalIgnoreCase))
+ path = path[..path.LastIndexOf('.')];
+ return path;
+ }
+
+ private static bool _SamePath(string left, string right) =>
</code_context>
<issue_to_address>
**启用和禁用状态的更新共用记录**
当同一资源的启用副本和禁用副本同时存在且都被更新时,`_GetRecordPath` 使用 `_NormalizeResourcePath`,该方法会移除 `.disabled` 和 `.old`,因此同时存在的启用和禁用副本会映射到同一个记录文件。后一次更新会覆盖前一次记录,而 `_TryReadRecord` 也会将两条路径视为等价;Undo 可能恢复兄弟副本的备份并丢弃所选文件,而不是恢复它自身的前一个版本。
应根据更新后的准确路径建立记录索引,并通过明确且无歧义的记录查找处理启用/禁用切换期间的文件名变化。
另见 `PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs:235-237`。
</issue_to_address>
### 评论 4
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="228-229" />
<code_context>
+ private static string _GetContainedPath(string directory, string path)
+ {
+ path = Path.GetFullPath(path);
+ if (!path.StartsWith(directory + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ throw new ArgumentException("资源路径必须位于当前游戏目录内。", nameof(path));
+ return path;
+ }
</code_context>
<issue_to_address>
**根目录中的资源会被拒绝**
当配置的游戏目录是卷根目录或共享根目录时,`_GetContainedPath` 会在检查前缀前向根目录追加分隔符,从而产生重复的分隔符,使有效的资源路径无法匹配。`Replace` 会拒绝更新,而 `CanUndo` 找不到符合条件的资源。
构造和检查包含关系前缀时,应处理文件系统根目录的情况。
另见 `PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs:23`。
</issue_to_address>
### 评论 5
<location path="Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs" line_range="2191" />
<code_context>
- {
- ModBase.Log($"[Mod] 更新后的目标文件夹已被删除:{Entry.Value}", ModBase.LogLevel.Debug);
- }
+ recycleBin.Replace(replacement.Original, replacement.Updated, replacement.Downloaded);
+ finishedFileNames.Add(ModBase.GetFileNameFromPath(replacement.Updated));
}
</code_context>
<issue_to_address>
**失败的更新会留下混合批次**
当多资源更新中的某个替换失败时,`recycleBin.Replace` 抛出的异常会停止循环,因此在较早资源成功后,后续资源不会被安装。完成处理程序只会报告笼统的失败,用户最终得到一个混合批次,也没有逐资源的结果摘要。
按资源处理替换失败,继续处理整个批次,并报告哪些资源成功、哪些资源失败。
另见 `Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs:1355`。
</issue_to_address>
### 评论 6
<location path="Plain Craft Launcher 2/Pages/PageInstance/ResourceUpdateUndo.cs" line_range="32-33" />
<code_context>
+
+ public static MyIconButton? CreateButton(MyLocalCompItem item, string gameDirectory, Action refresh)
+ {
+ var recycleBin = new ResourceUpdateRecycleBin(gameDirectory);
+ if (item.Entry.IsFolder || !recycleBin.CanUndo(item.Entry.path)) return null;
+
+ var button = new MyIconButton { LogoScale = 1d, SvgIcon = "lucide/rotate-ccw", Tag = item };
</code_context>
<issue_to_address>
**大型资源会冻结界面**
当更新后的资源很大或存储设备速度较慢时,`CreateButton` 会调用 `CanUndo`,点击处理程序会调用 `Undo`;两者都会在 UI 线程上同步计算整个更新文件的哈希。因此,创建或刷新行以及点击 Undo 时,磁盘 I/O 都会阻塞界面。
将文件哈希计算移出 UI 线程,或避免在创建行和 Undo 过程中重复同步计算完整文件哈希。
另见 `Plain Craft Launcher 2/Pages/PageInstance/ResourceUpdateUndo.cs:45`、`Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs:689`、`Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs:333`。
</issue_to_address>
### 评论 7
<location path="Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs" line_range="2120" />
<code_context>
var fileCopyList = new Dictionary<string, string>();
+ var replacements = new List<(string Original, string Downloaded, string Updated)>();
+ var recycleBin = new ResourceUpdateRecycleBin(PageInstanceLeft.McInstance.PathIndie);
+ var tempRoot = Path.Combine(ModBase.pathTemp, "DownloadedComp", Guid.NewGuid().ToString("N"));
foreach (var Entry in modList)
{
</code_context>
<issue_to_address>
**临时目录不断累积**
资源反复更新时,每次运行都会创建唯一的临时根目录和每个资源对应的目录,但完成清理只会删除已下载的文件。空目录会不断累积在 `DownloadedComp` 下。
下载文件清理完成后,删除本次更新的临时根目录。
另见 `Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs:1304-1305`。
</issue_to_address>Original comment in English
Hey - I've found 7 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="228" />
<code_context>
+ private static string _GetContainedPath(string directory, string path)
+ {
+ path = Path.GetFullPath(path);
+ if (!path.StartsWith(directory + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ throw new ArgumentException("资源路径必须位于当前游戏目录内。", nameof(path));
+ return path;
</code_context>
<issue_to_address>
**Files escape game directory**
When a resource or recycle subdirectory is a symlink or junction pointing outside the game directory, `_GetContainedPath` checks only the normalized string prefix, so `Replace` and `Undo` follow the link and move or delete files outside the intended directory.
Resolve physical paths or reject linked path components before allowing file operations.
</issue_to_address>
### Comment 2
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="76-80" />
<code_context>
+ try
+ {
+ File.WriteAllText(pendingRecordPath, JsonSerializer.Serialize(record));
+ File.Move(originalPath, backupPath);
+ backedUp = true;
+ File.Move(downloadedPath, updatedPath);
+ installed = true;
+ File.Move(pendingRecordPath, recordPath, true);
+ }
+ catch (Exception updateError)
</code_context>
<issue_to_address>
**Interrupted updates cannot be undone**
When the launcher or machine terminates during the file moves in `Replace` or `Undo`, the exception handlers cannot roll back after process termination, and startup does not recover incomplete moves. The original can be absent or the updated file can remain under a temporary name without a usable record, leaving the resource missing or unavailable to Undo.
Persist a recoverable transaction record and recover incomplete Replace and Undo operations at startup.
Also at `PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs:166-170`.
</issue_to_address>
### Comment 3
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="242-246" />
<code_context>
+
+ private static string _NormalizeResourcePath(string path)
+ {
+ while (path.EndsWith(".disabled", StringComparison.OrdinalIgnoreCase) ||
+ path.EndsWith(".old", StringComparison.OrdinalIgnoreCase))
+ path = path[..path.LastIndexOf('.')];
+ return path;
+ }
+
+ private static bool _SamePath(string left, string right) =>
</code_context>
<issue_to_address>
**Enabled and disabled updates share records**
When enabled and disabled copies of the same resource are both present and both are updated, `_GetRecordPath` uses `_NormalizeResourcePath`, which strips `.disabled` and `.old`, so simultaneously present enabled and disabled counterparts map to the same record file. The later update overwrites the earlier record, and `_TryReadRecord` also treats the paths as equivalent; Undo can restore the sibling's backup and discard the selected file instead of restoring its own predecessor.
Key records by the exact updated path and handle filename changes across enable/disable toggles with an explicit, unambiguous record lookup.
Also at `PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs:235-237`.
</issue_to_address>
### Comment 4
<location path="PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs" line_range="228-229" />
<code_context>
+ private static string _GetContainedPath(string directory, string path)
+ {
+ path = Path.GetFullPath(path);
+ if (!path.StartsWith(directory + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
+ throw new ArgumentException("资源路径必须位于当前游戏目录内。", nameof(path));
+ return path;
+ }
</code_context>
<issue_to_address>
**Root-directory resources are rejected**
When the configured game directory is a volume or share root, `_GetContainedPath` appends a separator to the root before checking the prefix, producing a doubled separator that valid resource paths do not match. `Replace` rejects updates and `CanUndo` finds no eligible resources.
Handle filesystem roots when constructing and checking the containment prefix.
Also at `PCL.Core/Minecraft/ResourceUpdateRecycleBin.cs:23`.
</issue_to_address>
### Comment 5
<location path="Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs" line_range="2191" />
<code_context>
- {
- ModBase.Log($"[Mod] 更新后的目标文件夹已被删除:{Entry.Value}", ModBase.LogLevel.Debug);
- }
+ recycleBin.Replace(replacement.Original, replacement.Updated, replacement.Downloaded);
+ finishedFileNames.Add(ModBase.GetFileNameFromPath(replacement.Updated));
}
</code_context>
<issue_to_address>
**Failed updates leave mixed batches**
When a replacement in a multi-resource update fails, the exception from `recycleBin.Replace` stops the loop, so later resources are not installed after earlier ones have succeeded. The completion handler reports only a generic failure, leaving the user with a mixed batch and no per-resource summary.
Handle replacement failures per resource, continue processing the batch, and report which resources succeeded or failed.
Also at `Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs:1355`.
</issue_to_address>
### Comment 6
<location path="Plain Craft Launcher 2/Pages/PageInstance/ResourceUpdateUndo.cs" line_range="32-33" />
<code_context>
+
+ public static MyIconButton? CreateButton(MyLocalCompItem item, string gameDirectory, Action refresh)
+ {
+ var recycleBin = new ResourceUpdateRecycleBin(gameDirectory);
+ if (item.Entry.IsFolder || !recycleBin.CanUndo(item.Entry.path)) return null;
+
+ var button = new MyIconButton { LogoScale = 1d, SvgIcon = "lucide/rotate-ccw", Tag = item };
</code_context>
<issue_to_address>
**Large resources freeze the interface**
When an updated resource is large or stored on slow storage, `CreateButton` calls `CanUndo`, and the click handler calls `Undo`; both synchronously hash the entire updated file on the UI thread. Building or refreshing rows and clicking Undo therefore block the interface during disk I/O.
Move file hashing off the UI thread or avoid repeating synchronous full-file hashes during row creation and Undo.
Also at `Plain Craft Launcher 2/Pages/PageInstance/ResourceUpdateUndo.cs:45`, `Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs:689`, `Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs:333`.
</issue_to_address>
### Comment 7
<location path="Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs" line_range="2120" />
<code_context>
var fileCopyList = new Dictionary<string, string>();
+ var replacements = new List<(string Original, string Downloaded, string Updated)>();
+ var recycleBin = new ResourceUpdateRecycleBin(PageInstanceLeft.McInstance.PathIndie);
+ var tempRoot = Path.Combine(ModBase.pathTemp, "DownloadedComp", Guid.NewGuid().ToString("N"));
foreach (var Entry in modList)
{
</code_context>
<issue_to_address>
**Temporary directories accumulate**
When resources are updated repeatedly, each run creates a unique temp root and per-resource directories, but completion cleanup deletes only downloaded files. The empty directories accumulate under `DownloadedComp`.
Remove each update's temp root after its downloads are cleaned up.
Also at `Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs:1304-1305`.
</issue_to_address>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 091c04b424
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| var updatingPaths = loader.input.compType == CompType.DataPack | ||
| ? PageInstanceSavesDatapack.updatingVersions | ||
| : PageInstanceCompResource.updatingVersions; |
There was a problem hiding this comment.
Avoid dereferencing the absent datapack page after waiting
When a data-pack update is still running as PageInstanceSavesDatapack.UpdateResource calls ReloadDatapackFileList(true), GetRequireLoaderData supplies frm = null; routing data packs through their new updatingVersions list now makes this loader enter the wait branch, and once the update finishes it reaches the unconditional loader.input.frm.LoaderRun(...) at line 1901. That raises NullReferenceException and leaves the shared resource-list loader in the Failed state instead of showing the updated data packs, so the datapack branch needs to avoid using frm or invoke the datapack refresh path explicitly.
Useful? React with 👍 / 👎.
等待资源更新结束后,直接更新当前加载器的目录缓存,避免访问数据包页面未提供的资源页对象。
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37b558f2b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Directory.CreateDirectory(resourcepacksFolder); | ||
| ModBase.Log("[Download] 自动创建资源包文件夹:" + resourcepacksFolder); | ||
| // 回收站与实际资源目录使用相同的版本隔离路径。 | ||
| new ResourceUpdateRecycleBin(new McInstance(instanceFolder).PathIndie).InitializeFolders(); |
There was a problem hiding this comment.
Keep recycle setup from failing combined installs
When a combined McInstall uses a game or instance path containing a junction or symlink, InitializeFolders() deterministically throws because ResourceUpdateRecycleBin._GetUnlinkedPath rejects every reparse-point ancestor. Unlike the best-effort call in McInstallState, this invocation is inside the blocking InstallGame task with no catch, so the combo reaches Failed and McInstallFailedClearFolder removes the newly installed instance even though the game installation itself succeeded; recycle-bin initialization should be logged and skipped instead of failing the install.
Useful? React with 👍 / 👎.
|
|
||
| var stagedPath = Path.Combine(Path.GetDirectoryName(updatedPath)!, | ||
| ".pcl-undo-" + Guid.NewGuid().ToString("N") + ".tmp"); | ||
| record.OriginalHash = _HashFile(backupPath); |
There was a problem hiding this comment.
Verify the recorded backup hash before undoing
If a file under recycle is modified or corrupted after an update, CanUndo still reports it eligible because _TryReadRecord checks only backup existence and the current resource hash. This assignment then replaces the hash captured by Replace with the modified backup's hash, so Undo treats corrupt bytes as authoritative, deletes the valid new version, and restores them; compare the backup to the recorded OriginalHash before starting the transaction, only deriving it for genuinely legacy records.
Useful? React with 👍 / 👎.
组合安装中的回收站初始化采用与安装完成回调一致的异常处理,记录失败并继续,避免链接路径或目录创建失败触发实例清理。
撤回可用性和执行阶段校验更新时记录的旧版哈希,不再以备份当前内容覆盖校验值。仅为缺少哈希的历史记录补全恢复日志所需信息;损坏备份及无效哈希会拒绝撤回并保留新版、备份和记录。 新增 7 个回归用例:备份损坏(同名及改名更新)、缺少/空/null 旧版哈希兼容、无效及不匹配哈希。 验证:Linux .NET 10 临时 MSTest 项目直接编译仓库源码与现有测试文件,55 项可移植测试通过,包含新增 7 项;旧实现对照运行新增用例为 4 项失败、3 项通过。另对实际安装初始化代码片段执行 4 项独立检查通过。未运行 Windows 文件锁、junction、完整 WPF 构建或安装集成测试。
|
简体中文 · 点击展开 / 收起
资源更新会将旧文件送入系统回收站,升级后无法在资源列表中直接恢复。本 PR 将因更新而替换的旧文件保存到实际游戏目录的
recycle,提供行内及多选“撤回”;普通删除仍使用系统回收站。行为
验证
PCL.Core.Test中 62 项回收站回归用例通过,包括独立副本、旧记录兼容、各移动阶段中断恢复、恢复冲突、目录联接、外部正常下载缓存及批量失败后继续。审查状态
本轮逐项处理 7 条审查意见,并拆分为 GitHub 已验证签名的提交。PR 保持打开且可审查;维护者此前的
CHANGES_REQUESTED不代表已撤销。本地验证结果与 GitHub CI 状态分别记录,未将等待批准的 CI 视为通过。实现分支:HadesScience/PCL-CE:codex/resource-update-recycle-v3。
English · Click to expand / collapse
Resource updates send the previous file to the system Recycle Bin, leaving no direct way to restore it from the resource list. This PR keeps files replaced by updates in
recycleunder the active game directory and provides row and multi-selection Undo. Regular Delete continues to use the system Recycle Bin.Behavior
Validation
PCL.Core.Test, including independent copies, legacy records, interrupted move stages, recovery conflicts, junctions, ordinary external download caches and continued batch processing after failure.Review status
This round addresses the 7 review comments in separate GitHub-verified commits. The PR remains open and ready for review; the existing maintainer
CHANGES_REQUESTEDreview has not been dismissed. Local validation and GitHub CI are tracked separately; CI awaiting approval is not counted as passing.Implementation branch: HadesScience/PCL-CE:codex/resource-update-recycle-v3.
Sourcery 总结
实现可恢复的资源更新功能,加入游戏内回收站,并提供可靠的单项和多项撤销支持。
新功能:
错误修复:
改进:
测试:
Original summary in English
Sourcery 摘要
实现可恢复的资源更新功能,包括游戏内回收站,以及可靠的单项和批量撤销支持。
新功能:
错误修复:
改进:
测试:
Original summary in English
Summary by Sourcery
Implement recoverable resource updates with an in-game recycle bin and reliable single-item and bulk undo support.
New Features:
Bug Fixes:
Enhancements:
Tests: