Skip to content

fix(json): 修复有关 JSON 的一系列问题#2931

Merged
Big-Cake-jpg merged 4 commits into
devfrom
fix/json2
May 30, 2026
Merged

fix(json): 修复有关 JSON 的一系列问题#2931
Big-Cake-jpg merged 4 commits into
devfrom
fix/json2

Conversation

@Chiloven945
Copy link
Copy Markdown
Member

@Chiloven945 Chiloven945 commented May 30, 2026

GPT-5.5 Thinking 修复并校对

新增 PCL.Core/Utils/JsonCompat 作为统一的 JSON 兼容解析入口,替代原先散落在 Plain Craft Launcher 2 项目中的 JsonNodeExtensions,并全部替换调用方式。

  • JsonCompat — 集中管理 SerializerOptions / NodeOptions / DocumentOptions,内置 FlexibleDateTimeConverterFlexibleBoolConverterFlexibleStringConverter 三个宽松转换器,提供 ParseNode()ToObject<T>()(扩展方法)、FromObject<T>()Merge() 等辅助方法
  • 全局迁移 — 将整体 JsonNode.Parse()GetValue<T>()JsonSerializer.* 裸调用全部替换为 JsonCompat 的对应 API,确保所有 JSON 解析使用一致的宽松选项,消除因格式/类型不匹配导致的反序列化崩溃
  • 空引用修复 — 服务端名称获取等处加入 ?. 空条件传播
  • Forge 版本列表 — 从 FetchJson 改为 FetchString(返回内容实为 HTML)
  • ExpandoObjectConverter 优化 — 用直接值类型判断替代二次序列化
  • SignOutAsync 优化 — 204 NoContent 时提前返回,避免解析空响应
  • Yggdrasil record 修正 — property 语义从 set 改为 init

Summary by Sourcery

引入集中化的 JSON 兼容性工具,并迁移现有的 JSON 解析/序列化逻辑以使用该工具,从而在整个代码库中实现更健壮、更宽松的处理。

Bug 修复:

  • 防止由于不一致或过于严格的 JSON 处理(包括可空字段、类型不匹配以及无内容的服务器响应)导致的崩溃和解析错误。
  • 修复对实际上是 HTML 而非 JSON 的 Forge 版本列表响应的处理,避免将其误当作 JSON 解析。
  • 更正 Yggdrasil 认证模型,使其使用仅在初始化时设置的属性以及正确的默认初始化,以避免非预期的修改和空引用问题。
  • 在解析错误消息时,安全地处理返回 204 No Content 且响应体为空的登出(sign-out)响应。

增强功能:

  • 通过新的 JsonCompat 工具统一 JSON 序列化器、文档和节点选项(包括自定义转换器),以模拟类似 Newtonsoft.Json 的宽松行为。
  • 通过避免冗余序列化并添加直接的元素到 CLR 映射,优化动态类型和 ExpandoObject 的 JSON 转换。
  • 借助共享的 JSON 选项和解析器,提高各类服务(如依赖检查、Natayark、EasyTier、McPing、配置、CLI 和元数据加载)的健壮性。
  • 通过增加灵活的 DateTime 解析并容忍不同格式和时区,使版本和日期处理更加可靠。
  • 用集中化的辅助工具取代临时的 JsonNode 解析/合并及分散的辅助函数,这些新工具支持深度合并和宽容的类型转换。
Original summary in English

Summary by Sourcery

Introduce a centralized JSON compatibility utility and migrate existing JSON parsing/serialization to use it for more robust, lenient handling across the codebase.

Bug Fixes:

  • Prevent crashes and misparsing caused by inconsistent or strict JSON handling, including nullable fields, type mismatches, and server responses without content.
  • Fix handling of Forge version list responses that are actually HTML instead of JSON, avoiding invalid JSON parsing.
  • Correct Yggdrasil authentication models to use init-only properties and proper default initialization to avoid unintended mutation and null issues.
  • Handle sign-out responses with 204 No Content and empty bodies safely when parsing error messages.

Enhancements:

  • Standardize JSON serializer, document, and node options (including custom converters) via a new JsonCompat utility to emulate Newtonsoft.Json-like leniency.
  • Optimize dynamic and ExpandoObject JSON conversion by avoiding redundant serialization and adding direct element-to-CLR mapping.
  • Improve resilience of various services (e.g., dependency checks, Natayark, EasyTier, McPing, config, CLI, and metadata loading) by using shared JSON options and parsers.
  • Make version and date handling more robust by adding flexible DateTime parsing and tolerance for different formats and time zones.
  • Replace ad-hoc JsonNode parsing/merging and scattered helpers with centralized helpers that support deep merges and tolerant conversions.

…ers and null safety

- Replace GetValue<T>() with ToObject<T>() via CompatOptions to handle type mismatches
- Add FlexibleBoolConverter and FlexibleStringConverter for resilient parsing
- Add null-conditional (? / ?.) propagation to server name and JSON field access
- Centralize ParseJson() helper to ensure consistent options everywhere
- Replace raw string JSON construction with JsonObject for LabyMod libraries
…, forge list, and modpack parsing

- Add robust _GetDateTime() to handle both DateTime and string JSON values in McVersionClassifier
- Replace unsafe GetValue<T>() with TryGetValue<T>() in _GetString()
- Use FetchString instead of FetchJson for Forge HTML version list page
- Replace GetValue<T>() with ToObject<T>() for modpack file fields
…unified API

- Add JsonCompat class in PCL.Core.Utils with centralized SerializerOptions, NodeOptions, DocumentOptions, converters, and helper methods (ParseNode, ToObject, FromObject, Merge)
- Replace all JsonNodeExtensions.* references (app project) with JsonCompat.* (core library) site-wide
- Make ToObject<T>() an extension method on JsonNode for cleaner call syntax
- Optimize ExpandoObjectConverter with direct element-kind conversion instead of re-serializing
- Fix YggdrasilCredential record semantics (init-only properties, property initializers)
- Improve SignOutAsync to check NoContent status before parsing response body
- Use primary constructor syntax for JsonWebToken
@pcl-ce-automation pcl-ce-automation Bot added 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 size: XXL PR 大小评估:巨型 labels May 30, 2026
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 30, 2026

Reviewer's Guide

引入集中管理的 JsonCompat 实用工具,使用更宽松的 System.Text.Json 默认配置,并迁移代码库统一使用它。同时收紧各处 JSON 使用方式、空值处理路径以及部分协议/记录定义,以避免反序列化和运行时错误。

更新后的 YggdrasilLegacyClient.SignOutAsync 流程时序图

sequenceDiagram
    participant Client as YggdrasilLegacyClient
    participant HttpReq as HttpRequest
    participant Server as YggdrasilServer
    participant JsonC as JsonCompat

    Client->>HttpReq: CreatePost(address)
    Client->>HttpReq: WithHeaders(options.Headers)
    Client->>HttpReq: WithJsonContent(signoutData)
    Client->>HttpReq: SendAsync(options.GetClient.Invoke(), token)
    HttpReq-->>Client: HttpResponseMessage response

    alt StatusCode == HttpStatusCode.NoContent
        Client-->>Client: return (true, null)
    else StatusCode != HttpStatusCode.NoContent
        Client->>HttpReq: AsStringAsync(token)
        HttpReq-->>Client: content
        Client->>JsonC: ParseNode(content)
        JsonC-->>Client: JsonNode data
        Client-->>Client: errorMessage = data["errorMessage"]?.ToString()
        Client-->>Client: return (false, errorMessage)
    end
Loading

文件级变更

Change Details Files
引入 JsonCompat 作为集中、宽松的 System.Text.Json 配置与助手 API,并移除分散的 JsonNodeExtensions。
  • 添加 JsonCompat,提供共享的 JsonNodeOptions、JsonDocumentOptions 和 SerializerOptions,包括对 DateTime、bool、string 和 enum 的灵活转换器。
  • 暴露以下辅助方法:ParseNode、JsonNode.ToObject()、用于数组的类似 FromObject 的创建方法,以及 JsonObject/JsonArray 的 Merge 语义。
  • 将 JsonCompat.SerializerOptions/DocumentOptions/NodeOptions 接入配置、HTTP、IO、启动流程、加密、CLI 和元数据加载路径,使其共享一致行为。
  • 删除旧的 JsonNodeExtensions,并将其使用点替换为对应的 JsonCompat 实现。
PCL.Core/Utils/JsonCompat.cs
Plain Craft Launcher 2/Modules/Base/JsonNodeExtensions.cs
PCL.Core/App/Configuration/Storage/JsonFileProvider.cs
PCL.Core/App/Configuration/Storage/ConfigStorage.cs
PCL.Core/App/Configuration/Storage/EncryptedFileConfigStorage.cs
PCL.Core/App/Configuration/Storage/JsonToYamlConverter.cs
PCL.Core/App/Essentials/StartupService.cs
PCL.Core/App/Essentials/SingleInstanceService.cs
PCL.Core/App/Essentials/PromoteService.cs
PCL.Core/App/Essentials/DependencyCheckService.cs
PCL.Core/App/Basics.cs
PCL.Core/IO/Files.cs
PCL.Core/IO/Net/Http/HttpContentExtension.cs
PCL.Core/IO/Net/Http/HttpRouteResponse.cs
PCL.Core/IO/Net/Http/HttpResponseExtension.cs
PCL.Core/Link/McPing/McPingService.cs
PCL.Core/Link/EasyTier/ETInfoProvider.cs
PCL.Core/Link/Scaffolding/EasyTier/EasyTierEntity.cs
PCL.Core/Link/Scaffolding/EasyTier/CliNetTest.cs
PCL.Core/Link/Scaffolding/Client/Requests/GetPlayerProfileListRequest.cs
PCL.Core/Link/Scaffolding/Client/Requests/PlayerPingRequest.cs
PCL.Core/Link/Scaffolding/Server/Handlers/GetPlayerProfileListHandler.cs
PCL.Core/Link/Scaffolding/Server/Handlers/PlayerPingHandler.cs
PCL.Core/Link/Natayark/NatayarkProfileManager.cs
Plain Craft Launcher 2/Modules/Network/Http/Requester.cs
Plain Craft Launcher 2/Modules/Base/ModBase.cs
使用 JsonCompat 和更安全的 JsonNode 访问方式,在启动器各模块中强化 JSON 解析与类型转换。
  • 在模组下载、配置档、Java、样式和更新逻辑中,将 JsonNode.GetValue() 和直接调用 JsonSerializer 的用法替换为 JsonCompat.ToObject() 或带 SerializerOptions 的调用。
  • 在解析原始字符串(如配置档文件、资源索引、远程缓存和 Yggdrasil 响应)时,统一使用 ModBase.GetJson(现由 JsonCompat.ParseNode 支持)。
  • 调整代码以容忍缺失/无效节点,通过空传播和默认值回退处理,例如读取 serverName、公告版本、LabyMod 字段和 Minecraft 版本元数据时。
  • 更新 JSON 写入路径,复用 JsonCompat.SerializerOptions(通常克隆后设置 WriteIndented = true),以确保可往返的、一致的格式化输出。
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.cs
Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs
Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs
Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs
Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs
Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs
Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs
Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs
Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs
Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs
Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.cs
PCL.Core/App/Tools/DependencyCheckService.cs
PCL.Core/Minecraft/McVersionClassifier.cs
PCL.Core/Minecraft/Java/JavaManager.cs
PCL.Core/Test/App/CommandLineTest.cs
PCL.Core.Test/DynamicJsonTest.cs
修复认证流程、Yggdrasil 模型、JWT 处理和 HTTP 助手中的 JSON 相关 bug 和边界情况。
  • JsonWebToken 现在使用 JsonCompat.SerializerOptions 对 header 和 payload 进行序列化/反序列化,以获得宽松行为和一致的枚举/字符串处理。
  • YggdrasilLegacyClient.SignOutAsync 在收到 204 时提前返回,并仅在存在 JSON 错误响应体时使用 JsonCompat 解析;当没有响应体时,错误描述为 null。
  • YggdrasilAuthenticateResult.User 改为 init-only 属性,YggdrasilCredential 中的 Agent 也改为 init-only 并具有默认实例,以匹配记录类型的语义。
  • HttpContentExtension.WithJsonContent 与 HttpRouteResponse.Json/HttpResponseExtension.AsJsonAsync 统一默认接受/使用 JsonCompat.SerializerOptions,避免调用方和服务端之间选项不匹配。
PCL.Core/Minecraft/IdentityModel/Extensions/JsonWebToken/JsonWebToken.cs
PCL.Core/Minecraft/IdentityModel/Extensions/JsonWebToken/JsonWebKeys.cs
PCL.Core/Minecraft/IdentityModel/Yggdrasil/Client.cs
PCL.Core/Minecraft/IdentityModel/Yggdrasil/YggdrasilCredential.cs
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs
PCL.Core/IO/Net/Http/HttpContentExtension.cs
PCL.Core/IO/Net/Http/HttpRouteResponse.cs
PCL.Core/IO/Net/Http/HttpResponseExtension.cs
提升基于 JSON 的领域逻辑的鲁棒性,例如版本分类、LabyMod 合并以及动态/expando 处理。
  • McVersionClassifier.GetReleaseTime/_GetDateTime 现在能容忍多种 DateTime/字符串形式,并归一化为本地时间;_GetString 在遇到非字符串值时不再抛异常。
  • LabyMod 合并逻辑不再对插值字符串调用 JsonNode.Parse,而是通过空值检查和对尺寸字段的 DeepClone 构建 JsonObject 树,以避免在属性缺失时生成非法 JSON。
  • ExpandoObjectConverter.Read 通过递归将 JsonElement 映射为 ExpandoObject/List/基础类型来避免二次序列化,并通过使用 JsonCompat.SerializerOptions 的测试进行验证。
  • Forge 版本列表现在使用 FetchString 而不是 FetchJson,因为上游端点返回的是 HTML,从而避免解析失败。
PCL.Core/Minecraft/McVersionClassifier.cs
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs
Plain Craft Launcher 2/Modules/Minecraft/ModDownloadLib.cs
PCL.Core/Utils/ExpandoObjectConverter.cs
PCL.Core.Test/DynamicJsonTest.cs
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs

Tips and commands

Interacting with 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 触发新评审!

Customizing Your Experience

访问你的 dashboard 以:

  • 启用或禁用评审功能,例如 Sourcery 生成的 Pull Request 总结、评审者指南等。
  • 修改评审语言。
  • 添加、删除或编辑自定义评审指令。
  • 调整其他评审设置。

Getting Help

Original review guide in English

Reviewer's Guide

Introduce a centralized JsonCompat utility with relaxed System.Text.Json defaults and migrate the codebase to use it, while tightening up various JSON usages, null-handling paths, and a few protocol/record definitions to avoid deserialization and runtime errors.

Sequence diagram for updated YggdrasilLegacyClient.SignOutAsync flow

sequenceDiagram
    participant Client as YggdrasilLegacyClient
    participant HttpReq as HttpRequest
    participant Server as YggdrasilServer
    participant JsonC as JsonCompat

    Client->>HttpReq: CreatePost(address)
    Client->>HttpReq: WithHeaders(options.Headers)
    Client->>HttpReq: WithJsonContent(signoutData)
    Client->>HttpReq: SendAsync(options.GetClient.Invoke(), token)
    HttpReq-->>Client: HttpResponseMessage response

    alt StatusCode == HttpStatusCode.NoContent
        Client-->>Client: return (true, null)
    else StatusCode != HttpStatusCode.NoContent
        Client->>HttpReq: AsStringAsync(token)
        HttpReq-->>Client: content
        Client->>JsonC: ParseNode(content)
        JsonC-->>Client: JsonNode data
        Client-->>Client: errorMessage = data["errorMessage"]?.ToString()
        Client-->>Client: return (false, errorMessage)
    end
Loading

File-Level Changes

Change Details Files
Introduce JsonCompat as a centralized, lenient System.Text.Json configuration and helper API, and remove scattered JsonNodeExtensions.
  • Add JsonCompat with shared JsonNodeOptions, JsonDocumentOptions, and SerializerOptions including flexible converters for DateTime, bool, string and enums.
  • Expose helpers: ParseNode, JsonNode.ToObject(), FromObject-like creation for arrays, and Merge semantics for JsonObject/JsonArray.
  • Wire JsonCompat.SerializerOptions/DocumentOptions/NodeOptions into configuration, HTTP, IO, startup, encryption, CLI, and metadata loading paths so they all share the same behavior.
  • Delete legacy JsonNodeExtensions and replace its usages with JsonCompat equivalents.
PCL.Core/Utils/JsonCompat.cs
Plain Craft Launcher 2/Modules/Base/JsonNodeExtensions.cs
PCL.Core/App/Configuration/Storage/JsonFileProvider.cs
PCL.Core/App/Configuration/Storage/ConfigStorage.cs
PCL.Core/App/Configuration/Storage/EncryptedFileConfigStorage.cs
PCL.Core/App/Configuration/Storage/JsonToYamlConverter.cs
PCL.Core/App/Essentials/StartupService.cs
PCL.Core/App/Essentials/SingleInstanceService.cs
PCL.Core/App/Essentials/PromoteService.cs
PCL.Core/App/Essentials/DependencyCheckService.cs
PCL.Core/App/Basics.cs
PCL.Core/IO/Files.cs
PCL.Core/IO/Net/Http/HttpContentExtension.cs
PCL.Core/IO/Net/Http/HttpRouteResponse.cs
PCL.Core/IO/Net/Http/HttpResponseExtension.cs
PCL.Core/Link/McPing/McPingService.cs
PCL.Core/Link/EasyTier/ETInfoProvider.cs
PCL.Core/Link/Scaffolding/EasyTier/EasyTierEntity.cs
PCL.Core/Link/Scaffolding/EasyTier/CliNetTest.cs
PCL.Core/Link/Scaffolding/Client/Requests/GetPlayerProfileListRequest.cs
PCL.Core/Link/Scaffolding/Client/Requests/PlayerPingRequest.cs
PCL.Core/Link/Scaffolding/Server/Handlers/GetPlayerProfileListHandler.cs
PCL.Core/Link/Scaffolding/Server/Handlers/PlayerPingHandler.cs
PCL.Core/Link/Natayark/NatayarkProfileManager.cs
Plain Craft Launcher 2/Modules/Network/Http/Requester.cs
Plain Craft Launcher 2/Modules/Base/ModBase.cs
Harden JSON parsing and type conversion across launcher modules using JsonCompat and safer JsonNode access.
  • Replace JsonNode.GetValue() and bare JsonSerializer calls with JsonCompat.ToObject() or SerializerOptions-aware calls in mod download, profile, Java, style, and update code.
  • Use ModBase.GetJson (now backed by JsonCompat.ParseNode) wherever raw strings are parsed, including profile files, asset indexes, remote caches, and Yggdrasil responses.
  • Adjust code to tolerate missing/invalid nodes by null-propagation and defaulting, e.g., when reading serverName, notice versions, LabyMod fields, and Minecraft version metadata.
  • Update JSON writing paths to reuse JsonCompat.SerializerOptions (often cloned with WriteIndented = true) to ensure round-trippable, consistent formatting.
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.cs
Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs
Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs
Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs
Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs
Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs
Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs
Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs
Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs
Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs
Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.cs
PCL.Core/App/Tools/DependencyCheckService.cs
PCL.Core/Minecraft/McVersionClassifier.cs
PCL.Core/Minecraft/Java/JavaManager.cs
PCL.Core/Test/App/CommandLineTest.cs
PCL.Core.Test/DynamicJsonTest.cs
Fix JSON-related bugs and edge cases in auth flows, Yggdrasil models, JWT handling, and HTTP helpers.
  • JsonWebToken now serializes/deserializes header and payload with JsonCompat.SerializerOptions to get lenient behavior and consistent enum/string handling.
  • YggdrasilLegacyClient.SignOutAsync returns early on 204 and only parses JSON error bodies with JsonCompat; error description becomes null when no body.
  • YggdrasilAuthenticateResult.User is changed to an init-only property, and Agent in YggdrasilCredential becomes init-only with a default instance, matching record semantics.
  • HttpContentExtension.WithJsonContent and HttpRouteResponse.Json/HttpResponseExtension.AsJsonAsync all accept/use JsonCompat.SerializerOptions by default to avoid mismatched options between callers and servers.
PCL.Core/Minecraft/IdentityModel/Extensions/JsonWebToken/JsonWebToken.cs
PCL.Core/Minecraft/IdentityModel/Extensions/JsonWebToken/JsonWebKeys.cs
PCL.Core/Minecraft/IdentityModel/Yggdrasil/Client.cs
PCL.Core/Minecraft/IdentityModel/Yggdrasil/YggdrasilCredential.cs
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs
PCL.Core/IO/Net/Http/HttpContentExtension.cs
PCL.Core/IO/Net/Http/HttpRouteResponse.cs
PCL.Core/IO/Net/Http/HttpResponseExtension.cs
Improve robustness of JSON-driven domain logic such as version classification, LabyMod merge, and dynamic/expando handling.
  • McVersionClassifier.GetReleaseTime/_GetDateTime now tolerate various DateTime/string forms and normalize to local time; _GetString no longer throws on non-string values.
  • LabyMod merge logic stops using JsonNode.Parse on interpolated strings and instead constructs JsonObject trees with null checks and DeepClone for sizes, avoiding invalid JSON on missing properties.
  • ExpandoObjectConverter.Read avoids double-serialization by recursively mapping JsonElement to ExpandoObject/List/primitive types, and is wired through tests using JsonCompat.SerializerOptions.
  • Forge version list now uses FetchString instead of FetchJson because the upstream endpoint returns HTML, avoiding parse failures.
PCL.Core/Minecraft/McVersionClassifier.cs
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs
Plain Craft Launcher 2/Modules/Minecraft/ModDownloadLib.cs
PCL.Core/Utils/ExpandoObjectConverter.cs
PCL.Core.Test/DynamicJsonTest.cs
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs

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[bot]

This comment was marked as resolved.

… freeze SerializerOptions

- Add TryGetDateTime() and TryParseDateTime() to JsonCompat, shared with FlexibleDateTimeConverter
- Simplify McVersionClassifier._GetDateTime() by delegating to JsonCompat.TryGetDateTime()
- Freeze SerializerOptions with MakeReadOnly() to prevent accidental mutation
- Wrap SignOutAsync parsing in try/catch to handle non-JSON responses gracefully
@Chiloven945 Chiloven945 requested a review from a team May 30, 2026 11:26
Copy link
Copy Markdown
Member

@Big-Cake-jpg Big-Cake-jpg left a comment

Choose a reason for hiding this comment

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

简单测了下似乎没啥问题,先就这样吧,爆了问题再修……(

@pcl-ce-automation pcl-ce-automation Bot added 🕑 等待合并 已处理完毕,正在等待代码合并入主分支 and removed 🛠️ 等待审查 Pull Request 已完善,等待维护者或负责人进行代码审查 labels May 30, 2026
@Big-Cake-jpg Big-Cake-jpg merged commit 40dbd07 into dev May 30, 2026
3 checks passed
@pcl-ce-automation pcl-ce-automation Bot added 👌 完成 相关问题已修复或功能已实现,计划在下次版本更新时正式上线 and removed 🕑 等待合并 已处理完毕,正在等待代码合并入主分支 labels May 30, 2026
@Big-Cake-jpg Big-Cake-jpg deleted the fix/json2 branch May 30, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: XXL PR 大小评估:巨型 👌 完成 相关问题已修复或功能已实现,计划在下次版本更新时正式上线

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants