@@ -83,19 +83,20 @@ public void HandleInput(PlayerKey key, bool fromBind)
8383 }
8484 }
8585
86- private bool _PresentingHtml ;
87- private bool PresentingHtml
86+ public bool PresentingHtml { get ; set ; }
87+ private bool _MenuActive ;
88+ private bool MenuActive
8889 {
89- get => _PresentingHtml ;
90+ get => _MenuActive ;
9091 set
9192 {
92- if ( value == _PresentingHtml )
93+ if ( value == _MenuActive )
9394 return ;
94- _PresentingHtml = value ;
95+ _MenuActive = value ;
9596 if ( value )
96- Driver . ActiveHtmlMenuStates . Add ( this ) ;
97+ Driver . ActiveMenuStates . Add ( this ) ;
9798 else
98- Driver . ActiveHtmlMenuStates . Remove ( this ) ;
99+ Driver . ActiveMenuStates . Remove ( this ) ;
99100 }
100101 }
101102
@@ -124,13 +125,11 @@ public void Refresh(bool sortPriorities = true)
124125 }
125126
126127 CurrentMenu = FocusStack . Count > 0 ? FocusStack [ 0 ] : null ;
128+ MenuActive = CurrentMenu is not null ;
127129
128130 if ( CreateInitialInvisibleWorldTextEntity ( ) )
129131 {
130- Server . NextFrame ( ( ) =>
131- {
132- Refresh ( sortPriorities : false ) ;
133- } ) ;
132+ ForceRefresh = true ;
134133 return ;
135134 }
136135
@@ -140,6 +139,8 @@ public void Refresh(bool sortPriorities = true)
140139 }
141140 else
142141 {
142+ if ( ! PresentingHtml )
143+ DestroyEntities ( ) ;
143144 DrawActiveMenuHtml ( ) ;
144145 PresentingHtml = true ;
145146 }
@@ -167,7 +168,6 @@ private void DestroyEntities()
167168 Background ? . Remove ( ) ;
168169
169170 ForegroundText = BackgroundText = Background = null ;
170- Console . WriteLine ( "DEBUG: DestroyEntities()" ) ;
171171 }
172172
173173 private static readonly Color ForegroundTextColor = Color . FromArgb ( 229 , 150 , 32 ) ; // 245, 177, 103 with a white bg, maybe 240, 160, 30 at 95% opacity?
@@ -180,40 +180,37 @@ private void CreateEntities()
180180 Background = CreateWorldText ( textColor : Color . FromArgb ( 200 , 127 , 127 , 127 ) , true , - 0.002f ) ;
181181 }
182182
183- private bool _Created = false ;
183+ // sometimes creating an ent for a pawn requires it to be done twice, so
184+ // do it twice whenever our observed entity changes
185+ private nint ? _CreatedFor = null ;
184186 /// <summary>
185187 /// The first world text isn't shown for some reason, this creates a barebones version then immediately destroys it
186188 /// </summary>
187189 private bool CreateInitialInvisibleWorldTextEntity ( )
188190 {
189- if ( _Created )
191+ var observerInfo = Player . GetObserverInfo ( ) ;
192+
193+ if ( _CreatedFor . HasValue && _CreatedFor . Value == observerInfo . Observing ? . Handle )
190194 return false ;
191195
192- var viewmodel = Player . GetPredictedViewmodel ( ) ;
196+ var viewmodel = observerInfo . GetPredictedViewmodel ( ) ;
193197 if ( viewmodel is null )
194- {
195- CurrentMenu ? . Close ( ) ;
196198 return false ;
197- }
198199
199200 var entity = CreateWorldText ( Color . Orange , drawBackground : false , depthOffset : 0.0f ) ;
200201 if ( entity is null )
201- {
202- CurrentMenu ? . Close ( ) ;
203202 return false ;
204- }
205203
206- var maybeAngles = Player . GetEyeAngles ( ) ;
204+ var maybeAngles = observerInfo . GetEyeAngles ( ) ;
207205 if ( ! maybeAngles . HasValue )
208- {
209- CurrentMenu ? . Close ( ) ;
210206 return false ;
211- }
212207
213- UpdateEntity ( entity , viewmodel , "Hey" , maybeAngles . Value . Position , maybeAngles . Value . Angle ) ;
208+ UpdateEntity ( entity , viewmodel , "Hey" , maybeAngles . Value . Position , maybeAngles . Value . Angle , updateText : true , updateParent : true ) ;
214209 entity . Remove ( ) ;
215210
216- _Created = true ;
211+ _CreatedFor = observerInfo . Observing ? . Handle ?? nint . Zero ;
212+
213+ Console . WriteLine ( "CreateInitialInvisibleWorldTextEntity(): DONE" ) ;
217214 return true ;
218215 }
219216
@@ -255,32 +252,40 @@ private CPointWorldText CreateWorldText(
255252 private static QAngle _Ang = new ( ) ;
256253 private void UpdateEntity (
257254 CPointWorldText ent ,
258- CCSGOViewModel viewmodel ,
259- string ? newText ,
255+ CCSGOViewModel ? viewmodel ,
256+ string newText ,
260257 Vector3 position ,
261- Vector3 angles )
258+ Vector3 angles ,
259+ bool updateText = true ,
260+ bool updateParent = true )
262261 {
263262 _Pos . X = position . X ;
264263 _Pos . Y = position . Y ;
265264 _Pos . Z = position . Z ;
266265 _Ang . X = angles . X ;
267266 _Ang . Y = angles . Y ;
268267 _Ang . Z = angles . Z ;
269- if ( newText is not null )
268+
269+ if ( updateText )
270270 ent . MessageText = newText ;
271271 ent . Teleport ( _Pos , _Ang , null ) ;
272- ent . AcceptInput ( "SetParent" , viewmodel , null , "!activator" ) ;
273- if ( newText is not null )
272+
273+ if ( updateParent )
274+ ent . AcceptInput ( "SetParent" , viewmodel , null , "!activator" ) ;
275+
276+ if ( updateText )
274277 Utilities . SetStateChanged ( ent , "CPointWorldText" , "m_messageText" ) ;
275278 }
276279
277- private readonly Vector MenuPosition = new ( - 7.0f , 0.0f ) ;
280+ private readonly Vector MenuPosition = new ( - 6.9f , 0.0f ) ;
278281
279- private CCSGOViewModel ? LastViewmodel { get ; set ; }
280282 private Menu ? LastPresented { get ; set ; }
281283 private readonly StringBuilder ForegroundTextSb = new ( ) ;
282284 private readonly StringBuilder BackgroundTextSb = new ( ) ;
283285 private readonly StringBuilder BackgroundSb = new ( ) ;
286+ private nint MenuCurrentObserver { get ; set ; } = nint . Zero ;
287+ private ObserverMode MenuCurrentObserverMode { get ; set ; }
288+ private CCSGOViewModel ? MenuCurrentViewmodel { get ; set ; }
284289 public bool DrawActiveMenu ( )
285290 {
286291 if ( ReferenceEquals ( CurrentMenu , LastPresented ) )
@@ -300,25 +305,18 @@ public bool DrawActiveMenu()
300305
301306 CurrentMenu . IsDirty = false ;
302307
303- bool allValid =
304- ( ForegroundText ? . IsValid ?? false ) &&
305- ( BackgroundText ? . IsValid ?? false ) &&
306- ( Background ? . IsValid ?? false ) ;
307- if ( ! allValid )
308- {
309- DestroyEntities ( ) ;
310- CreateEntities ( ) ;
311- }
308+ var observerInfo = Player . GetObserverInfo ( ) ;
309+ if ( observerInfo . Mode != ObserverMode . FirstPerson )
310+ return false ;
312311
313- var maybeEyeAngles = Player . GetEyeAngles ( ) ;
312+ var maybeEyeAngles = observerInfo . GetEyeAngles ( ) ;
314313 if ( ! maybeEyeAngles . HasValue )
315314 return false ;
316315 var eyeAngles = maybeEyeAngles . Value ;
317316
318- var predictedViewmodel = Player . GetPredictedViewmodel ( ) ;
317+ var predictedViewmodel = observerInfo . GetPredictedViewmodel ( ) ;
319318 if ( predictedViewmodel is null )
320319 return false ;
321- LastViewmodel = predictedViewmodel ;
322320
323321 ForegroundTextSb . Clear ( ) ;
324322 BackgroundTextSb . Clear ( ) ;
@@ -356,13 +354,25 @@ void writeLine(string text, bool background)
356354 X = 0.0f
357355 } ;
358356
357+ MenuCurrentObserver = observerInfo . Observing ? . Handle ?? nint . Zero ;
358+ MenuCurrentObserverMode = observerInfo . Mode ;
359+ MenuCurrentViewmodel = predictedViewmodel ;
360+
361+ bool allValid =
362+ ( ForegroundText ? . IsValid ?? false ) &&
363+ ( BackgroundText ? . IsValid ?? false ) &&
364+ ( Background ? . IsValid ?? false ) ;
365+ if ( ! allValid )
366+ {
367+ DestroyEntities ( ) ;
368+ CreateEntities ( ) ;
369+ }
359370 UpdateEntity ( ForegroundText ! , predictedViewmodel , ForegroundTextSb . ToString ( ) , position , angle ) ;
360371 UpdateEntity ( BackgroundText ! , predictedViewmodel , BackgroundTextSb . ToString ( ) , position , angle ) ;
361372 UpdateEntity ( Background ! , predictedViewmodel , BackgroundSb . ToString ( ) , position , angle ) ;
362373 return true ;
363374 }
364375
365-
366376 private readonly StringBuilder HtmlTextSb = new ( ) ;
367377 public string ? HtmlContent { get ; set ; } = null ;
368378 public void DrawActiveMenuHtml ( )
@@ -373,7 +383,6 @@ public void DrawActiveMenuHtml()
373383 return ;
374384 }
375385
376-
377386 bool firstLine = true ;
378387 int linesWrote = 0 ;
379388 void writeLine ( string text , bool background )
@@ -442,4 +451,28 @@ private void BuildMenuStrings(Menu currentMenu, Action<string, bool> writeLine)
442451 writeLine ( "0. Exit" , true ) ;
443452 }
444453 }
454+
455+ public bool ForceRefresh = true ;
456+ public void Tick ( )
457+ {
458+ if ( CurrentMenu is null )
459+ return ;
460+
461+ if ( PresentingHtml && HtmlContent is not null )
462+ Player . PrintToCenterHtml ( HtmlContent ) ;
463+
464+ var observerInfo = Player . GetObserverInfo ( ) ;
465+
466+ bool refresh =
467+ ForceRefresh ||
468+ observerInfo . Mode != MenuCurrentObserverMode ||
469+ observerInfo . Observing ? . Handle != MenuCurrentObserver ;
470+
471+ if ( refresh )
472+ {
473+ ForceRefresh = false ;
474+ CurrentMenu . IsDirty = true ;
475+ Refresh ( sortPriorities : false ) ;
476+ }
477+ }
445478}
0 commit comments