Skip to content

[+] New mod GameSystem.SkipBoardNoCheck#50

Merged
clansty merged 2 commits intoMuNET-OSS:mainfrom
Eternal973:main
Sep 6, 2025
Merged

[+] New mod GameSystem.SkipBoardNoCheck#50
clansty merged 2 commits intoMuNET-OSS:mainfrom
Eternal973:main

Conversation

@Eternal973
Copy link
Copy Markdown
Contributor

@Eternal973 Eternal973 commented Aug 22, 2025

Skip "BoardNo check" to use the old cab light board 837-15070-02 on Sinmai. Tested. Use [HarmonyTranspiler].

Sourcery 总结

添加一个新的 GameSystem.SkipBoardNoCheck mod,该mod使用 Harmony transpilers 来覆盖电路板验证和固件更新检查,从而支持旧版 837-15070-02 驾驶室灯板。

新功能:

  • 引入 SkipBoardNoCheck mod,以绕过旧版驾驶室灯板 837-15070-02 的 BoardNo 检查
  • 实现 Harmony transpiler 补丁,强制使 BoardCtrl15070_4._md_initBoard_GetBoardInfo 和 Bd15070_4Control.IsNeedFirmUpdate 成功

改进:

  • 在 configSort.yaml 的 mod 加载顺序中添加 SkipBoardNoCheck 条目
Original summary in English

Summary by Sourcery

Add a new GameSystem.SkipBoardNoCheck mod that uses Harmony transpilers to override board validation and firmware update checks, enabling support for the legacy 837-15070-02 cab light board.

New Features:

  • Introduce SkipBoardNoCheck mod to bypass BoardNo checks for the old cab light board 837-15070-02
  • Implement Harmony transpiler patches to force success in BoardCtrl15070_4._md_initBoard_GetBoardInfo and Bd15070_4Control.IsNeedFirmUpdate

Enhancements:

  • Add SkipBoardNoCheck entry to the mod load order in configSort.yaml

Skip BoardNo Check to use 837-15070-02 as 837-15070-04. (use HarmonyTranspiler,)
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Aug 22, 2025

审阅者指南

引入了一个新的模组,通过向两个目标方法注入 Harmony 转译器来绕过旧版 837-15070-02 板卡的板号检查,并将新模组注册到配置中。

Harmony 转译器修补 BoardCtrl15070_4._md_initBoard_GetBoardInfo 的时序图

sequenceDiagram
    participant Harmony as HarmonyTranspiler
    participant BoardCtrl as BoardCtrl15070_4
    participant Logger as MelonLogger
    Harmony->>BoardCtrl: Patch _md_initBoard_GetBoardInfo
    BoardCtrl->>Harmony: Provide instructions
    Harmony->>BoardCtrl: Replace IsEqual call with always true
    Harmony->>Logger: Log patch success or warning
Loading

Harmony 转译器修补 Bd15070_4Control.IsNeedFirmUpdate 的时序图

sequenceDiagram
    participant Harmony as HarmonyTranspiler
    participant BdControl as Bd15070_4Control
    participant Logger as MelonLogger
    Harmony->>BdControl: Patch IsNeedFirmUpdate
    BdControl->>Harmony: Provide instructions
    Harmony->>BdControl: Replace IsEqual call with always true
    Harmony->>Logger: Log patch success or warning
Loading

新 SkipBoardNoCheck 模组的类图

classDiagram
    class SkipBoardNoCheck {
        <<ConfigSection>>
        +Transpiler1(instructions)
        +Transpiler2(instructions)
    }
    SkipBoardNoCheck --|> HarmonyTranspiler
    SkipBoardNoCheck --|> HarmonyPatch
    HarmonyPatch <|-- BoardCtrl15070_4
    HarmonyPatch <|-- Bd15070_4Control
    BoardCtrl15070_4 : _md_initBoard_GetBoardInfo()
    Bd15070_4Control : IsNeedFirmUpdate()
Loading

文件级别更改

更改 详情 文件
在加载顺序中注册新的 SkipBoardNoCheck 模组
  • 将 GameSystem.SkipBoardNoCheck 条目添加到 configSort.yaml
AquaMai/configSort.yaml
实现带两个 Harmony 转译器的 SkipBoardNoCheck 模组
  • 转译器1 修补 BoardCtrl15070_4._md_initBoard_GetBoardInfo 以强制 IsEqual 为真
  • 转译器2 以相同方式修补 Bd15070_4Control.IsNeedFirmUpdate
  • 每个转译器在成功时记录日志,或在未找到目标指令时发出警告
AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs

提示和命令

与 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

Introduces a new mod that bypasses board number checks for the legacy 837-15070-02 board by injecting Harmony transpilers into two target methods, and registers the new mod in the configuration.

Sequence diagram for Harmony transpiler patching BoardCtrl15070_4._md_initBoard_GetBoardInfo

sequenceDiagram
    participant Harmony as HarmonyTranspiler
    participant BoardCtrl as BoardCtrl15070_4
    participant Logger as MelonLogger
    Harmony->>BoardCtrl: Patch _md_initBoard_GetBoardInfo
    BoardCtrl->>Harmony: Provide instructions
    Harmony->>BoardCtrl: Replace IsEqual call with always true
    Harmony->>Logger: Log patch success or warning
Loading

Sequence diagram for Harmony transpiler patching Bd15070_4Control.IsNeedFirmUpdate

sequenceDiagram
    participant Harmony as HarmonyTranspiler
    participant BdControl as Bd15070_4Control
    participant Logger as MelonLogger
    Harmony->>BdControl: Patch IsNeedFirmUpdate
    BdControl->>Harmony: Provide instructions
    Harmony->>BdControl: Replace IsEqual call with always true
    Harmony->>Logger: Log patch success or warning
Loading

Class diagram for the new SkipBoardNoCheck mod

classDiagram
    class SkipBoardNoCheck {
        <<ConfigSection>>
        +Transpiler1(instructions)
        +Transpiler2(instructions)
    }
    SkipBoardNoCheck --|> HarmonyTranspiler
    SkipBoardNoCheck --|> HarmonyPatch
    HarmonyPatch <|-- BoardCtrl15070_4
    HarmonyPatch <|-- Bd15070_4Control
    BoardCtrl15070_4 : _md_initBoard_GetBoardInfo()
    Bd15070_4Control : IsNeedFirmUpdate()
Loading

File-Level Changes

Change Details Files
Register new SkipBoardNoCheck mod in the load order
  • Added GameSystem.SkipBoardNoCheck entry to configSort.yaml
AquaMai/configSort.yaml
Implement SkipBoardNoCheck mod with two Harmony transpilers
  • Transpiler1 patches BoardCtrl15070_4._md_initBoard_GetBoardInfo to force IsEqual to true
  • Transpiler2 patches Bd15070_4Control.IsNeedFirmUpdate in the same manner
  • Each transpiler logs success or warns if the target instruction isn’t found
AquaMai.Mods/GameSystem/SkipBoardNoCheck.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

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

你好 - 我已经审阅了你的更改,它们看起来很棒!

AI 代理提示
请解决此代码审查中的评论:
## 单独评论

### 评论 1
<location> `AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs:23` </location>
<code_context>
+    [HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
+    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
+    {
+        var codes = new List<CodeInstruction>(instructions);
+        bool patched = false;
+        for (int i = 0; i < codes.Count; i++)
</code_context>

<issue_to_address>
考虑使用更健壮的模式来匹配目标指令。

通过字符串值匹配操作数容易出错,并且如果方法名称或签名更改,可能会中断。为了可靠性,请直接比较 MethodInfo。

建议的实现:

```csharp
        var codes = new List<CodeInstruction>(instructions);
        bool patched = false;

        // 获取目标 IsEqual 方法的 MethodInfo
        var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand is MethodInfo method &&
                method == isEqualMethod)
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));

                patched = true;

```

如果 `IsEqual` 方法被重载,你可能需要在 `GetMethod` 中指定参数类型。例如:
```csharp
var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new[] { typeof(/* param types here */) }, null);
```
此外,请确保你的文件顶部有 `using System.Reflection;`(如果尚未存在)。
</issue_to_address>

### 评论 2
<location> `AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs:19` </location>
<code_context>
+        return codes;
+    }
+
+    [HarmonyTranspiler]
+    [HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
+    static IEnumerable<CodeInstruction> Transpiler2(IEnumerable<CodeInstruction> instructions)
+    {
+        var codes = new List<CodeInstruction>(instructions);
</code_context>

<issue_to_address>
重复的 Transpiler 逻辑可以重构以提高可维护性。

考虑将共享的修补逻辑移到一个辅助方法中,以最大程度地减少重复并简化未来的更新。

建议的实现:

```csharp
    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);

```

```csharp
    [HarmonyTranspiler]
    [HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
    static IEnumerable<CodeInstruction> Transpiler2(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);

```

```csharp
    // 用于重构共享 Transpiler 逻辑的辅助方法
    private static IEnumerable<CodeInstruction> PatchIsEqualTranspiler(IEnumerable<CodeInstruction> instructions)
    {
        var codes = new List<CodeInstruction>(instructions);
        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand.ToString().Contains("IsEqual"))
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));
                break;
            }
        }
        return codes;
    }

```
</issue_to_address>

### 评论 3
<location> `AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs:21` </location>
<code_context>
+{
+    [HarmonyTranspiler]
+    [HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
+    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
+    {
+        var codes = new List<CodeInstruction>(instructions);
</code_context>

<issue_to_address>
考虑重构 Transpiler 方法以使用共享的 IL 修补助手来消除重复代码。

以下是将两个 Transpiler 合并为一个 IL 修补器并删除所有重复的循环/列表逻辑而无需更改任何行为的一种方法:

```csharp
// 1) 执行 “Pop, Pop, Ldc_I4_1” 替换 + 日志记录的通用助手
static IEnumerable<CodeInstruction> ReplaceIsEqual(
    IEnumerable<CodeInstruction> instructions,
    string contextName)
{
    var codes = instructions.ToList();
    bool patched = false;

    for (int i = 0; i < codes.Count; i++)
    {
        var instr = codes[i];
        if (instr.opcode == OpCodes.Callvirt
            && instr.operand != null
            && instr.operand.ToString().Contains("IsEqual"))
        {
            codes[i]     = new CodeInstruction(OpCodes.Pop);
            codes.Insert(i+1, new CodeInstruction(OpCodes.Pop));
            codes.Insert(i+2, new CodeInstruction(OpCodes.Ldc_I4_1));
            MelonLoader.MelonLogger.Msg(
                $"[SkipBoardNoCheck] 修补 {contextName} 方法成功");
            patched = true;
            break;
        }
    }

    if (!patched)
        MelonLoader.MelonLogger.Warning(
            $"[SkipBoardNoCheck] 未找到需要修补的代码位置:{contextName}");

    return codes;
}
```

```csharp
// 2) 单个 Transpiler 方法,修补到两个目标,
//    将其自己的上下文字符串传递给助手
[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
[HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
public static class SkipBoardNoCheck
{
    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler1(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "BoardCtrl15070_4._md_initBoard_GetBoardInfo");

    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler2(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "Bd15070_4Control.IsNeedFirmUpdate");
}
```

这消除了所有手动 IL 重复,同时保持了两个补丁和日志的完整性。
</issue_to_address>

Sourcery 对开源项目免费 - 如果你喜欢我们的评论,请考虑分享它们 ✨
请帮助我变得更有用!请在每个评论上点击 👍 或 👎,我将使用这些反馈来改进你的评论。
Original comment in English

Hey there - I've reviewed your changes and they look great!

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

### Comment 1
<location> `AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs:23` </location>
<code_context>
+    [HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
+    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
+    {
+        var codes = new List<CodeInstruction>(instructions);
+        bool patched = false;
+        for (int i = 0; i < codes.Count; i++)
</code_context>

<issue_to_address>
Consider using a more robust pattern for matching the target instruction.

Matching the operand by its string value is error-prone and may break if method names or signatures change. Prefer comparing MethodInfo directly for reliability.

Suggested implementation:

```csharp
        var codes = new List<CodeInstruction>(instructions);
        bool patched = false;

        // Get MethodInfo for the target IsEqual method
        var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand is MethodInfo method &&
                method == isEqualMethod)
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));

                patched = true;

```

If the `IsEqual` method is overloaded, you may need to specify the parameter types in `GetMethod`. For example:
```csharp
var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new[] { typeof(/* param types here */) }, null);
```
Also, ensure you have `using System.Reflection;` at the top of your file if not already present.
</issue_to_address>

### Comment 2
<location> `AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs:19` </location>
<code_context>
+        return codes;
+    }
+
+    [HarmonyTranspiler]
+    [HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
+    static IEnumerable<CodeInstruction> Transpiler2(IEnumerable<CodeInstruction> instructions)
+    {
+        var codes = new List<CodeInstruction>(instructions);
</code_context>

<issue_to_address>
Duplicated transpiler logic could be refactored for maintainability.

Consider moving the shared patching logic into a helper method to minimize duplication and simplify future updates.

Suggested implementation:

```csharp
    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);

```

```csharp
    [HarmonyTranspiler]
    [HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
    static IEnumerable<CodeInstruction> Transpiler2(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);

```

```csharp
    // Helper method to refactor shared transpiler logic
    private static IEnumerable<CodeInstruction> PatchIsEqualTranspiler(IEnumerable<CodeInstruction> instructions)
    {
        var codes = new List<CodeInstruction>(instructions);
        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand.ToString().Contains("IsEqual"))
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));
                break;
            }
        }
        return codes;
    }

```
</issue_to_address>

### Comment 3
<location> `AquaMai.Mods/GameSystem/SkipBoardNoCheck.cs:21` </location>
<code_context>
+{
+    [HarmonyTranspiler]
+    [HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
+    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
+    {
+        var codes = new List<CodeInstruction>(instructions);
</code_context>

<issue_to_address>
Consider refactoring the transpiler methods to use a shared helper for IL patching to eliminate duplicated code.

Heres one way to collapse both transpilers into a single ILpatcher and remove all of the duplicated loop/list logic without changing any behavior:

```csharp
// 1) Common helper that does the “Pop, Pop, Ldc_I4_1” replace + logging
static IEnumerable<CodeInstruction> ReplaceIsEqual(
    IEnumerable<CodeInstruction> instructions,
    string contextName)
{
    var codes = instructions.ToList();
    bool patched = false;

    for (int i = 0; i < codes.Count; i++)
    {
        var instr = codes[i];
        if (instr.opcode == OpCodes.Callvirt
            && instr.operand != null
            && instr.operand.ToString().Contains("IsEqual"))
        {
            codes[i]     = new CodeInstruction(OpCodes.Pop);
            codes.Insert(i+1, new CodeInstruction(OpCodes.Pop));
            codes.Insert(i+2, new CodeInstruction(OpCodes.Ldc_I4_1));
            MelonLoader.MelonLogger.Msg(
                $"[SkipBoardNoCheck] 修补 {contextName} 方法成功");
            patched = true;
            break;
        }
    }

    if (!patched)
        MelonLoader.MelonLogger.Warning(
            $"[SkipBoardNoCheck] 未找到需要修补的代码位置:{contextName}");

    return codes;
}
```

```csharp
// 2) Single transpiler method, patched to both targets,
//    passing its own context string into the helper
[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
[HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
public static class SkipBoardNoCheck
{
    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler1(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "BoardCtrl15070_4._md_initBoard_GetBoardInfo");

    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler2(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "Bd15070_4Control.IsNeedFirmUpdate");
}
```

This removes all the manualIL duplication while keeping both patches and logs intact.
</issue_to_address>

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.

[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: 考虑使用更健壮的模式来匹配目标指令。

通过字符串值匹配操作数容易出错,并且如果方法名称或签名更改,可能会中断。为了可靠性,请直接比较 MethodInfo。

建议的实现:

        var codes = new List<CodeInstruction>(instructions);
        bool patched = false;

        // 获取目标 IsEqual 方法的 MethodInfo
        var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand is MethodInfo method &&
                method == isEqualMethod)
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));

                patched = true;

如果 IsEqual 方法被重载,你可能需要在 GetMethod 中指定参数类型。例如:

var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new[] { typeof(/* param types here */) }, null);

此外,请确保你的文件顶部有 using System.Reflection;(如果尚未存在)。

Original comment in English

suggestion: Consider using a more robust pattern for matching the target instruction.

Matching the operand by its string value is error-prone and may break if method names or signatures change. Prefer comparing MethodInfo directly for reliability.

Suggested implementation:

        var codes = new List<CodeInstruction>(instructions);
        bool patched = false;

        // Get MethodInfo for the target IsEqual method
        var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand is MethodInfo method &&
                method == isEqualMethod)
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));

                patched = true;

If the IsEqual method is overloaded, you may need to specify the parameter types in GetMethod. For example:

var isEqualMethod = typeof(BoardCtrl15070_4).GetMethod("IsEqual", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new[] { typeof(/* param types here */) }, null);

Also, ensure you have using System.Reflection; at the top of your file if not already present.

Comment on lines +19 to +28
[HarmonyTranspiler]
[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
{
var codes = new List<CodeInstruction>(instructions);
bool patched = false;
for (int i = 0; i < codes.Count; i++)
{
if (codes[i].opcode == OpCodes.Callvirt &&
codes[i].operand != null &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: 重复的 Transpiler 逻辑可以重构以提高可维护性。

考虑将共享的修补逻辑移到一个辅助方法中,以最大程度地减少重复并简化未来的更新。

建议的实现:

    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);
    [HarmonyTranspiler]
    [HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
    static IEnumerable<CodeInstruction> Transpiler2(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);
    // 用于重构共享 Transpiler 逻辑的辅助方法
    private static IEnumerable<CodeInstruction> PatchIsEqualTranspiler(IEnumerable<CodeInstruction> instructions)
    {
        var codes = new List<CodeInstruction>(instructions);
        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand.ToString().Contains("IsEqual"))
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));
                break;
            }
        }
        return codes;
    }
Original comment in English

suggestion: Duplicated transpiler logic could be refactored for maintainability.

Consider moving the shared patching logic into a helper method to minimize duplication and simplify future updates.

Suggested implementation:

    static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);
    [HarmonyTranspiler]
    [HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
    static IEnumerable<CodeInstruction> Transpiler2(IEnumerable<CodeInstruction> instructions)
    {
        return PatchIsEqualTranspiler(instructions);
    // Helper method to refactor shared transpiler logic
    private static IEnumerable<CodeInstruction> PatchIsEqualTranspiler(IEnumerable<CodeInstruction> instructions)
    {
        var codes = new List<CodeInstruction>(instructions);
        for (int i = 0; i < codes.Count; i++)
        {
            if (codes[i].opcode == OpCodes.Callvirt &&
                codes[i].operand != null &&
                codes[i].operand.ToString().Contains("IsEqual"))
            {
                codes[i] = new CodeInstruction(OpCodes.Pop);
                codes.Insert(i + 1, new CodeInstruction(OpCodes.Pop));
                codes.Insert(i + 2, new CodeInstruction(OpCodes.Ldc_I4_1));
                break;
            }
        }
        return codes;
    }

{
[HarmonyTranspiler]
[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
static IEnumerable<CodeInstruction> Transpiler1(IEnumerable<CodeInstruction> instructions)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (complexity): 考虑重构 Transpiler 方法以使用共享的 IL 修补助手来消除重复代码。

以下是将两个 Transpiler 合并为一个 IL 修补器并删除所有重复的循环/列表逻辑而无需更改任何行为的一种方法:

// 1) 执行 “Pop, Pop, Ldc_I4_1” 替换 + 日志记录的通用助手
static IEnumerable<CodeInstruction> ReplaceIsEqual(
    IEnumerable<CodeInstruction> instructions,
    string contextName)
{
    var codes = instructions.ToList();
    bool patched = false;

    for (int i = 0; i < codes.Count; i++)
    {
        var instr = codes[i];
        if (instr.opcode == OpCodes.Callvirt
            && instr.operand != null
            && instr.operand.ToString().Contains("IsEqual"))
        {
            codes[i]     = new CodeInstruction(OpCodes.Pop);
            codes.Insert(i+1, new CodeInstruction(OpCodes.Pop));
            codes.Insert(i+2, new CodeInstruction(OpCodes.Ldc_I4_1));
            MelonLoader.MelonLogger.Msg(
                $"[SkipBoardNoCheck] 修补 {contextName} 方法成功");
            patched = true;
            break;
        }
    }

    if (!patched)
        MelonLoader.MelonLogger.Warning(
            $"[SkipBoardNoCheck] 未找到需要修补的代码位置:{contextName}");

    return codes;
}
// 2) 单个 Transpiler 方法,修补到两个目标,
//    将其自己的上下文字符串传递给助手
[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
[HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
public static class SkipBoardNoCheck
{
    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler1(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "BoardCtrl15070_4._md_initBoard_GetBoardInfo");

    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler2(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "Bd15070_4Control.IsNeedFirmUpdate");
}

这消除了所有手动 IL 重复,同时保持了两个补丁和日志的完整性。

Original comment in English

issue (complexity): Consider refactoring the transpiler methods to use a shared helper for IL patching to eliminate duplicated code.

Here’s one way to collapse both transpilers into a single IL‐patcher and remove all of the duplicated loop/list logic without changing any behavior:

// 1) Common helper that does the “Pop, Pop, Ldc_I4_1” replace + logging
static IEnumerable<CodeInstruction> ReplaceIsEqual(
    IEnumerable<CodeInstruction> instructions,
    string contextName)
{
    var codes = instructions.ToList();
    bool patched = false;

    for (int i = 0; i < codes.Count; i++)
    {
        var instr = codes[i];
        if (instr.opcode == OpCodes.Callvirt
            && instr.operand != null
            && instr.operand.ToString().Contains("IsEqual"))
        {
            codes[i]     = new CodeInstruction(OpCodes.Pop);
            codes.Insert(i+1, new CodeInstruction(OpCodes.Pop));
            codes.Insert(i+2, new CodeInstruction(OpCodes.Ldc_I4_1));
            MelonLoader.MelonLogger.Msg(
                $"[SkipBoardNoCheck] 修补 {contextName} 方法成功");
            patched = true;
            break;
        }
    }

    if (!patched)
        MelonLoader.MelonLogger.Warning(
            $"[SkipBoardNoCheck] 未找到需要修补的代码位置:{contextName}");

    return codes;
}
// 2) Single transpiler method, patched to both targets,
//    passing its own context string into the helper
[HarmonyPatch(typeof(BoardCtrl15070_4), "_md_initBoard_GetBoardInfo")]
[HarmonyPatch(typeof(Bd15070_4Control), "IsNeedFirmUpdate")]
public static class SkipBoardNoCheck
{
    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler1(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "BoardCtrl15070_4._md_initBoard_GetBoardInfo");

    [HarmonyTranspiler]
    static IEnumerable<CodeInstruction> Transpiler2(
        IEnumerable<CodeInstruction> instrs)
        => ReplaceIsEqual(
            instrs,
            "Bd15070_4Control.IsNeedFirmUpdate");
}

This removes all the manual‐IL duplication while keeping both patches and logs intact.

@Eternal973
Copy link
Copy Markdown
Contributor Author

ai说的我一个都看不懂,但是代码既然能跑,就不用动,性能差异是微乎其微的。

@clansty
Copy link
Copy Markdown
Member

clansty commented Sep 6, 2025

ETN973 漏的

@clansty clansty merged commit 00b36b7 into MuNET-OSS:main Sep 6, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants