@@ -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