Conversation
审阅者指南此PR引入了一个新的ReviveFinaleVSlide模组,通过Harmony转译器补丁将自定义SVG和HitArea数据注入到SlideManager中,从而实现起点和终点相同的V形滑块。 ReviveFinaleVSlide模组及相关类型的类图classDiagram
class ReviveFinaleVSlide {
+InsertData(list: List<string>) List<string>
+InsertHitArea(list: List<List<SlideManager.HitArea>>) List<List<SlideManager.HitArea>>
}
class ReviveFinaleVSlide.SlideDataPatch {
+Transpiler(instructions: IEnumerable<CodeInstruction>) IEnumerable<CodeInstruction>
}
class SlideManager {
-_vDataList: List<string>
-_vHitAreaList: List<List<HitArea>>
}
class SlideManager.HitArea {
+HitPoints: List<InputManager.TouchPanelArea>
+PushDistance: float
+ReleaseDistance: float
}
class InputManager.TouchPanelArea
ReviveFinaleVSlide <|-- ReviveFinaleVSlide.SlideDataPatch
SlideManager "1" *-- "many" SlideManager.HitArea
SlideManager.HitArea "1" *-- "many" InputManager.TouchPanelArea
文件级更改
提示和命令与Sourcery互动
自定义您的体验访问您的仪表盘以:
获取帮助Original review guide in EnglishReviewer's GuideThis PR introduces a new ReviveFinaleVSlide mod that enables v-shaped slides with identical start and end points by injecting custom SVG and HitArea data into SlideManager via a Harmony transpiler patch. Class diagram for ReviveFinaleVSlide mod and related typesclassDiagram
class ReviveFinaleVSlide {
+InsertData(list: List<string>) List<string>
+InsertHitArea(list: List<List<SlideManager.HitArea>>) List<List<SlideManager.HitArea>>
}
class ReviveFinaleVSlide.SlideDataPatch {
+Transpiler(instructions: IEnumerable<CodeInstruction>) IEnumerable<CodeInstruction>
}
class SlideManager {
-_vDataList: List<string>
-_vHitAreaList: List<List<HitArea>>
}
class SlideManager.HitArea {
+HitPoints: List<InputManager.TouchPanelArea>
+PushDistance: float
+ReleaseDistance: float
}
class InputManager.TouchPanelArea
ReviveFinaleVSlide <|-- ReviveFinaleVSlide.SlideDataPatch
SlideManager "1" *-- "many" SlideManager.HitArea
SlideManager.HitArea "1" *-- "many" InputManager.TouchPanelArea
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
你好 - 我已审阅了你的更改,它们看起来很棒!
AI 代理提示
请解决此代码审查中的评论:
## Individual Comments
### Comment 1
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:20` </location>
<code_context>
+ {
+ MelonLogger.Msg("[ReviveFinaleVSlide] Insert SVG data");
+
+ list[0] = "V_1.svg";
+ return list;
+ }
</code_context>
<issue_to_address>
直接覆盖 list[0] 可能会在列表为空时导致问题。
在不检查列表是否非空的情况下赋值给 list[0] 将会引发异常。请添加长度检查或使用安全处理空列表的方法。
</issue_to_address>
### Comment 2
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:63` </location>
<code_context>
+ return list;
+ }
+
+ [HarmonyPatch(typeof(SlideManager), MethodType.Constructor)]
+ public static class SlideDataPatch
+ {
</code_context>
<issue_to_address>
修补所有构造函数可能会产生意外的副作用。
如果 SlideManager 有多个构造函数,修补所有构造函数可能会导致问题。请指定构造函数签名以仅针对预期的构造函数。
建议的实现:
```csharp
// Example: If the intended constructor is SlideManager(int a, string b), use:
[HarmonyPatch(typeof(SlideManager), MethodType.Constructor, new Type[] { typeof(int), typeof(string) })]
public static class SlideDataPatch
{
```
你必须更新 `new Type[] { ... }` 数组以匹配你想要修补的特定 SlideManager 构造函数的参数类型。例如,如果构造函数是 `SlideManager(float x, bool y)`,请使用 `new Type[] { typeof(float), typeof(bool) }`。
</issue_to_address>
### Comment 3
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:73` </location>
<code_context>
+
+ foreach (var insn in instructions)
+ {
+ if (insn.StoresField(vDataList))
+ {
+ yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ReviveFinaleVSlide), "InsertData"));
+ }
+ else if (insn.StoresField(vHitAreaList))
+ {
+ yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ReviveFinaleVSlide), "InsertHitArea"));
</code_context>
<issue_to_address>
用方法调用替换字段存储指令可能会扰乱预期的堆栈行为。
请验证 InsertData 和 InsertHitArea 返回的值是否适合字段赋值,并确认这些方法调用后堆栈保持一致。
</issue_to_address>
### Comment 4
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:66` </location>
<code_context>
+ [HarmonyPatch(typeof(SlideManager), MethodType.Constructor)]
+ public static class SlideDataPatch
+ {
+ public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
+ {
+ var vDataList = AccessTools.Field(typeof(SlideManager), "_vDataList");
</code_context>
<issue_to_address>
考虑用一个简单的 Postfix 补丁和一个辅助函数替换 transpiler 和辅助方法,以使代码更短、更易读。
```markdown
你可以将所有 IL‐transpiler 代码和两个“Insert…”方法折叠成 SlideManager 构造函数上的一个简单 Postfix,然后将 HitArea 构造移动到一个带有集合初始化器的小型辅助函数中。这保持了相同的行为,但更短且更易读。
```csharp
[HarmonyPatch(typeof(SlideManager), MethodType.Constructor)]
static class SlideManagerCtorPatch
{
// Postfix can mutate the freshly created backing fields directly
static void Postfix(
ref List<string> ___vDataList,
ref List<List<SlideManager.HitArea>> ___vHitAreaList
)
{
MelonLogger.Msg("[ReviveFinaleVSlide] applying v-slide patch");
___vDataList[0] = "V_1.svg";
___vHitAreaList[0] = BuildVHitAreas();
}
// Helper builds the v-slide HitArea list in one place
static List<SlideManager.HitArea> BuildVHitAreas()
{
return new List<SlideManager.HitArea>
{
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.A1 },
PushDistance = 156.42124938964844,
ReleaseDistance= 43.27423858642578
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.B1 },
PushDistance = 128.9917755126953,
ReleaseDistance= 42.19921875
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.C1 },
PushDistance = 218.6302947998047,
ReleaseDistance= 42.19921875
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.B1 },
PushDistance = 128.9917755126953,
ReleaseDistance= 43.27423858642578
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.A1 },
PushDistance = 156.42124938964844,
ReleaseDistance= 0.0
},
};
}
}
```
步骤:
1. 删除 Transpiler 和两个 `Insert…` 方法。
2. 切换到 SlideManager 构造函数上的 `Postfix`,直接修改 `___vDataList` 和 `___vHitAreaList`。
3. 使用列表初始化器将 HitArea 数组提取到 `BuildVHitAreas()` 中——无需手动数组语法或冗余的 `return list;`。
4. 保持你的 `[ConfigSection]` 属性独立(如果仍然需要),但放在此补丁类之外。
</issue_to_address>帮助我更有用!请点击每个评论上的 👍 或 👎,我将使用反馈来改进你的评论。
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/ReviveFinaleVSlide.cs:20` </location>
<code_context>
+ {
+ MelonLogger.Msg("[ReviveFinaleVSlide] Insert SVG data");
+
+ list[0] = "V_1.svg";
+ return list;
+ }
</code_context>
<issue_to_address>
Directly overwriting list[0] may cause issues if the list is empty.
Assigning to list[0] without checking if the list is non-empty will raise an exception. Add a length check or use a method that safely handles empty lists.
</issue_to_address>
### Comment 2
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:63` </location>
<code_context>
+ return list;
+ }
+
+ [HarmonyPatch(typeof(SlideManager), MethodType.Constructor)]
+ public static class SlideDataPatch
+ {
</code_context>
<issue_to_address>
Patching all constructors may have unintended side effects.
If SlideManager has multiple constructors, patching all of them may cause issues. Specify the constructor signature to target only the intended one.
Suggested implementation:
```csharp
// Example: If the intended constructor is SlideManager(int a, string b), use:
[HarmonyPatch(typeof(SlideManager), MethodType.Constructor, new Type[] { typeof(int), typeof(string) })]
public static class SlideDataPatch
{
```
You must update the `new Type[] { ... }` array to match the parameter types of the specific SlideManager constructor you want to patch. For example, if the constructor is `SlideManager(float x, bool y)`, use `new Type[] { typeof(float), typeof(bool) }`.
</issue_to_address>
### Comment 3
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:73` </location>
<code_context>
+
+ foreach (var insn in instructions)
+ {
+ if (insn.StoresField(vDataList))
+ {
+ yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ReviveFinaleVSlide), "InsertData"));
+ }
+ else if (insn.StoresField(vHitAreaList))
+ {
+ yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ReviveFinaleVSlide), "InsertHitArea"));
</code_context>
<issue_to_address>
Replacing field store instructions with method calls may disrupt expected stack behavior.
Verify that InsertData and InsertHitArea return values suitable for field assignment, and confirm the stack remains consistent after these method calls.
</issue_to_address>
### Comment 4
<location> `AquaMai.Mods/GameSystem/ReviveFinaleVSlide.cs:66` </location>
<code_context>
+ [HarmonyPatch(typeof(SlideManager), MethodType.Constructor)]
+ public static class SlideDataPatch
+ {
+ public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
+ {
+ var vDataList = AccessTools.Field(typeof(SlideManager), "_vDataList");
</code_context>
<issue_to_address>
Consider replacing the transpiler and helper methods with a simple Postfix patch and a helper function to make the code shorter and more readable.
```markdown
You can collapse all that IL‐transpiler code and the two “Insert…” methods into a simple Postfix on SlideManager’s ctor, then move the HitArea construction into a small helper with a collection initializer. This keeps the same behavior but is far shorter and easier to read.
```csharp
[HarmonyPatch(typeof(SlideManager), MethodType.Constructor)]
static class SlideManagerCtorPatch
{
// Postfix can mutate the freshly created backing fields directly
static void Postfix(
ref List<string> ___vDataList,
ref List<List<SlideManager.HitArea>> ___vHitAreaList
)
{
MelonLogger.Msg("[ReviveFinaleVSlide] applying v-slide patch");
___vDataList[0] = "V_1.svg";
___vHitAreaList[0] = BuildVHitAreas();
}
// Helper builds the v-slide HitArea list in one place
static List<SlideManager.HitArea> BuildVHitAreas()
{
return new List<SlideManager.HitArea>
{
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.A1 },
PushDistance = 156.42124938964844,
ReleaseDistance= 43.27423858642578
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.B1 },
PushDistance = 128.9917755126953,
ReleaseDistance= 42.19921875
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.C1 },
PushDistance = 218.6302947998047,
ReleaseDistance= 42.19921875
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.B1 },
PushDistance = 128.9917755126953,
ReleaseDistance= 43.27423858642578
},
new() {
HitPoints = new[]{ InputManager.TouchPanelArea.A1 },
PushDistance = 156.42124938964844,
ReleaseDistance= 0.0
},
};
}
}
```
Steps:
1. Remove the Transpiler and the two `Insert…` methods.
2. Switch to a `Postfix` on SlideManager’s constructor, mutating `___vDataList` and `___vHitAreaList` directly.
3. Pull out the HitArea array into `BuildVHitAreas()` using a list initializer—no manual array syntax or redundant `return list;`.
4. Keep your `[ConfigSection]` attribute separate (if still needed) but outside of this patch class.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| { | ||
| MelonLogger.Msg("[ReviveFinaleVSlide] Insert SVG data"); | ||
|
|
||
| list[0] = "V_1.svg"; |
There was a problem hiding this comment.
issue: 直接覆盖 list[0] 可能会在列表为空时导致问题。
在不检查列表是否非空的情况下赋值给 list[0] 将会引发异常。请添加长度检查或使用安全处理空列表的方法。
Original comment in English
issue: Directly overwriting list[0] may cause issues if the list is empty.
Assigning to list[0] without checking if the list is non-empty will raise an exception. Add a length check or use a method that safely handles empty lists.
| return list; | ||
| } | ||
|
|
||
| [HarmonyPatch(typeof(SlideManager), MethodType.Constructor)] |
There was a problem hiding this comment.
suggestion (bug_risk): 修补所有构造函数可能会产生意外的副作用。
如果 SlideManager 有多个构造函数,修补所有构造函数可能会导致问题。请指定构造函数签名以仅针对预期的构造函数。
建议的实现:
// Example: If the intended constructor is SlideManager(int a, string b), use:
[HarmonyPatch(typeof(SlideManager), MethodType.Constructor, new Type[] { typeof(int), typeof(string) })]
public static class SlideDataPatch
{你必须更新 new Type[] { ... } 数组以匹配你想要修补的特定 SlideManager 构造函数的参数类型。例如,如果构造函数是 SlideManager(float x, bool y),请使用 new Type[] { typeof(float), typeof(bool) }。
Original comment in English
suggestion (bug_risk): Patching all constructors may have unintended side effects.
If SlideManager has multiple constructors, patching all of them may cause issues. Specify the constructor signature to target only the intended one.
Suggested implementation:
// Example: If the intended constructor is SlideManager(int a, string b), use:
[HarmonyPatch(typeof(SlideManager), MethodType.Constructor, new Type[] { typeof(int), typeof(string) })]
public static class SlideDataPatch
{You must update the new Type[] { ... } array to match the parameter types of the specific SlideManager constructor you want to patch. For example, if the constructor is SlideManager(float x, bool y), use new Type[] { typeof(float), typeof(bool) }.
| if (insn.StoresField(vDataList)) | ||
| { | ||
| yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ReviveFinaleVSlide), "InsertData")); | ||
| } | ||
| else if (insn.StoresField(vHitAreaList)) |
There was a problem hiding this comment.
issue (bug_risk): 用方法调用替换字段存储指令可能会扰乱预期的堆栈行为。
请验证 InsertData 和 InsertHitArea 返回的值是否适合字段赋值,并确认这些方法调用后堆栈保持一致。
Original comment in English
issue (bug_risk): Replacing field store instructions with method calls may disrupt expected stack behavior.
Verify that InsertData and InsertHitArea return values suitable for field assignment, and confirm the stack remains consistent after these method calls.
|
Is there any official chart that contains 1v1 slide? |
Sadly, no AFAIK. It exists in some fanmade charts though. |
Allow v-shaped slide with the same starting and ending point, such as
1v1in Simai notation.Sourcery 总结
通过使用 Harmony 转译器在运行时修补游戏的滑条数据和判定区域列表,启用同点V形滑条,并为该功能公开一个本地化的配置选项。
新功能:
改进:
Original summary in English
Summary by Sourcery
Enable same-point v-shaped slides by patching the game�s slide data and hit area lists at runtime using a Harmony transpiler and expose a localized config option for the feature.
New Features:
Enhancements: