Skip to content

feat(tools): 成就图片生成器改为本地渲染并支持任意语言 [Deepseek-V4.1-Flash] - #3655

Open
meixuan1234 wants to merge 6 commits into
PCL-Community:devfrom
meixuan1234:feat/achievement-render
Open

meixuan1234 wants to merge 6 commits into
PCL-Community:devfrom
meixuan1234:feat/achievement-render

Conversation

@meixuan1234

@meixuan1234 meixuan1234 commented Oct 5, 2026 •

Copy link
Copy Markdown

背景

成就图片生成器原先调用 minecraft-api.com,该接口不支持非 ASCII 字符,输入中文返回 404,界面因此只能标注「仅支持英文」。改为 WPF 本地渲染后不再依赖第三方接口。

改动

  • 本地绘制成就卡片,支持任意语言
  • 文字按像素宽度自动换行,卡片高度随内容自适应
  • 单行超过 67 字符时截取并追加 ...
  • 物品图标依次回退:实例资源 → 在线接口 → 屏障占位
  • 字体可切换为本机已安装的字体
  • 顺带修复两处既有缺陷:
    • RubbishClear:dirInfo2.Name == dirInfo2.Name + "-natives" 恒为 false,该清理分支从未生效
    • CmbHeadSize_SelectionChanged:skinPath is not null 无效(其初始值为空字符串)

AI 使用与状态

使用 Deepseek-V4.1-Flash 辅助实现、整理和验证。已使用 GitHub 签名。人工已核查每行代码并测试功能。

Fixes #1566

Sourcery 摘要

将成就图片生成迁移至本地渲染,提升多语言支持并修复相关工具缺陷。

新功能:

  • 将成就图片生成改为本地渲染,支持任意语言、按像素宽度换行、内容自适应高度和可选系统字体。
  • 为成就图标增加多级回退机制,依次使用本地实例资源、在线资源和屏障占位图标,并缓存在线图标。

错误修复:

  • 修复原生目录清理条件导致清理分支始终无法生效的问题。
  • 修复切换头像尺寸时无法正确判断空字符串路径的问题。
Original summary in English

Sourcery 摘要

将成就图片生成改为支持多语言的本地渲染,并修复工具清理和头像处理缺陷。

新功能:

  • 将成就图片生成迁移为本地渲染,支持任意语言、按像素宽度换行及内容自适应高度。
  • 支持选择系统字体,并为成就物品图标提供本地资源、在线资源和占位图标的多级回退。

问题修复:

  • 修复原生目录清理条件错误导致相关目录无法清理的问题。
  • 修复头像尺寸切换时对空路径判断失效的问题。

改进:

  • 改进成就图片预览与保存流程,增加渲染期间的状态管理和图标缓存。
Original summary in English

Sourcery 摘要

将成就图片生成迁移至本地渲染,以支持多语言内容,并修复工具清理和头像处理方面的问题。

新功能:

  • 将成就图片生成改为本地渲染,支持任意语言、按像素宽度换行,以及根据内容自适应高度。
  • 支持选择系统字体,并为成就图标提供多级回退方案:本地资源、在线资源和占位图标。

错误修复:

  • 修复原生目录清理条件错误,导致相关目录无法清理的问题。
  • 修复切换头像尺寸时空路径判断失效的问题。

改进:

  • 优化成就图片的预览与保存流程,并在渲染期间管理操作状态和缓存图标。
Original summary in English

Summary by Sourcery

将成就图片生成功能改为在本地渲染,以支持多种语言,并修复工具清理和头像处理方面的问题。

New Features:

  • 将成就图片生成迁移至本地渲染,支持任意语言、按像素宽度换行,以及根据内容自动调整高度。
  • 支持选择系统字体,并为成就图标提供多级回退方案:本地资源、在线资源和占位图标。

Bug Fixes:

  • 修复因原生目录清理条件错误导致相关目录无法清理的问题。
  • 修复切换头像尺寸时空路径判断失效的问题。

Enhancements:

  • 改进成就图片的预览和保存流程,并增加渲染状态管理、文本处理和图标缓存。
Original summary in English

Summary by Sourcery

将成就图片生成改为支持多语言的本地渲染,并修复工具清理和头像处理缺陷。

New Features:

  • 将成就图片生成迁移为本地渲染,支持任意语言、按像素宽度换行和内容自适应高度。
  • 支持选择系统字体,并为成就图标提供本地资源、在线资源和占位图标的多级回退。

Bug Fixes:

  • 修复原生目录清理条件错误导致相关目录无法清理的问题。
  • 修复头像尺寸切换时对空路径判断失效的问题。

Enhancements:

  • 改进成就图片的预览与保存流程,增加渲染状态管理、文本处理和图标缓存。
Original summary in English
Original summary in English

@pcl-ce-automation pcl-ce-automation Bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: XL PR 大小评估:超大型 labels Oct 5, 2026
@sourcery-ai

sourcery-ai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

审查者指南

该 PR 移除成就图片生成对 minecraft-api.com 的依赖,改用 WPF 本地渲染实现任意语言、自适应排版和可选字体,并通过本地资源、在线服务与占位图标提供多级图标回退;同时修复原生目录清理及头像尺寸切换问题。

本地成就图片渲染时序图

sequenceDiagram
    participant User
    participant PageToolsTest
    participant IconLoader
    participant Renderer
    participant AchievementImage

    User->>PageToolsTest: BtnAchievementPreview_Click
    PageToolsTest->>IconLoader: _LoadAchievementIconAsync(itemId)
    IconLoader->>IconLoader: _TryLoadVanillaIcon(itemId)
    alt local icon unavailable
        IconLoader->>IconLoader: _TryLoadOnlineIcon(itemId)
        alt online icon unavailable
            IconLoader->>IconLoader: _TryLoadBuiltInBarrier()
            alt built-in barrier unavailable
                IconLoader->>IconLoader: _LoadOnlineBarrier()
            end
        end
    end
    PageToolsTest->>Renderer: _RenderAchievementImage(icon)
    Renderer->>Renderer: _WrapTextByWidth(text, typeface, fontSize, maxWidth, pixelsPerDip)
    Renderer->>AchievementImage: set Source
Loading

成就图标回退流程图

flowchart TD
    A[Item ID] --> B[_TryLoadVanillaIcon]
    B -->|found| E[Render achievement image]
    B -->|not found| C[_TryLoadOnlineIcon]
    C -->|found| E
    C -->|not found| D[_TryLoadBuiltInBarrier]
    D -->|found| E
    D -->|not found| F[_LoadOnlineBarrier]
    F -->|found| E
    F -->|not found| G[Draw fallback cube]
    G --> E
Loading

文件级变更

变更 详情 文件
将成就图片生成从第三方接口改为 WPF 本地绘制,并增加多语言文本排版与字体选择。
  • 使用 DrawingVisual 和 RenderTargetBitmap 绘制带边框、阴影、图标及自适应高度的成就卡片。
  • 按字体实际像素宽度逐字符换行,并对各文本字段执行 67 字符截断和省略。
  • 枚举本机字体并支持在成就卡片中使用所选字体。
  • 更新成就输入校验、预览/保存流程及渲染期间的按钮和加载状态。
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs
PCL.Core/App/Localization/Languages/en-US.xaml
PCL.Core/App/Localization/Languages/zh-CN.xaml
实现物品图标的本地资源、在线服务和占位图标多级回退机制。
  • 根据 Minecraft 资源索引从当前实例加载物品或方块贴图。
  • 本地缺失时依次请求两个在线图标源,并缓存成功结果。
  • 增加内置屏障图标、在线屏障图标及程序绘制立方体作为最终兜底。
  • 为网络图标请求增加超时、异常处理和未找到提示。
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs
修复清理原生目录和头像尺寸切换的既有逻辑缺陷。
  • 将原生目录判断改为不区分大小写的 -natives 后缀匹配。
  • 将头像尺寸切换的皮肤路径判断改为空字符串检查。
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs

对照关联 issue 的评估

Issue 目标 已解决 说明
#1566 让百宝箱中的自定义成就图片生成器支持输入和生成中文等非 ASCII 语言文字。 ✅
#1566 移除对不支持非 ASCII 字符的第三方成就图片接口的依赖,并改为本地生成成就图片。 ✅
#1566 确保生成器的中文文本能够正确排版并可预览、保存为图片。 ✅

可能关联的 issue


提示与命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review。
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以回复 @sourcery-ai issue,从该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文的任意位置写入 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时生成或重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,以解决所有 Sourcery 评论。如果你已经处理完所有评论并且不想再看到它们,这一功能会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,以忽略所有现有的 Sourcery 审查。如果你想重新开始一次新的审查,这一功能尤其有用——别忘了评论 @sourcery-ai review 来触发新的审查!

自定义使用体验

访问你的控制面板以:

  • 启用或禁用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南等。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

该 PR 移除成就图片生成对 minecraft-api.com 的依赖,改用 WPF 本地渲染实现任意语言、自适应排版和可选字体,并通过本地资源、在线服务与占位图标提供多级图标回退;同时修复原生目录清理及头像尺寸切换问题。

Sequence diagram for local achievement image rendering

sequenceDiagram
    participant User
    participant PageToolsTest
    participant IconLoader
    participant Renderer
    participant AchievementImage

    User->>PageToolsTest: BtnAchievementPreview_Click
    PageToolsTest->>IconLoader: _LoadAchievementIconAsync(itemId)
    IconLoader->>IconLoader: _TryLoadVanillaIcon(itemId)
    alt local icon unavailable
        IconLoader->>IconLoader: _TryLoadOnlineIcon(itemId)
        alt online icon unavailable
            IconLoader->>IconLoader: _TryLoadBuiltInBarrier()
            alt built-in barrier unavailable
                IconLoader->>IconLoader: _LoadOnlineBarrier()
            end
        end
    end
    PageToolsTest->>Renderer: _RenderAchievementImage(icon)
    Renderer->>Renderer: _WrapTextByWidth(text, typeface, fontSize, maxWidth, pixelsPerDip)
    Renderer->>AchievementImage: set Source
Loading

Flow diagram for achievement icon fallback

flowchart TD
    A[Item ID] --> B[_TryLoadVanillaIcon]
    B -->|found| E[Render achievement image]
    B -->|not found| C[_TryLoadOnlineIcon]
    C -->|found| E
    C -->|not found| D[_TryLoadBuiltInBarrier]
    D -->|found| E
    D -->|not found| F[_LoadOnlineBarrier]
    F -->|found| E
    F -->|not found| G[Draw fallback cube]
    G --> E
Loading

File-Level Changes

Change Details Files
将成就图片生成从第三方接口改为 WPF 本地绘制,并增加多语言文本排版与字体选择。
  • 使用 DrawingVisual 和 RenderTargetBitmap 绘制带边框、阴影、图标及自适应高度的成就卡片。
  • 按字体实际像素宽度逐字符换行,并对各文本字段执行 67 字符截断和省略。
  • 枚举本机字体并支持在成就卡片中使用所选字体。
  • 更新成就输入校验、预览/保存流程及渲染期间的按钮和加载状态。
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs
PCL.Core/App/Localization/Languages/en-US.xaml
PCL.Core/App/Localization/Languages/zh-CN.xaml
实现物品图标的本地资源、在线服务和占位图标多级回退机制。
  • 根据 Minecraft 资源索引从当前实例加载物品或方块贴图。
  • 本地缺失时依次请求两个在线图标源,并缓存成功结果。
  • 增加内置屏障图标、在线屏障图标及程序绘制立方体作为最终兜底。
  • 为网络图标请求增加超时、异常处理和未找到提示。
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs
修复清理原生目录和头像尺寸切换的既有逻辑缺陷。
  • 将原生目录判断改为不区分大小写的 -natives 后缀匹配。
  • 将头像尺寸切换的皮肤路径判断改为空字符串检查。
Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#1566 让百宝箱中的自定义成就图片生成器支持输入和生成中文等非 ASCII 语言文字。 ✅
#1566 移除对不支持非 ASCII 字符的第三方成就图片接口的依赖,并改为本地生成成就图片。 ✅
#1566 确保生成器的中文文本能够正确排版并可预览、保存为图片。 ✅

Possibly linked issues


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

@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.

嘿——我发现了 3 个问题

面向 AI Agent 的提示
请处理这次代码审查中的评论:

## 单独评论

### 评论 1
<location path="Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs" line_range="741" />
<code_context>
+        Media.FormattedText MakeText(string text, Media.Color color) => new(
+            _WrapTextByWidth(text, typeface, fontSize, maxTextWidth, superSample),
+            CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, fontSize,
+            new Media.SolidColorBrush(color), superSample)
+        {
+            MaxTextWidth = maxTextWidth,
</code_context>
<issue_to_address>
**问题 (bug_risk):**RTL 成就文本始终按从左到右的方向进行格式化,因此即使该功能声称支持任意语言,阿拉伯语和希伯来语文本仍会以错误的双向文本顺序和方向显示。

**触发条件:**标题或描述包含从右到左的文本时。

**建议修复:**根据文本或输入区域性选择流方向,或者仅对 LTR 内容使用 `FlowDirection.LeftToRight`,对 RTL 内容使用 `FlowDirection.RightToLeft`。

```suggestion
            CultureInfo.CurrentUICulture, CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight, typeface, fontSize,
```
</issue_to_address>

### 评论 2
<location path="Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs" line_range="601-606" />
<code_context>
+        try
+        {
+            await Task.Yield(); // 先把加载指示绘制出来
+            var itemId = AchievementBlockTextBox.Text.Trim();
+            var (icon, notFound) = await _LoadAchievementIconAsync(itemId);
+            if (notFound && !string.IsNullOrEmpty(itemId))
+                HintService.Hint(Lang.Text("Tools.Test.Achievement.IconNotFound", itemId), HintType.Info);
+
+            AchievementImage.Source = _RenderAchievementImage(icon);
+            AchievementImage.Visibility = Visibility.Visible;
+        }
</code_context>
<issue_to_address>
**问题 (bug_risk):**项目 ID 在异步加载图标之前被捕获,但 `_RenderAchievementImage` 在等待完成后又重新读取文本框。因此,在网络请求进行期间编辑项目 ID 或成就文本,会将旧项目的图标与新文本组合在一起,从而生成内容不一致的预览或保存图片。

**触发条件:**在线图标或屏障请求进行期间,用户编辑成就字段时。

**建议修复:**在等待异步操作之前快照保存所有成就输入,并将该不可变快照传递给图标加载和渲染逻辑;或者在操作期间禁用输入控件。
</issue_to_address>

### 评论 3
<location path="Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs" line_range="826-844" />
<code_context>
-                ModBase.CopyFile(savePath, path);
-                File.Delete(savePath);
-                HintService.Hint(Lang.Text("Tools.Test.Achievement.Saved"), HintType.Success);
+        foreach (var ch in text)
+        {
+            if (ch == '\n')
+            {
+                result.Append(line).Append('\n');
+                line.Clear();
+                continue;
             }
-            // 下载成功,返回 True
-            else if (response.StatusCode == HttpStatusCode.NotFound)
</code_context>
<issue_to_address>
**问题 (bug_risk):**换行逻辑遍历的是 UTF-16 `char` 值,可能会将代理项对中的一半移动到下一行。这样生成的字符串会在代理项对之间插入换行符,导致表情符号和其他补充平面字符在换行边界处显示为损坏字符或替换字符。

**触发条件:**补充 Unicode 字符恰好位于行宽边界时。

**建议修复:**按 Unicode 标量值或字素簇进行换行,在测量和移动文本时确保每个代理项对保持完整。
</issue_to_address>

Sourcery 对开源项目免费——如果您喜欢我们的审查结果,请考虑分享它们 ✨
Original comment in English

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs" line_range="741" />
<code_context>
+        Media.FormattedText MakeText(string text, Media.Color color) => new(
+            _WrapTextByWidth(text, typeface, fontSize, maxTextWidth, superSample),
+            CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, fontSize,
+            new Media.SolidColorBrush(color), superSample)
+        {
+            MaxTextWidth = maxTextWidth,
</code_context>
<issue_to_address>
**issue (bug_risk):** RTL achievement text is always formatted as left-to-right, so Arabic and Hebrew text is displayed with incorrect bidi ordering and direction despite the feature claiming support for arbitrary languages.

**Triggers:** When the title or description contains right-to-left text.

**Suggested fix:** Choose the flow direction from the text or input culture, or use `FlowDirection.LeftToRight` only for LTR content and `FlowDirection.RightToLeft` for RTL content.

```suggestion
            CultureInfo.CurrentUICulture, CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight, typeface, fontSize,
```
</issue_to_address>

### Comment 2
<location path="Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs" line_range="601-606" />
<code_context>
+        try
+        {
+            await Task.Yield(); // 先把加载指示绘制出来
+            var itemId = AchievementBlockTextBox.Text.Trim();
+            var (icon, notFound) = await _LoadAchievementIconAsync(itemId);
+            if (notFound && !string.IsNullOrEmpty(itemId))
+                HintService.Hint(Lang.Text("Tools.Test.Achievement.IconNotFound", itemId), HintType.Info);
+
+            AchievementImage.Source = _RenderAchievementImage(icon);
+            AchievementImage.Visibility = Visibility.Visible;
+        }
</code_context>
<issue_to_address>
**issue (bug_risk):** The item ID is captured before the asynchronous icon load, but `_RenderAchievementImage` reads the text boxes again after the await. Editing the item ID or achievement text while the network request is running therefore combines the old item's icon with the new text, producing an internally inconsistent preview or saved image.

**Triggers:** When the user edits an achievement field while an online icon or barrier request is in progress.

**Suggested fix:** Snapshot all achievement inputs before awaiting and pass that immutable snapshot through icon loading and rendering, or disable the input controls for the duration of the operation.
</issue_to_address>

### Comment 3
<location path="Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs" line_range="826-844" />
<code_context>
-                ModBase.CopyFile(savePath, path);
-                File.Delete(savePath);
-                HintService.Hint(Lang.Text("Tools.Test.Achievement.Saved"), HintType.Success);
+        foreach (var ch in text)
+        {
+            if (ch == '\n')
+            {
+                result.Append(line).Append('\n');
+                line.Clear();
+                continue;
             }
-            // 下载成功,返回 True
-            else if (response.StatusCode == HttpStatusCode.NotFound)
</code_context>
<issue_to_address>
**issue (bug_risk):** Wrapping iterates UTF-16 `char` values and can move only one half of a surrogate pair to the next line. The resulting string contains a newline between the pair, so emoji and other supplementary-plane characters render as broken or replacement glyphs at a wrap boundary.

**Triggers:** When a supplementary Unicode character falls exactly at a line-width boundary.

**Suggested fix:** Wrap by Unicode scalar values or grapheme clusters, keeping each surrogate pair together while measuring and moving text.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs Outdated
Comment thread Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs Outdated
Comment thread Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs Outdated
@whitecat346

Copy link
Copy Markdown
Member

@codex

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T08:23:43.635511Z b84e6be New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 26aea5c2e4

ℹ️ 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 instance = ModInstanceList.McMcInstanceSelected;
if (instance is null) return null;

var objects = ModAssets.McAssetsGetIndex(instance)?["objects"];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Read local icons from the installed resource data

When a normal selected instance is available, ModAssets.McAssetsGetIndex returns only the instance JSON's assetIndex descriptor (Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs:20-39), whose fields are metadata such as id and url, rather than the downloaded index's objects map. This lookup is therefore null and _TryLoadVanillaIcon always falls through to the external services, so offline users get a barrier for valid installed items such as stone; read from the actual texture-bearing installed resource (for modern clients, the resolved client JAR) before taking the network fallback.

Useful? React with 👍 / 👎.

{
const int maxLength = 67;
if (string.IsNullOrEmpty(text) || text.Length <= maxLength) return text;
return text[..maxLength] + "...";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Truncate text without splitting surrogate pairs

When a title or description longer than 67 UTF-16 code units has a supplementary character at the cutoff (for example, 66 ASCII characters followed by an emoji), this slice retains only the high surrogate and FormattedText renders a replacement glyph. The wrapping path already enumerates Runes, but truncation must also stop at a Unicode scalar or grapheme boundary to preserve the advertised arbitrary-language rendering.

Useful? React with 👍 / 👎.

<Image x:Name="AchievementImage" Width="320" Height="64" Stretch="Uniform" Visibility="Collapsed" />
<local:MyLoading x:Name="LoadAchievement" Margin="0,5,0,10" HorizontalAlignment="Center"
Text="{DynamicResource Tools.Test.Achievement.Loading}"
Visibility="Collapsed" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop the collapsed loading control's animation

Whenever this page is open and no achievement render is running, Collapsed does not unload this element. MyLoading.InitState defaults its state to Run (Plain Craft Launcher 2/Controls/MyLoading.xaml.cs:188-195), and AniLoop checks only IsLoaded and recursively schedules itself (MyLoading.xaml.cs:260-295), while these handlers only change Visibility; the invisible pickaxe animation therefore consumes animation and UI-thread work for the page's lifetime. Disable AutoRun and explicitly run and stop the loading state around each operation.

Useful? React with 👍 / 👎.

@Chiloven945 Chiloven945 added the 🤖 AI 辅助 该内容已声明本次贡献使用生成式 AI,并只用于标识相应使用情况,不代表存在质量问题或违规 label Oct 24, 2026
@pcl-ce-automation pcl-ce-automation Bot removed the 🤖 AI 辅助 该内容已声明本次贡献使用生成式 AI,并只用于标识相应使用情况,不代表存在质量问题或违规 label Oct 25, 2026
@meixuan1234
meixuan1234 force-pushed the feat/achievement-render branch 2 times, most recently from bb737c6 to 26aea5c Compare October 25, 2026 07:27

@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: bb737c665f

ℹ️ 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 jar = current.PathInstance + current.Name + ".jar";
if (File.Exists(jar)) return jar;

if (string.IsNullOrEmpty(current.InheritInstanceName)) break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Honor client JAR overrides before following inheritance

For a selected profile that uses the supported version-JSON jar override, this resolver either stops when inheritsFrom is empty or follows the inherited ID, so it never opens the archive the launcher actually uses. The fresh evidence in this revision is the newly added resolver contrasted with ModLibrary.cs:159-181, where launches honor mcInstance.JsonObject["jar"]; with such a profile and no network, a locally available icon is replaced by the barrier, and with both fields it can come from the wrong version. Resolve the jar override before falling back to inheritance.

Useful? React with 👍 / 👎.

Comment on lines +886 to +888
foreach (var rune in text.EnumerateRunes())
if (rune.Value is >= 0x0590 and <= 0x08FF)
return FlowDirection.RightToLeft;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive mixed-text direction from the first strong character

When a field starts with LTR text but contains an Arabic or Hebrew run (for example, Version 2 — إصدار), returning RTL merely because any RTL rune appears gives the whole FormattedText the wrong paragraph base direction, which reorders runs and neutral punctuation; joining the two description lines also lets one RTL line force the other line's direction. Determine direction from the first strong directional character, ideally per paragraph, rather than from any matching character.

Useful? React with 👍 / 👎.

@meixuan1234
meixuan1234 force-pushed the feat/achievement-render branch from 26aea5c to 980f1c4 Compare October 25, 2026 08:09
- RubbishClear 中 natives 目录的判断条件恒为 false,该清理分支从未生效
- CmbHeadSize_SelectionChanged 中 skinPath 判空无效,其初始值是空字符串而非 null
原先调用 minecraft-api.com 生成图片,该接口不支持非 ASCII 字符,输入中文返回 404,
界面因此只能标注「仅支持英文」。改为完全本地渲染后不再依赖第三方接口。

- 用 WPF 本地绘制成就卡片,支持任意语言
- 文字按像素宽度自动换行(含连续 ASCII 串),卡片高度随内容自适应
- 单行超过 67 字符时截取并追加省略号
- 物品图标按实例资源、在线接口、屏障占位依次回退
- 字体可切换为本机已安装的字体
- 在线图标缓存使用 ConcurrentDictionary,生成期间禁用预览与保存按钮

BREAKING CHANGE: 移除对 minecraft-api.com 的依赖
- 书写方向固定为 LeftToRight,阿拉伯文、希伯来文等 RTL 文本会显示反掉;
  改为按文本内容检测(U+0590–U+08FF 区段)决定方向
- 图标异步加载完成后才读取文本框,若用户在此期间编辑,会得到
  「旧图标配新文字」的不一致结果;改为等待前快照全部输入
- 按 char 遍历换行会从中间拆开代理项对,emoji 等补充平面字符落在
  换行边界时会显示为乱码;改为按 Unicode 标量值(Rune)遍历
- 从实例客户端 JAR 读取物品贴图:assetIndex 只有元数据、objects 表不含贴图,
  原实现恒为 null 导致离线时始终回退到在线源或屏障图标;现沿继承链定位 JAR
- 文本截断改为按 Rune 遍历,避免在代理项对中间截断使 emoji 显示为替换符
- 成就加载指示关闭 AutoRun 并在预览/保存前后显式启停,避免折叠后动画持续空转
- 保存文件名改用快照标题并过滤 Windows 非法字符,标题含 : ? 等字符时不再保存失败
- 客户端 JAR 的读取与解码拆开:定位 JAR 留在 UI 线程,开包拷贝字节放到后台
- 在线请求超时改用 CancellationToken,超时后底层连接会被真正取消
- 图标缩放按原始尺寸选择插值:本地 16px 用最近邻,256px 在线渲染图用高质量
- 第一行为空时不再拼出多余空行
- 内置屏障图标加载失败后不再每次重试
- 统一在线下载与解码逻辑,去掉两处重复实现
- 实例 JSON 的 jar 字段指向其他实例时(OptiFine、LiteLoader 等),
  沿该字段定位真正被加载的 JAR,避免取到错误版本或退回屏障图标
- 书写方向改由第一个强方向字符决定,不再因文本中任意位置出现 RTL 字符
  就把整段判为 RTL,防止中性标点错位
@meixuan1234
meixuan1234 force-pushed the feat/achievement-render branch from 980f1c4 to b84e6be Compare October 25, 2026 08:16

@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: b84e6be579

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

Comment on lines +3495 to +3497
<sys:String x:Key="Tools.Test.Achievement.Title">Custom achievement image generator</sys:String>
<sys:String x:Key="Tools.Test.Achievement.Font">Font</sys:String>
<sys:String x:Key="Tools.Test.Achievement.Loading">Fetching item icon…</sys:String>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update complete locale overrides for the new achievement UI

When the UI language is en-GB or zh-TW, LocalizationService loads that locale after the zh-CN base dictionary (PCL.Core/App/Localization/LocalizationService.cs:267-277), but those two complete dictionaries were not updated: they still override the title with “English only” at en-GB.xaml:3437 / zh-TW.xaml:3437 and omit the new Font, Loading, and IconNotFound keys. Consequently these users see a contradictory title plus Simplified Chinese fallback labels/hints; add the corresponding entries to both locale dictionaries.

Useful? React with 👍 / 👎.

@lhx077 lhx077 added the 🤖 AI 辅助 该内容已声明本次贡献使用生成式 AI,并只用于标识相应使用情况,不代表存在质量问题或违规 label Oct 26, 2026
@lhx077
lhx077 requested a review from a team October 26, 2026 04:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 🤖 AI 辅助 该内容已声明本次贡献使用生成式 AI,并只用于标识相应使用情况,不代表存在质量问题或违规 size: XL PR 大小评估:超大型

Projects

None yet

Development

Successfully merging this pull request may close these issues.

在百宝箱-自定义成就图片生成器中添加中文支持

4 participants