Skip to content

Conversation

@Haisairova-Official
Copy link
Contributor

No description provided.

Haisairova-Official and others added 12 commits December 21, 2025 15:08
Implement CustomSkinsPlusStatic for full-scene background replacement with static injection. Includes methods for loading custom sprites and textures, and patches for rendering graphics.
Updated warning message for potential performance impact and conflicts.
Refactor SetFade class for better organization and functionality, including JSON loading and resource management.
@gemini-code-assist
Copy link

Summary of Changes

Hello @Haisairova-Official, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求通过引入KLD特殊转场功能,显著增强了现有转场动画模块。该功能允许开发者为特定歌曲配置独特的转场效果,通过外部JSON文件进行灵活管理。它采用了一种创新的“充能”机制,确保KLD转场在歌曲选择后有限次触发,为游戏体验增添了更多动态和个性化的视觉元素,尤其适用于1.55+版本。

Highlights

  • 引入KLD特殊转场: 为游戏引入了基于歌曲ID的KLD(Kaleidxscope)特殊转场动画功能,提升视觉体验。
  • JSON配置支持: 允许通过外部 CommonFadeList.json 文件配置哪些歌曲将触发KLD转场,并定义其具体动画参数,增加了灵活性。
  • 充能机制: KLD转场在匹配歌曲被选中后会“充能”3次,允许在接下来的几次转场中触发特殊动画,避免过度使用。
  • 资源动态加载: 在KLD转场激活时,动态加载KLD专属的预制件(UI_KLD_ChangeScreenUI_KLD_Sub_ChangeScreen),而非默认转场资源,实现更精细的控制。
  • 兼容现有转场: 在KLD转场未激活时,仍沿用原有的“普通”、“Plus”或“Festa”转场逻辑作为回退,确保功能稳定。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

这次的PR通过为特定歌曲增加KLD转场动画,极大地增强了模组的功能,非常棒。代码重构将原有逻辑与新功能整合得很好。

不过,我发现了一些可以改进的地方,主要集中在以下几点:

  • JSON解析: 目前使用正则表达式来解析JSON文件,这种方式非常脆弱且容易出错。我强烈建议改用成熟的JSON库(如 Newtonsoft.Json)来处理,这样代码会更健壮、更易于维护。
  • 异常处理: 代码中多处使用了空的 catch {} 块。这会静默地吞噬所有异常,导致出现问题时难以排查。建议至少在 catch 块中记录异常信息。
  • 代码健壮性与性能: 部分代码在健壮性(如资源加载检查)和性能(如高频调用的Hook点)方面还有提升空间。

我已经针对这些问题提出了具体的修改建议,希望能帮助你进一步完善代码。

Comment on lines 207 to 227
private static void LoadJsonManual()
{
try {
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, JSONDir, JSONFileName);
if (!File.Exists(path)) return;
string content = File.ReadAllText(path);
cachedEntries.Clear();
var matches = Regex.Matches(content, @"\{[^{}]+\}");
foreach (Match m in matches) {
string raw = m.Value;
var e = new CommonFadeEntry {
ID = ExtractInt(raw, "ID"),
isBlack = ExtractInt(raw, "isBlack"),
Type = ExtractInt(raw, "Type"),
FadeType = ExtractInt(raw, "FadeType")
};
if (e.ID > 0) cachedEntries.Add(e);
}
MelonLogger.Msg($"[SetFade] 共载入 {cachedEntries.Count} 条 KLD 特殊配置。");
} catch (Exception e) { MelonLogger.Error($"[SetFade] JSON加载出错: {e.Message}"); }
}

Choose a reason for hiding this comment

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

critical

使用正则表达式来手动解析JSON文件非常脆弱且容易出错。它强依赖于JSON字符串的格式(如空格),并且无法处理嵌套对象或数组等复杂情况。当 CommonFadeList.json 文件格式稍微改变,解析就可能失败。

强烈建议使用一个标准的JSON库(例如 Newtonsoft.Json)来反序列化JSON。这样代码会更简洁、稳健且易于维护。这也使得 ExtractInt 方法变得多余,可以将其删除。

你需要将 Newtonsoft.Json.dll 添加到你的项目引用中,并在文件顶部添加 using Newtonsoft.Json;

    private static void LoadJsonManual()
    {
        try {
            string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, JSONDir, JSONFileName);
            if (!File.Exists(path)) return;
            
            string content = File.ReadAllText(path);
            
            var entries = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CommonFadeEntry>>(content);
            cachedEntries = entries?.FindAll(e => e.ID > 0) ?? new List<CommonFadeEntry>();

            MelonLogger.Msg($"[SetFade] 共载入 {cachedEntries.Count} 条 KLD 特殊配置。");
        } catch (Exception e) { 
            MelonLogger.Error($"[SetFade] JSON加载或解析出错: {e}"); 
        }
    }

_kldRemainingCharges = 0;
}
}
} catch { }

Choose a reason for hiding this comment

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

high

捕获了异常却不做任何处理(空的 catch 块)是一种危险的做法。如果 OnMusicSelectionChanged 方法内部的逻辑出现任何预料之外的错误,异常会被悄无声息地忽略掉,这会给调试带来巨大困难。

建议至少将异常信息记录下来,以便在出现问题时能够追踪。

} catch (Exception e) { MelonLogger.Error($"[SetFade] OnMusicSelectionChanged error: {e}"); }

try {
var subBG = monitor.transform.Find("Canvas/Sub/Sub_ChangeScreen(Clone)/Sub_BG")?.GetComponent<Image>();
if (subBG != null) subBG.sprite = subBGs[FadeType];
} catch { }

Choose a reason for hiding this comment

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

high

这里的空 catch 块同样会隐藏潜在的错误。例如,如果 monitor.transform.Find(...) 返回 null,后续的 GetComponent<Image>() 就会抛出 NullReferenceException。虽然代码中使用了 ?. 操作符来防御,但如果将来逻辑变动引入了其他错误,这个空的 catch 块会使问题排查变得困难。

建议添加日志记录。

} catch (Exception e) { MelonLogger.Warning($"[SetFade] Failed to replace SubBG: {e.Message}"); }

sCtrl.PlayAnimation(KaleidxScopeSubFadeController.AnimState.In);
}
}
} catch { }

Choose a reason for hiding this comment

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

high

同样地,空的 catch 块会隐藏 DriveKLDAnimation 方法中可能发生的所有错误,例如组件查找失败、类型转换失败等。这会使调试非常困难。

建议记录异常信息。

} catch (Exception e) { MelonLogger.Error($"[SetFade] Failed to drive KLD animation: {e}"); }

Comment on lines +46 to +48
subBGs[0] = Resources.Load<Sprite>("Process/ChangeScreen/Sprites/Sub_01");
subBGs[1] = Resources.Load<Sprite>("Process/ChangeScreen/Sprites/Sub_02");
subBGs[2] = (GameInfo.GameVersion >= 26000) ? Resources.Load<Sprite>("Process/ChangeScreen/Sprites/Sub_03") : subBGs[0];

Choose a reason for hiding this comment

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

medium

新的 Prepare 方法直接加载了 SubBG 精灵,但没有像旧的 SetFade_Initialize 方法那样检查加载结果是否为 null。如果 Resources.Load 由于某些原因(例如资源路径错误或资源损坏)失败并返回 null,那么在后续调用 ReplaceSubBG 时可能会导致 NullReferenceException

建议恢复对加载资源的空值检查,并在加载失败时记录错误日志,以提高模组的健壮性。

        subBGs[0] = Resources.Load<Sprite>("Process/ChangeScreen/Sprites/Sub_01");
        subBGs[1] = Resources.Load<Sprite>("Process/ChangeScreen/Sprites/Sub_02");
        subBGs[2] = (GameInfo.GameVersion >= 26000) ? Resources.Load<Sprite>("Process/ChangeScreen/Sprites/Sub_03") : subBGs[0];
        if (subBGs[0] == null || subBGs[1] == null || (GameInfo.GameVersion >= 26000 && subBGs[2] == null))
        {
            MelonLogger.Error("[SetFade] Failed to load one or more SubBG sprites. The mod may not function correctly.");
        }

if (_activeKldConfig != matched)
{
_activeKldConfig = matched;
_kldRemainingCharges = 3; // 锁定 3 次机会

Choose a reason for hiding this comment

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

medium

数字 3 在这里是一个“魔术数字”,它的含义没有在代码中明确解释。为了提高代码的可读性和可维护性,建议在类的顶部定义一个常量(例如 private const int KldInitialCharges = 3;),并在此处使用该常量。这样如果以后需要修改充能次数,只需要修改一处即可。

@Haisairova-Official
Copy link
Contributor Author

正则是不能改的。一改全都要出问题。我本来是正儿八经的json后来改成现在这样

name: "转场类型",
en: "Type: Non-Plus 0, Plus 1. (If SDEZ 1.60 can choose Festa 2)",
zh: "类型: Non-Plus 0, Plus 1. (SDEZ 1.60 限定可选 Festa 2)")]
[ConfigEntry(name: "转场类型", zh: "0:Normal, 1:Plus, 2:Festa(仅限1.60+)")]
Copy link
Member

Choose a reason for hiding this comment

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

我觉得既然两个功能要合在一起的话,这里应该提供一个选项叫 不更改

Copy link
Contributor Author

Choose a reason for hiding this comment

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

其实我在想写的时候预留过一个5)

}

private static int ExtractInt(string text, string key) {
var m = Regex.Match(text, $"\"{key}\"\\s*:\\s*\"?(\\d+)\"?");
Copy link
Member

Choose a reason for hiding this comment

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

真力大砖飞啊
有一个 TinyJson,要合并到主线里肯定是不可以手写 JSON parser 的

Copy link
Member

Choose a reason for hiding this comment

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

想办法解析到 dictionary 吧

Copy link
Contributor Author

Choose a reason for hiding this comment

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

真力大砖飞啊 有一个 TinyJson,要合并到主线里肯定是不可以手写 JSON parser 的

那我这个又想要点自定义的配置)) 写死也可以就是有点太长了吧

想办法解析到 dictionary 吧

没搞过 我理解一下

Copy link
Member

Choose a reason for hiding this comment

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

好吧,那我试试给你改一下
其实可以有一个默认的 json,没有的时候自动启用,内置在里面,内容就是门对应的歌

Copy link
Contributor Author

Choose a reason for hiding this comment

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

好吧,那我试试给你改一下 其实可以有一个默认的 json,没有的时候自动启用,内置在里面,内容就是门对应的歌

我其实也有这个想法)

@Haisairova-Official
Copy link
Contributor Author

宝宝我修好了你看看

@Haisairova-Official
Copy link
Contributor Author

又加了新模组)

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