Files
LightlessClient/LightlessSync/UI/ContextMenu.cs
2025-09-29 19:44:36 +02:00

159 lines
5.1 KiB
C#

using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Gui.ContextMenu;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using LightlessSync.LightlessConfiguration;
using LightlessSync.Services;
using LightlessSync.Utils;
using LightlessSync.WebAPI;
using Lumina.Excel.Sheets;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace LightlessSync.UI;
internal class ContextMenu : IHostedService
{
private readonly IContextMenu _contextMenu;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly IDataManager _gameData;
private readonly ILogger<ContextMenu> _logger;
private readonly DalamudUtilService _dalamudUtil;
private readonly LightlessConfigService _configService;
private readonly ApiController _apiController;
private readonly IObjectTable _objectTable;
private static readonly string[] ValidAddons = new[]
{
null,
"PartyMemberList", "FriendList", "FreeCompany", "LinkShell", "CrossWorldLinkshell",
"_PartyList", "ChatLog", "LookingForGroup", "BlackList", "ContentMemberList",
"SocialList", "ContactList", "BeginnerChatList", "MuteList"
};
public ContextMenu(
IContextMenu contextMenu,
IDalamudPluginInterface pluginInterface,
IDataManager gameData,
ILogger<ContextMenu> logger,
DalamudUtilService dalamudUtil,
ApiController apiController,
IObjectTable objectTable,
LightlessConfigService configService)
{
_contextMenu = contextMenu;
_pluginInterface = pluginInterface;
_gameData = gameData;
_logger = logger;
_dalamudUtil = dalamudUtil;
_apiController = apiController;
_objectTable = objectTable;
_configService = configService;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_contextMenu.OnMenuOpened += OnMenuOpened;
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_contextMenu.OnMenuOpened -= OnMenuOpened;
return Task.CompletedTask;
}
public void Enable()
{
_contextMenu.OnMenuOpened += OnMenuOpened;
_logger.LogDebug("Context menu enabled.");
}
public void Disable()
{
_contextMenu.OnMenuOpened -= OnMenuOpened;
_logger.LogDebug("Context menu disabled.");
}
private void OnMenuOpened(IMenuOpenedArgs args)
{
if (!_pluginInterface.UiBuilder.ShouldModifyUi)
return;
if (!ValidAddons.Contains(args.AddonName))
return;
if (args.Target is not MenuTargetDefault target)
return;
if (string.IsNullOrEmpty(target.TargetName) || target.TargetObjectId == 0 || target.TargetHomeWorld.RowId == 0)
return;
var world = GetWorld(target.TargetHomeWorld.RowId);
if (!IsWorldValid(world))
return;
if (_configService.Current.BroadcastEnabled)
{
args.AddMenuItem(new MenuItem
{
Name = "Send Pair Request",
PrefixChar = 'L',
UseDefaultPrefix = false,
PrefixColor = 708,
OnClicked = async _ => await HandleSelection(args)
});
}
}
private async Task HandleSelection(IMenuArgs args)
{
if (args.Target is not MenuTargetDefault target)
return;
var world = GetWorld(target.TargetHomeWorld.RowId);
if (!IsWorldValid(world))
return;
try
{
var targetData = _objectTable
.OfType<IPlayerCharacter>()
.FirstOrDefault(p =>
string.Equals(p.Name.TextValue, target.TargetName, StringComparison.OrdinalIgnoreCase) &&
p.HomeWorld.RowId == target.TargetHomeWorld.RowId);
if (targetData == null || targetData.Address == IntPtr.Zero)
{
_logger.LogWarning("Target player {TargetName}@{World} not found in object table.", target.TargetName, world.Name);
return;
}
var senderCid = (await _dalamudUtil.GetCIDAsync()).ToString().GetHash256();
var receiverCid = DalamudUtilService.GetHashedCIDFromPlayerPointer(targetData.Address);
_logger.LogInformation("Sending pair request: sender {SenderCid}, receiver {ReceiverCid}", senderCid, receiverCid);
await _apiController.TryPairWithContentId(receiverCid, senderCid);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error sending pair request.");
}
}
private World GetWorld(uint worldId)
{
var sheet = _gameData.GetExcelSheet<World>()!;
return sheet.TryGetRow(worldId, out var world) ? world : sheet.First();
}
public bool IsWorldValid(uint worldId) => IsWorldValid(GetWorld(worldId));
public static bool IsWorldValid(World world)
{
var name = world.Name.ToString();
return !string.IsNullOrWhiteSpace(name) && char.IsUpper(name[0]);
}
}