From 1e88fe0cf31553d8fa579e5eabf0071d032ccf5c Mon Sep 17 00:00:00 2001 From: cake Date: Sat, 29 Nov 2025 22:42:55 +0100 Subject: [PATCH] Fixed context menu items, made static function for it to be used --- LightlessSync/PlayerData/Pairs/Pair.cs | 49 ++++------- LightlessSync/Services/ContextMenuService.cs | 85 +++++++++++++------- LightlessSync/UI/UISharedService.cs | 19 ++++- 3 files changed, 90 insertions(+), 63 deletions(-) diff --git a/LightlessSync/PlayerData/Pairs/Pair.cs b/LightlessSync/PlayerData/Pairs/Pair.cs index a861dae..0eda06a 100644 --- a/LightlessSync/PlayerData/Pairs/Pair.cs +++ b/LightlessSync/PlayerData/Pairs/Pair.cs @@ -6,8 +6,9 @@ using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.User; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; -using Microsoft.Extensions.Logging; +using LightlessSync.UI; using LightlessSync.WebAPI; +using Microsoft.Extensions.Logging; namespace LightlessSync.PlayerData.Pairs; @@ -22,6 +23,8 @@ public class Pair private readonly ServerConfigurationManager _serverConfigurationManager; private readonly Lazy _apiController; + private const int _lightlessPrefixColor = 708; + public Pair( ILogger logger, UserFullPairDto userPair, @@ -89,48 +92,28 @@ public class Pair return; } - var openProfileSeString = new SeStringBuilder().AddText("Open Profile").Build(); - var reapplyDataSeString = new SeStringBuilder().AddText("Reapply last data").Build(); - var cyclePauseState = new SeStringBuilder().AddText("Cycle pause state").Build(); - var changePermissions = new SeStringBuilder().AddText("Change Permissions").Build(); - - args.AddMenuItem(new MenuItem + UiSharedService.AddContextMenuItem(args, name: "Open Profile", prefixChar: 'L', colorMenuItem: _lightlessPrefixColor, onClick: () => { - Name = openProfileSeString, - OnClicked = _ => _mediator.Publish(new ProfileOpenStandaloneMessage(this)), - UseDefaultPrefix = false, - PrefixChar = 'L', - PrefixColor = 708 + _mediator.Publish(new ProfileOpenStandaloneMessage(this)); + return Task.CompletedTask; }); - args.AddMenuItem(new MenuItem + UiSharedService.AddContextMenuItem(args, name: "Reapply last data", prefixChar: 'L', colorMenuItem: _lightlessPrefixColor, onClick: () => { - Name = reapplyDataSeString, - OnClicked = _ => ApplyLastReceivedData(forced: true), - UseDefaultPrefix = false, - PrefixChar = 'L', - PrefixColor = 708 + ApplyLastReceivedData(forced: true); + return Task.CompletedTask; }); - args.AddMenuItem(new MenuItem + UiSharedService.AddContextMenuItem(args, name: "Change Permissions", prefixChar: 'L', colorMenuItem: _lightlessPrefixColor, onClick: () => { - Name = changePermissions, - OnClicked = _ => _mediator.Publish(new OpenPermissionWindow(this)), - UseDefaultPrefix = false, - PrefixChar = 'L', - PrefixColor = 708 + _mediator.Publish(new OpenPermissionWindow(this)); + return Task.CompletedTask; }); - args.AddMenuItem(new MenuItem + UiSharedService.AddContextMenuItem(args, name: "Cycle pause state", prefixChar: 'L', colorMenuItem: _lightlessPrefixColor, onClick: () => { - Name = cyclePauseState, - OnClicked = _ => - { - TriggerCyclePause(); - }, - UseDefaultPrefix = false, - PrefixChar = 'L', - PrefixColor = 708 + TriggerCyclePause(); + return Task.CompletedTask; }); } diff --git a/LightlessSync/Services/ContextMenuService.cs b/LightlessSync/Services/ContextMenuService.cs index 42cac86..78e34a8 100644 --- a/LightlessSync/Services/ContextMenuService.cs +++ b/LightlessSync/Services/ContextMenuService.cs @@ -1,5 +1,4 @@ -using LightlessSync; -using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.Gui.ContextMenu; using Dalamud.Plugin; using Dalamud.Plugin.Services; @@ -12,6 +11,7 @@ using Lumina.Excel.Sheets; using LightlessSync.UI.Services; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using LightlessSync.UI; namespace LightlessSync.Services; @@ -33,6 +33,8 @@ internal class ContextMenuService : IHostedService private readonly LightlessProfileManager _lightlessProfileManager; private readonly LightlessMediator _mediator; + private const int _lightlessPrefixColor = 708; + public ContextMenuService( IContextMenu contextMenu, IDalamudPluginInterface pluginInterface, @@ -40,7 +42,7 @@ internal class ContextMenuService : IHostedService ILogger logger, DalamudUtilService dalamudUtil, ApiController apiController, - IObjectTable objectTable, + IObjectTable objectTable, LightlessConfigService configService, PairRequestService pairRequestService, PairUiService pairUiService, @@ -97,44 +99,74 @@ internal class ContextMenuService : IHostedService return; if (args.AddonName != null) + { + var addonName = args.AddonName; + _logger.LogTrace("Context menu addon name: {AddonName}", addonName); return; + } if (args.Target is not MenuTargetDefault target) + { + _logger.LogTrace("Context menu target is not MenuTargetDefault."); return; + } + + _logger.LogTrace("Context menu opened for target: {Target}", target.TargetName ?? "null"); if (string.IsNullOrEmpty(target.TargetName) || target.TargetObjectId == 0 || target.TargetHomeWorld.RowId == 0) + { + _logger.LogTrace("Context menu target has invalid data: Name='{TargetName}', ObjectId={TargetObjectId}, HomeWorldId={TargetHomeWorldId}", target.TargetName, target.TargetObjectId, target.TargetHomeWorld.RowId); return; + } IPlayerCharacter? targetData = GetPlayerFromObjectTable(target); - if (targetData == null || targetData.Address == nint.Zero || _clientState.LocalPlayer == null) - return; - - //Check if user is directly paired or is own. - if (VisibleUserIds.Any(u => u == target.TargetObjectId) || _clientState.LocalPlayer.GameObjectId == target.TargetObjectId || !_configService.Current.EnableRightClickMenus) + if (targetData == null || targetData.Address == nint.Zero || _objectTable.LocalPlayer == null) + { + _logger.LogTrace("Target player {TargetName}@{World} not found in object table.", target.TargetName, target.TargetHomeWorld.RowId); return; + } var snapshot = _pairUiService.GetSnapshot(); var pair = snapshot.PairsByUid.Values.FirstOrDefault(p => p.IsVisible && p.PlayerCharacterId != uint.MaxValue && - (ulong)p.PlayerCharacterId == target.TargetObjectId); + p.PlayerCharacterId == target.TargetObjectId); if (pair is not null) { + _logger.LogTrace("Target player {TargetName}@{World} is already paired, adding existing pair context menu.", target.TargetName, target.TargetHomeWorld.RowId); + pair.AddContextMenu(args); + if (!pair.IsDirectlyPaired) + { + _logger.LogTrace("Target player {TargetName}@{World} is not directly paired, add direct pair menu item", target.TargetName, target.TargetHomeWorld.RowId); + AddDirectPairMenuItem(args); + } + return; } + _logger.LogTrace("Target player {TargetName}@{World} is not paired, adding direct pair request context menu.", target.TargetName, target.TargetHomeWorld.RowId); + //Check if user is directly paired or is own. - if (VisibleUserIds.Contains(target.TargetObjectId) || (_clientState.LocalPlayer?.GameObjectId ?? 0) == target.TargetObjectId) + if (VisibleUserIds.Any(u => u == target.TargetObjectId) || _objectTable.LocalPlayer?.GameObjectId == target.TargetObjectId || !_configService.Current.EnableRightClickMenus) + { + _logger.LogTrace("Target player {TargetName}@{World} is already paired or is self, or right-click menus are disabled.", target.TargetName, target.TargetHomeWorld.RowId); return; + } if (_clientState.IsPvPExcludingDen || _clientState.IsGPosing) + { + _logger.LogTrace("Cannot send pair request to {TargetName}@{World} while in PvP or GPose.", target.TargetName, target.TargetHomeWorld.RowId); return; + } var world = GetWorld(target.TargetHomeWorld.RowId); if (!IsWorldValid(world)) + { + _logger.LogTrace("Target player {TargetName}@{World} is on an invalid world.", target.TargetName, target.TargetHomeWorld.RowId); return; + } string? targetHashedCid = null; if (_broadcastService.IsBroadcasting) @@ -145,31 +177,26 @@ internal class ContextMenuService : IHostedService if (!string.IsNullOrEmpty(targetHashedCid) && CanOpenLightfinderProfile(targetHashedCid)) { var hashedCid = targetHashedCid; - args.AddMenuItem(new MenuItem - { - Name = "Open Lightless Profile", - PrefixChar = 'L', - UseDefaultPrefix = false, - PrefixColor = 708, - OnClicked = async _ => await HandleLightfinderProfileSelection(hashedCid!).ConfigureAwait(false) - }); + UiSharedService.AddContextMenuItem(args, name: "Open Lightless Profile", prefixChar: 'L', colorMenuItem: _lightlessPrefixColor, onClick: () => HandleLightfinderProfileSelection(hashedCid)); } - args.AddMenuItem(new MenuItem - { - Name = "Send Direct Pair Request", - PrefixChar = 'L', - UseDefaultPrefix = false, - PrefixColor = 708, - OnClicked = _ => HandleSelection(args).ConfigureAwait(false).GetAwaiter().GetResult() - }); + AddDirectPairMenuItem(args); + } + + private void AddDirectPairMenuItem(IMenuOpenedArgs args) + { + UiSharedService.AddContextMenuItem( + args, + name: "Send Direct Pair Request", + prefixChar: 'L', + colorMenuItem: _lightlessPrefixColor, + onClick: () => HandleSelection(args)); } private HashSet VisibleUserIds => - _pairUiService.GetSnapshot().PairsByUid.Values + [.. _pairUiService.GetSnapshot().PairsByUid.Values .Where(p => p.IsVisible && p.PlayerCharacterId != uint.MaxValue) - .Select(p => (ulong)p.PlayerCharacterId) - .ToHashSet(); + .Select(p => (ulong)p.PlayerCharacterId)]; private async Task HandleSelection(IMenuArgs args) { diff --git a/LightlessSync/UI/UISharedService.cs b/LightlessSync/UI/UISharedService.cs index b3734a3..2875acb 100644 --- a/LightlessSync/UI/UISharedService.cs +++ b/LightlessSync/UI/UISharedService.cs @@ -1,4 +1,6 @@ using Dalamud.Bindings.ImGui; +using Dalamud.Game.Gui.ContextMenu; +using Dalamud.Game.Text.SeStringHandling; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.GameFonts; @@ -8,7 +10,6 @@ using Dalamud.Interface.Textures; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; -using System; using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Utility; @@ -25,6 +26,7 @@ using LightlessSync.Utils; using LightlessSync.WebAPI; using LightlessSync.WebAPI.SignalR; using Microsoft.Extensions.Logging; +using System; using System.IdentityModel.Tokens.Jwt; using System.Numerics; using System.Runtime.InteropServices; @@ -487,6 +489,21 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase ); } + public static void AddContextMenuItem(IMenuOpenedArgs args, SeString name, char prefixChar, ushort colorMenuItem, Func onClick) + { + args.AddMenuItem(new MenuItem + { + Name = name, + PrefixChar = prefixChar, + UseDefaultPrefix = false, + PrefixColor = colorMenuItem, + OnClicked = _ => + { + onClick(); + }, + }); + } + public static void ColoredSeparator(Vector4? color = null, float thickness = 1f, float indent = 0f) { var drawList = ImGui.GetWindowDrawList();