Skip to content

Commit dc8fc11

Browse files
committed
feat(Settings): enhance Mod Settings UI integration and entry management
- Updated the ModSettingsUiPatches to ensure the "Mod Settings (RitsuLib)" entry is always displayed, regardless of registered pages. - Refactored entry line and divider node management for improved stability and performance. - Implemented methods to handle stale entry nodes and ensure proper refresh of the settings panel. - Enhanced documentation for clarity on functionality and behavior during UI interactions.
1 parent d9c67bf commit dc8fc11

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

Settings/Integration/Patches/ModSettingsUiPatches.cs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,20 @@ public static bool Prefix(NRunSubmenuStack __instance, Type type, ref NSubmenu _
109109

110110
/// <summary>
111111
/// Injects the “Mod Settings (RitsuLib)” row into the vanilla settings screen and keeps general panel height in sync.
112+
/// The entry is always shown regardless of registered page count; in-run access stays enabled.
112113
/// 将 “Mod Settings (RitsuLib)” 行注入原版设置屏幕,并保持 General 面板高度同步。
114+
/// 入口固定显示,与是否注册设置页无关;对局中保持可打开。
113115
/// </summary>
114116
[HarmonyAfter(Const.BaseLibHarmonyId)]
115117
[HarmonyPriority(Priority.Last)]
116118
public class SettingsScreenModSettingsButtonPatch : IPatchMethod
117119
{
118120
private const string GeneralSettingsResizeHookMeta = "ritsulib_general_settings_content_resize_hook";
119121

122+
private const string EntryLineNodeName = "RitsuLibModSettings";
123+
124+
private const string EntryDividerNodeName = "RitsuLibModSettingsDivider";
125+
120126
/// <inheritdoc />
121127
public static string PatchId => "ritsulib_mod_settings_button";
122128

@@ -133,19 +139,18 @@ public static ModPatchTarget[] GetTargets()
133139
[
134140
new(typeof(NSettingsScreen), nameof(NSettingsScreen._Ready)),
135141
new(typeof(NSettingsScreen), nameof(NSettingsScreen.OnSubmenuOpened)),
142+
new(typeof(NSettingsScreen), "OnSubmenuShown"),
136143
];
137144
}
138145

139146
// ReSharper disable once InconsistentNaming
140147
/// <summary>
141-
/// Ensures the entry line exists, refreshes copy, and schedules panel height refresh when mod pages exist.
142-
/// 确保条目行存在,刷新文案,并在存在 mod 页面时安排面板高度刷新
148+
/// Ensures the entry line exists and refreshes chrome on ready, open, and show.
149+
/// 在 ready、open、show 时确保入口行存在并刷新外观
143150
/// </summary>
144151
public static void Postfix(NSettingsScreen __instance)
145152
{
146153
RitsuLibModSettingsBootstrap.EnsureFrameworkPagesRegistered();
147-
if (!ModSettingsRegistry.HasPages)
148-
return;
149154

150155
try
151156
{
@@ -168,11 +173,13 @@ private static MarginContainer EnsureEntryPoint(NSettingsScreen screen)
168173
var content = panel.Content;
169174
EnsureGeneralSettingsContentTracksChildAdds(content);
170175

171-
if (content.GetNodeOrNull<MarginContainer>("RitsuLibModSettings") is { } existing)
176+
if (TryGetEntryLine(content) is { } existing)
172177
return existing;
173178

179+
RemoveStaleEntryNodes(content);
180+
174181
var divider = ModSettingsUiFactory.CreateDivider();
175-
divider.Name = "RitsuLibModSettingsDivider";
182+
divider.Name = EntryDividerNodeName;
176183

177184
var line = ModSettingsGameSettingsEntryLine.Create(OpenSubmenu);
178185

@@ -193,6 +200,25 @@ void OpenSubmenu()
193200
}
194201
}
195202

203+
internal static MarginContainer? TryGetEntryLine(VBoxContainer content)
204+
{
205+
var line = content.GetNodeOrNull<MarginContainer>(EntryLineNodeName);
206+
if (line is null || !GodotObject.IsInstanceValid(line) || line.GetParent() != content)
207+
return null;
208+
209+
return line;
210+
}
211+
212+
private static void RemoveStaleEntryNodes(VBoxContainer content)
213+
{
214+
var divider = content.GetNodeOrNull<Control>(EntryDividerNodeName);
215+
if (divider is { } d && GodotObject.IsInstanceValid(d))
216+
d.QueueFree();
217+
218+
var line = content.GetNodeOrNull<Control>(EntryLineNodeName);
219+
if (line is { } l && GodotObject.IsInstanceValid(l))
220+
l.QueueFree();
221+
}
196222

197223
private static void EnsureGeneralSettingsContentTracksChildAdds(VBoxContainer content)
198224
{
@@ -215,7 +241,7 @@ private static void OnGeneralSettingsContentChildEntered(Node child)
215241
return;
216242

217243
ScheduleRefreshGeneralSettingsPanelSize(panel);
218-
if (content.GetNodeOrNull("RitsuLibModSettings") != null)
244+
if (TryGetEntryLine(content) != null)
219245
GeneralSettingsModEntryFocusWire.ScheduleTryWire(content);
220246
}
221247

@@ -313,7 +339,7 @@ internal static void ScheduleTryWire(VBoxContainer content)
313339

314340
internal static void TryRebuildEntireGeneralFocusChain(VBoxContainer content)
315341
{
316-
if (content.GetNodeOrNull("RitsuLibModSettings") == null)
342+
if (SettingsScreenModSettingsButtonPatch.TryGetEntryLine(content) == null)
317343
return;
318344

319345
var list = new List<Control>();

0 commit comments

Comments
 (0)