11using System ;
22using System . Collections . Generic ;
33using System . Linq ;
4-
54using Dalamud . Game . ClientState . Conditions ;
65using Dalamud . Game . ClientState . Objects . SubKinds ;
76using Dalamud . Game . ClientState . Objects . Types ;
7+ using Dalamud . Hooking ;
88
99using FFXIVClientStructs . FFXIV . Client . Game . Character ;
1010using FFXIVClientStructs . FFXIV . Client . Game . Control ;
@@ -57,10 +57,14 @@ public class FrameworkHandler: IDisposable
5757 private Func < bool > ? isDisabled ;
5858 private bool isChangingTerritory ;
5959
60+ // Friend list sync via EndRequest hook
61+ private unsafe delegate void EndRequestDelegate ( InfoProxyInterface * thisPtr ) ;
62+ private Hook < EndRequestDelegate > ? endRequestHook ;
63+
6064 /// <summary>
6165 /// Constructor for FrameworkHandler
6266 /// </summary>
63- public FrameworkHandler ( VisibilityConfiguration configuration )
67+ public unsafe FrameworkHandler ( VisibilityConfiguration configuration )
6468 {
6569 // Initialize managers
6670 this . containerManager = new ContainerManager ( ) ;
@@ -72,6 +76,15 @@ public FrameworkHandler(VisibilityConfiguration configuration)
7276 this . petHandler = new PetHandler ( this . containerManager , this . voidListManager , this . visibilityManager , configuration ) ;
7377 this . chocoboHandler = new ChocoboHandler ( this . containerManager , this . voidListManager , this . visibilityManager , configuration ) ;
7478 this . minionHandler = new MinionHandler ( this . containerManager , this . visibilityManager , configuration ) ;
79+
80+ // Hook InfoProxyFriendList.EndRequest to sync friend content IDs when the list is refreshed
81+ InfoProxyFriendList * friendList = InfoProxyFriendList . Instance ( ) ;
82+ if ( friendList != null )
83+ {
84+ nint endRequestAddr = ( nint ) ( ( InfoProxyInterface * ) friendList ) ->VirtualTable ->EndRequest ;
85+ this . endRequestHook = Service . GameInteropProvider . HookFromAddress < EndRequestDelegate > ( endRequestAddr , this . OnFriendListEndRequest ) ;
86+ this . endRequestHook . Enable ( ) ;
87+ }
7588 }
7689
7790 public void SetDisableCheck ( Func < bool > check ) => this . isDisabled = check ;
@@ -200,6 +213,16 @@ public void Show(UnitType unitType, ContainerType containerType)
200213 this . containerManager . ClearContainer ( unitType , containerType ) ;
201214 }
202215
216+ /// <summary>
217+ /// Hook callback for InfoProxyFriendList.EndRequest.
218+ /// Forces a friend container refresh so IsFriend is re-evaluated on the next frame.
219+ /// </summary>
220+ private unsafe void OnFriendListEndRequest ( InfoProxyInterface * thisPtr )
221+ {
222+ this . endRequestHook ! . Original ( thisPtr ) ;
223+ this . ShowAll ( ) ;
224+ }
225+
203226 /// <summary>
204227 /// Handle territory change events
205228 /// </summary>
@@ -329,5 +352,10 @@ public void ShowPlayer(string name)
329352 /// <summary>
330353 /// Dispose the framework handler and show all hidden entities
331354 /// </summary>
332- public void Dispose ( ) => this . ShowAll ( ) ;
355+ public void Dispose ( )
356+ {
357+ this . endRequestHook ? . Disable ( ) ;
358+ this . endRequestHook ? . Dispose ( ) ;
359+ this . ShowAll ( ) ;
360+ }
333361}
0 commit comments