@@ -23,6 +23,8 @@ internal static class ContentSourceHoverTipPatchHelper
2323 {
2424 private const string EventBadgeNodeName = "RitsuLibContentSourceBadge" ;
2525 private const string EventDrawerHotZoneName = "RitsuLibContentSourceHotZone" ;
26+ private const string HoverTipScenePath = "res://scenes/ui/hover_tip.tscn" ;
27+ private const string HoverTipSetScenePath = "res://scenes/ui/hover_tip_set.tscn" ;
2628 private const float EventTipWidth = 360f ;
2729 private const float EventTipRightMargin = 42f ;
2830 private const float EventTipBottomMargin = 38f ;
@@ -74,6 +76,9 @@ private static HoverTip CreateSourceTip(ContentSourceHoverTipFactory.ContentSour
7476
7577 internal static void UpdateEventSourceBadge ( NEventLayout layout , EventModel eventModel )
7678 {
79+ if ( ! IsNodeUsable ( layout ) )
80+ return ;
81+
7782 var existing = layout . GetNodeOrNull < NHoverTipSet > ( EventBadgeNodeName ) ;
7883 var existingHotZone = layout . GetNodeOrNull < Control > ( EventDrawerHotZoneName ) ;
7984 if ( ! RitsuLibSettingsStore . IsModSourceHoverTipsEnabled ( ) ||
@@ -96,8 +101,8 @@ internal static void UpdateEventSourceBadge(NEventLayout layout, EventModel even
96101 RemoveBadge ( layout , existingHotZone ) ;
97102 var tipSet = CreateEventSourceTipSet ( layout , source ) ;
98103 var hotZone = CreateEventSourceHotZone ( ) ;
99- layout . AddChild ( tipSet ) ;
100- layout . AddChild ( hotZone ) ;
104+ layout . AddChildSafely ( tipSet ) ;
105+ layout . AddChildSafely ( hotZone ) ;
101106 tipSet . Visible = true ;
102107 Callable . From ( ( ) => PopulateAndPositionEventSourceTipSet ( layout , tipSet , hotZone , source ) ) . CallDeferred ( ) ;
103108 }
@@ -106,7 +111,7 @@ private static NHoverTipSet CreateEventSourceTipSet(Control owner,
106111 ContentSourceHoverTipFactory . ContentSourceInfo source )
107112 {
108113 var tipSet = PreloadManager . Cache
109- . GetScene ( "res://scenes/ui/hover_tip_set.tscn" )
114+ . GetScene ( HoverTipSetScenePath )
110115 . Instantiate < NHoverTipSet > ( ) ;
111116 tipSet . Name = EventBadgeNodeName ;
112117 tipSet . MouseFilter = Control . MouseFilterEnum . Ignore ;
@@ -121,7 +126,7 @@ private static void PopulateAndPositionEventSourceTipSet(
121126 Control hotZone ,
122127 ContentSourceHoverTipFactory . ContentSourceInfo source )
123128 {
124- if ( ! GodotObject . IsInstanceValid ( tipSet ) || ! GodotObject . IsInstanceValid ( hotZone ) )
129+ if ( ! IsEventSourceBadgeUsable ( layout , tipSet , hotZone ) )
125130 return ;
126131
127132 if ( tipSet . _textHoverTipContainer == null )
@@ -131,6 +136,9 @@ private static void PopulateAndPositionEventSourceTipSet(
131136 return ;
132137 }
133138
139+ if ( ! IsNodeUsable ( tipSet . _textHoverTipContainer ) )
140+ return ;
141+
134142 AddHoverTipControl ( tipSet , new ( ContentSourceHoverTipFactory . GetTitle ( ) , source . Format ( ) )
135143 {
136144 Id = "ritsulib:event_content_source:" + source . Id ,
@@ -142,8 +150,11 @@ private static void PopulateAndPositionEventSourceTipSet(
142150
143151 private static void AddHoverTipControl ( NHoverTipSet tipSet , HoverTip hoverTip )
144152 {
153+ if ( ! IsNodeUsable ( tipSet ) || ! IsNodeUsable ( tipSet . _textHoverTipContainer ) )
154+ return ;
155+
145156 var tipControl = PreloadManager . Cache
146- . GetScene ( "res://scenes/ui/hover_tip.tscn" )
157+ . GetScene ( HoverTipScenePath )
147158 . Instantiate < Control > ( ) ;
148159 tipSet . _textHoverTipContainer . AddChildSafely ( tipControl ) ;
149160
@@ -172,20 +183,30 @@ private static Control CreateEventSourceHotZone()
172183
173184 private static void ConfigureEventSourceTipDrawer ( Control layout , NHoverTipSet tipSet , Control hotZone )
174185 {
186+ if ( ! IsEventSourceBadgeUsable ( layout , tipSet , hotZone ) ||
187+ ! IsNodeUsable ( tipSet . _textHoverTipContainer ) )
188+ return ;
189+
175190 var textContainer = tipSet . _textHoverTipContainer ;
176191 textContainer . MouseFilter = Control . MouseFilterEnum . Ignore ;
177192 var isExpanded = false ;
178193 hotZone . Connect (
179194 Control . SignalName . MouseEntered ,
180195 Callable . From ( ( ) =>
181196 {
197+ if ( ! IsEventSourceBadgeUsable ( layout , tipSet , hotZone ) )
198+ return ;
199+
182200 isExpanded = true ;
183201 PositionEventSourceTipSet ( layout , tipSet , true , true ) ;
184202 } ) ) ;
185203 hotZone . Connect (
186204 Control . SignalName . MouseExited ,
187205 Callable . From ( ( ) =>
188206 {
207+ if ( ! IsEventSourceBadgeUsable ( layout , tipSet , hotZone ) )
208+ return ;
209+
189210 if ( isExpanded )
190211 PositionEventSourceTipSet ( layout , tipSet , false , true ) ;
191212 isExpanded = false ;
@@ -195,13 +216,20 @@ private static void ConfigureEventSourceTipDrawer(Control layout, NHoverTipSet t
195216 if ( inputEvent is not InputEventMouseButton { Pressed : true , ButtonIndex : MouseButton . Left } )
196217 return ;
197218
219+ if ( ! IsEventSourceBadgeUsable ( layout , tipSet , hotZone ) )
220+ return ;
221+
198222 isExpanded = ! isExpanded ;
199223 PositionEventSourceTipSet ( layout , tipSet , isExpanded , true ) ;
200224 } ;
201225 }
202226
203227 private static void PositionEventSourceHotZone ( Control layout , NHoverTipSet tipSet , Control hotZone )
204228 {
229+ if ( ! IsEventSourceBadgeUsable ( layout , tipSet , hotZone ) ||
230+ ! IsNodeUsable ( tipSet . _textHoverTipContainer ) )
231+ return ;
232+
205233 var viewportSize = NGame . Instance ? . GetViewportRect ( ) . Size ?? layout . GetViewportRect ( ) . Size ;
206234 var textContainer = tipSet . _textHoverTipContainer ;
207235 var height = Math . Max ( EventTipHotZoneMinHeight ,
@@ -213,7 +241,7 @@ private static void PositionEventSourceHotZone(Control layout, NHoverTipSet tipS
213241
214242 private static void PositionEventSourceTipSet ( Control layout , NHoverTipSet tipSet , bool expanded , bool animate )
215243 {
216- if ( ! GodotObject . IsInstanceValid ( tipSet ) )
244+ if ( ! IsNodeUsable ( layout ) || ! IsNodeUsable ( tipSet ) || ! IsNodeUsable ( tipSet . _textHoverTipContainer ) )
217245 return ;
218246
219247 var viewportSize = NGame . Instance ? . GetViewportRect ( ) . Size ?? layout . GetViewportRect ( ) . Size ;
@@ -237,11 +265,28 @@ private static void PositionEventSourceTipSet(Control layout, NHoverTipSet tipSe
237265
238266 private static void RemoveBadge ( Node owner , Node ? badge )
239267 {
240- if ( badge == null )
268+ if ( ! IsNodeUsable ( owner ) || badge == null || ! IsNodeUsable ( badge ) )
241269 return ;
242270
243- owner . RemoveChild ( badge ) ;
244- badge . QueueFree ( ) ;
271+ if ( badge . GetParent ( ) == owner )
272+ owner . RemoveChildSafely ( badge ) ;
273+ badge . QueueFreeSafely ( ) ;
274+ }
275+
276+ private static bool IsEventSourceBadgeUsable ( Control layout , NHoverTipSet tipSet , Control hotZone )
277+ {
278+ return IsNodeUsable ( layout ) &&
279+ IsNodeUsable ( tipSet ) &&
280+ IsNodeUsable ( hotZone ) &&
281+ tipSet . GetParent ( ) == layout &&
282+ hotZone . GetParent ( ) == layout ;
283+ }
284+
285+ private static bool IsNodeUsable ( Node ? node )
286+ {
287+ return node != null &&
288+ GodotObject . IsInstanceValid ( node ) &&
289+ ! node . IsQueuedForDeletion ( ) ;
245290 }
246291 }
247292
0 commit comments