Skip to content

feat(resource): 支持从其他实例导入资源包与光影包 [GPT-5.6] - #3536

Open
nya-a-cat wants to merge 4 commits into
PCL-Community:devfrom
nya-a-cat:feat/import-from-other-instance
Open

feat(resource): 支持从其他实例导入资源包与光影包 [GPT-5.6]#3536
nya-a-cat wants to merge 4 commits into
PCL-Community:devfrom
nya-a-cat:feat/import-from-other-instance

Conversation

@nya-a-cat

@nya-a-cat nya-a-cat commented Aug 14, 2026

Copy link
Copy Markdown

修改内容

  • 在资源包与光影包管理页增加“从其他实例导入”入口,并覆盖有内容与空列表两种页面状态
  • 列出资源目录中存在文件或文件夹的其他实例,排除当前实例与共用同一目标目录的实例
  • 将来源目录中的顶层文件和文件夹直接复制到目标实例;ZIP 作为普通文件原样复制,文件夹资源递归复制
  • 同名文件或文件夹逐项确认覆盖,完成后刷新资源列表;复制时跳过重解析点

验证情况

  • dotnet build "Plain Craft Launcher 2/Plain Craft Launcher 2.csproj" -c Debug -p:Platform=x64 --no-restore:通过,0 个错误
  • 仓库外临时验证程序:ZIP、普通文件和文件夹枚举,文件夹递归复制、覆盖目标清理与缺失来源目录均通过
  • git diff --check dev...feat/import-from-other-instance:通过

AI 使用

  • GPT-5.6:辅助实现、代码审查与本地验证
  • 仓库内未新增文档或测试文件

Summary by Sourcery

为资源包和光影包管理增加跨实例导入能力。

New Features:

  • 为资源包和光影包管理页增加从其他实例导入资源的入口。

Enhancements:

  • 支持选择可用的其他实例,并将其顶层资源文件或文件夹导入当前实例。
  • 支持导入过程中的同名资源覆盖确认、递归复制及完成后的列表刷新。
Original summary in English

Summary by Sourcery

为资源包和光影包管理增加跨实例导入能力。

New Features:

  • 为资源包和光影包管理页增加从其他实例导入资源的入口。

Enhancements:

  • 支持选择可用的其他实例,并将其顶层资源文件或文件夹导入当前实例。
  • 支持导入过程中的同名资源覆盖确认、递归复制及完成后的列表刷新。

@pcl-ce-automation pcl-ce-automation Bot added 🚧 正在处理 开发人员正在对该内容进行开发、测试或修复,进展中 size: M PR 大小评估:中型 labels Aug 14, 2026
@sourcery-ai

sourcery-ai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

审阅者指南

为从其他实例导入资源包和光影包的功能添加了 UI 和逻辑,包括实例选择、安全的文件枚举/复制(带覆盖确认提示),以及新的导入流程所需的本地化文案。

从其他实例导入资源/光影包的时序图

sequenceDiagram
    actor User
    participant PageInstanceCompResource
    participant ModInstanceList
    participant Directory
    participant ModMain
    participant ModBase
    participant HintService

    User->>PageInstanceCompResource: BtnManageImport_Click
    PageInstanceCompResource->>PageInstanceCompResource: resolve folderName (resourcepacks/shaderpacks)
    PageInstanceCompResource->>ModInstanceList: mcInstanceList
    ModInstanceList-->>PageInstanceCompResource: candidate instances
    loop each instance
        PageInstanceCompResource->>Directory: _GetImportEntries(instance, sourceFolder)
        Directory-->>PageInstanceCompResource: entries[]
    end
    PageInstanceCompResource->>PageInstanceCompResource: filter empty / same target
    alt no available source
        PageInstanceCompResource->>HintService: Hint(Instance.Resource.Import.NoAvailableInstance)
        PageInstanceCompResource-->>User: return
    else sources available
        PageInstanceCompResource->>ModMain: MyMsgBoxSelect(selection)
        ModMain-->>PageInstanceCompResource: selectedIndex
        alt user cancelled
            PageInstanceCompResource-->>User: return
        else instance selected
            PageInstanceCompResource->>PageInstanceCompResource: _ImportEntries(entries, targetFolder)
            loop each sourceEntry
                PageInstanceCompResource->>Directory: File/Directory.Exists(targetEntry)
                Directory-->>PageInstanceCompResource: exists?
                alt target exists
                    PageInstanceCompResource->>ModMain: MyMsgBox(OverwriteConfirm)
                    ModMain-->>PageInstanceCompResource: result
                    alt user confirms overwrite
                        PageInstanceCompResource->>PageInstanceCompResource: _DeleteImportTarget(targetEntry)
                    else cancel this entry
                        PageInstanceCompResource-->>PageInstanceCompResource: continue
                    end
                end
                alt source is file
                    PageInstanceCompResource->>ModBase: CopyFile(sourceEntry, targetEntry)
                else source is directory
                    PageInstanceCompResource->>PageInstanceCompResource: _CopyImportDirectory(sourceEntry, targetEntry)
                end
            end
            alt importedCount > 0
                PageInstanceCompResource->>HintService: Hint(Import.Success, HintType.Success)
                PageInstanceCompResource->>PageInstanceCompResource: ReloadCompFileList(true)
            end
        end
    end
    Note over PageInstanceCompResource,ModBase: Exceptions are logged via ModBase.Log in _GetImportEntries/_ImportEntries
Loading

文件级更改

变更 详情 文件
在资源/光影管理 UI 中接入新的导入操作,并只在支持的组件类型上显示。
  • 将 BtnManageImport 和 BtnHintImport 的点击事件处理程序绑定到新的 BtnManageImport_Click 方法,并与现有的管理/提示按钮并列。
  • 仅当 currentCompType 为 ResourcePack 或 Shader 时有条件地设置导入按钮的可见性,保持其他组件类型不变。
  • 更新 XAML 布局,在资源管理页面的「正常列表」和「空列表」两种状态下都定义新的导入按钮。
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml
为资源/光影包实现从其他实例导入的工作流,并安全地枚举与复制文件/文件夹。
  • 在 BtnManageImport_Click 中推导资源文件夹名称(resourcepacks/shaderpacks),计算当前实例下的目标文件夹,并从 ModInstanceList 中收集候选源实例,排除当前实例以及出错的实例。
  • 对每个候选实例解析其资源文件夹路径,通过 _GetImportEntries 列出顶层条目,并过滤掉没有条目的实例或其文件夹路径与目标文件夹相同的实例。
  • 向用户展示一个实例单选对话框(带条目数量),在用户确认后,将所选实例的条目和目标文件夹传入 _ImportEntries。
  • 在 _ImportEntries 中确保目标目录存在,遍历条目,在出现同名冲突时先提示用户是否覆盖,通过 _DeleteImportTarget 删除现有目标;对文件直接复制,对目录递归复制;成功后显示成功提示并刷新资源列表。
  • 在导入过程中,通过 ModBase.Log 记录并暴露错误,并以用户可见的「操作失败」提示进行反馈,避免导致 UI 崩溃。
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs
提供辅助方法,用于枚举可导入的条目、安全删除现有目标,以及在跳过重解析点的前提下递归复制目录。
  • _GetImportEntries 在源文件夹存在时,枚举其下非递归的文件系统条目,跳过重解析点,并按实例记录失败日志。
  • _DeleteImportTarget 对已有文件直接删除;对已有目录,如果是重解析点则使用简单的 Directory.Delete,否则使用 ModBase.DeleteDirectory。
  • _CopyImportDirectory 创建目标目录,并递归地将源目录中的所有文件复制到目标目录,复制文件使用 ModBase.CopyFile,枚举时启用递归子目录并跳过重解析点的选项。
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs
为「从其他实例导入」流程在英文和简体中文中添加本地化字符串。
  • 在 en-US.xaml 中定义「无可用实例」提示、实例选择对话框标题、条目数量格式化、覆盖确认对话框标题/消息、通用「操作失败」消息以及「导入成功」消息等文案。
  • 在 zh-CN.xaml 中为相同的键添加对应的中文翻译和格式化占位符。
PCL.Core/App/Localization/Languages/en-US.xaml
PCL.Core/App/Localization/Languages/zh-CN.xaml

提示与命令

与 Sourcery 交互

  • 触发新的审查: 在 Pull Request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub Issue: 在回复某条审查评论时,要求 Sourcery 从该评论创建一个 issue。你也可以直接回复该审查评论 @sourcery-ai issue,由此创建 issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题的任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 Pull Request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 Pull Request 摘要: 在 Pull Request 正文任意位置写上 @sourcery-ai summary,即可在对应位置生成 PR 摘要。你也可以在 Pull Request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在 Pull Request 中评论 @sourcery-ai guide,即可(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,即可批量标记所有 Sourcery 评论为已解决。如果你已经处理完所有评论且不想再看到它们,这会非常有用。
  • 撤销所有 Sourcery 审查: 在 Pull Request 中评论 @sourcery-ai dismiss,即可撤销所有现有的 Sourcery 审查。特别适合在你希望以一次全新的审查开始时使用——别忘了随后评论 @sourcery-ai review 来触发新的审查!

自定义你的体验

打开你的 控制面板 可以:

  • 启用或禁用各类审查功能,例如 Sourcery 自动生成的 Pull Request 摘要、审阅者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查指引。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

Adds UI and logic to import resource packs and shader packs from other instances, including instance selection, safe file enumeration/copying with overwrite prompts, and localization strings for the new import flow.

Sequence diagram for importing resource/shader packs from another instance

sequenceDiagram
    actor User
    participant PageInstanceCompResource
    participant ModInstanceList
    participant Directory
    participant ModMain
    participant ModBase
    participant HintService

    User->>PageInstanceCompResource: BtnManageImport_Click
    PageInstanceCompResource->>PageInstanceCompResource: resolve folderName (resourcepacks/shaderpacks)
    PageInstanceCompResource->>ModInstanceList: mcInstanceList
    ModInstanceList-->>PageInstanceCompResource: candidate instances
    loop each instance
        PageInstanceCompResource->>Directory: _GetImportEntries(instance, sourceFolder)
        Directory-->>PageInstanceCompResource: entries[]
    end
    PageInstanceCompResource->>PageInstanceCompResource: filter empty / same target
    alt no available source
        PageInstanceCompResource->>HintService: Hint(Instance.Resource.Import.NoAvailableInstance)
        PageInstanceCompResource-->>User: return
    else sources available
        PageInstanceCompResource->>ModMain: MyMsgBoxSelect(selection)
        ModMain-->>PageInstanceCompResource: selectedIndex
        alt user cancelled
            PageInstanceCompResource-->>User: return
        else instance selected
            PageInstanceCompResource->>PageInstanceCompResource: _ImportEntries(entries, targetFolder)
            loop each sourceEntry
                PageInstanceCompResource->>Directory: File/Directory.Exists(targetEntry)
                Directory-->>PageInstanceCompResource: exists?
                alt target exists
                    PageInstanceCompResource->>ModMain: MyMsgBox(OverwriteConfirm)
                    ModMain-->>PageInstanceCompResource: result
                    alt user confirms overwrite
                        PageInstanceCompResource->>PageInstanceCompResource: _DeleteImportTarget(targetEntry)
                    else cancel this entry
                        PageInstanceCompResource-->>PageInstanceCompResource: continue
                    end
                end
                alt source is file
                    PageInstanceCompResource->>ModBase: CopyFile(sourceEntry, targetEntry)
                else source is directory
                    PageInstanceCompResource->>PageInstanceCompResource: _CopyImportDirectory(sourceEntry, targetEntry)
                end
            end
            alt importedCount > 0
                PageInstanceCompResource->>HintService: Hint(Import.Success, HintType.Success)
                PageInstanceCompResource->>PageInstanceCompResource: ReloadCompFileList(true)
            end
        end
    end
    Note over PageInstanceCompResource,ModBase: Exceptions are logged via ModBase.Log in _GetImportEntries/_ImportEntries
Loading

File-Level Changes

Change Details Files
Wire up new import actions in the resource/shader management UI and show them only for supported component types.
  • Attach BtnManageImport and BtnHintImport click handlers to a new BtnManageImport_Click method alongside existing manage/hint buttons.
  • Conditionally set visibility of import buttons only when currentCompType is ResourcePack or Shader, keeping other component types unchanged.
  • Update the XAML layout to define the new import buttons in both the normal and empty-list states of the resource management page.
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml
Implement import-from-other-instance workflow for resource/shader packs with safe enumeration and copying of files/folders.
  • In BtnManageImport_Click, derive the resource folder name (resourcepacks/shaderpacks), compute the target folder under the current instance, and gather candidate source instances from ModInstanceList excluding the current instance and error instances.
  • For each candidate instance, resolve its resource folder path, list top-level entries via _GetImportEntries, and filter out instances with no entries or whose folder path matches the target folder.
  • Present the user with a radio-selection dialog of instances (with item counts); on confirmation, pass the chosen instance’s entries and the target folder to _ImportEntries.
  • In _ImportEntries, ensure the target directory exists, iterate entries, handle name collisions by prompting the user before overwriting, delete existing targets via _DeleteImportTarget, copy files directly and directories recursively, and on success show a success hint and refresh the resource list.
  • Log and surface errors during import with ModBase.Log and a user-facing operation-failed hint without crashing the UI.
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs
Provide helper methods to enumerate importable entries, safely delete existing targets, and recursively copy directories while skipping reparse points.
  • _GetImportEntries enumerates non-recursive filesystem entries under a source folder when it exists, skipping reparse points and logging failures per instance.
  • _DeleteImportTarget deletes an existing file directly, or deletes an existing directory, using simple Directory.Delete for reparse points and ModBase.DeleteDirectory for normal directories.
  • _CopyImportDirectory creates the target directory and recursively copies all files from the source directory to the target using ModBase.CopyFile, enumerating with options that recurse subdirectories and skip reparse points.
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs
Add localization strings for the import-from-other-instance flow in both English and Simplified Chinese.
  • Define texts for no-available-instance hint, instance selection dialog title, item count formatting, overwrite confirmation dialog title/message, generic operation-failed message, and import-success message in en-US.xaml.
  • Add the corresponding Chinese translations and formatting placeholders for the same keys in zh-CN.xaml.
PCL.Core/App/Localization/Languages/en-US.xaml
PCL.Core/App/Localization/Languages/zh-CN.xaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@pcl-ce-automation pcl-ce-automation Bot added size: L PR 大小评估:大型 and removed size: M PR 大小评估:中型 labels Aug 14, 2026
@nya-a-cat
nya-a-cat marked this pull request as ready for review August 17, 2026 18:48
@pcl-ce-automation pcl-ce-automation Bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 and removed 🚧 正在处理 开发人员正在对该内容进行开发、测试或修复,进展中 labels Aug 17, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - 我在这里给出了一些整体层面的反馈:

  • 导入操作(扫描实例并复制可能很大的资源/着色器目录)目前在 UI 线程上同步执行;建议把耗时较长的工作移动到后台任务中(例如使用 Task.Run,通过 dispatcher 更新 UI),以避免在执行大型导入时界面卡死。
  • _ImportEntries 中,只要一次文件/文件夹复制抛出异常,就会中止整个导入循环;如果合适,建议在循环内部按条目处理失败情况(记录日志并继续),这样单个有问题的条目就不会阻止其他资源被导入。
给 AI Agent 的提示
请根据这次代码评审中的评论进行修改:

## 总体评论
- 导入操作(扫描实例并复制可能很大的资源/着色器目录)目前在 UI 线程上同步执行;建议把耗时较长的工作移动到后台任务中(例如使用 Task.Run,通过 dispatcher 更新 UI),以避免在执行大型导入时界面卡死。
-`_ImportEntries` 中,只要一次文件/文件夹复制抛出异常,就会中止整个导入循环;如果合适,建议在循环内部按条目处理失败情况(记录日志并继续),这样单个有问题的条目就不会阻止其他资源被导入。

Sourcery 对开源项目是免费的——如果你喜欢我们的评审,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据反馈改进后续的评审。
Original comment in English

Hey - I've left some high level feedback:

  • The import operation (scanning instances and copying potentially large resource/shader directories) runs synchronously on the UI thread; consider moving the heavy work into a background task (e.g., Task.Run with UI updates via dispatcher) to avoid freezing the interface during large imports.
  • In _ImportEntries, a single exception during one file/folder copy aborts the entire import loop; if appropriate, consider handling per-entry failures inside the loop (logging and continuing) so that one problematic item does not prevent other resources from being imported.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The import operation (scanning instances and copying potentially large resource/shader directories) runs synchronously on the UI thread; consider moving the heavy work into a background task (e.g., Task.Run with UI updates via dispatcher) to avoid freezing the interface during large imports.
- In `_ImportEntries`, a single exception during one file/folder copy aborts the entire import loop; if appropriate, consider handling per-entry failures inside the loop (logging and continuing) so that one problematic item does not prevent other resources from being imported.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0db2ec4028

ℹ️ 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".

};
if (folderName is null) return;

var targetFolder = Path.GetFullPath(Path.Combine(PageInstanceLeft.McInstance.PathIndie, folderName));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use the LabyMod-aware component directory for imports

When either the current or source instance is a LabyMod instance, LoaderRun manages resources under the instance's LabyMod-specific labymod-neo/fabric/<VanillaName> prefix, while this code always targets PathIndie/<folderName> and line 1053 searches sources there as well. As a result, a target import can report success but remain absent after the refresh, and LabyMod sources containing resources in the managed directory are not offered; derive both paths using the same LabyMod-aware component-path logic as the page loader.

Useful? React with 👍 / 👎.

This comment was marked as spam.

@MoYuan-CN
MoYuan-CN requested a review from a team August 23, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L PR 大小评估:大型 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant