using System; using System.Text; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Group; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI.Info; using FFXIVClientStructs.FFXIV.Client.UI.Shell; namespace QuestionableCompanion.Services; public class PartyInviteService { private readonly IPluginLog log; private readonly IObjectTable objectTable; private readonly IClientState clientState; public PartyInviteService(IPluginLog log, IObjectTable objectTable, IClientState clientState) { this.log = log; this.objectTable = objectTable; this.clientState = clientState; } public unsafe bool InviteToParty(string characterName, ushort worldId) { if (string.IsNullOrWhiteSpace(characterName)) { log.Error("[PartyInvite] Character name is null or empty!"); return false; } if (worldId == 0) { log.Error("[PartyInvite] World ID is 0 (invalid)!"); return false; } characterName = characterName.Trim(); try { InfoModule* infoModule = InfoModule.Instance(); if (infoModule == null) { log.Error("[PartyInvite] InfoModule is null!"); return false; } InfoProxyPartyInvite* partyInviteProxy = (InfoProxyPartyInvite*)infoModule->GetInfoProxyById(InfoProxyId.PartyInvite); if (partyInviteProxy == null) { log.Error("[PartyInvite] InfoProxyPartyInvite is null!"); return false; } ulong contentId = 0uL; log.Information($"[PartyInvite] Using name-based invite (ContentId=0, Name={characterName}, World={worldId})"); log.Information($"[PartyInvite] Sending invite to {characterName}@{worldId} (ContentId: {contentId})"); fixed (byte* namePtr = Encoding.UTF8.GetBytes(characterName + "\0")) { bool num = partyInviteProxy->InviteToParty(contentId, namePtr, worldId); if (num) { log.Information($"[PartyInvite] ✓ Successfully sent invite to {characterName}@{worldId}"); } else { log.Warning($"[PartyInvite] ✗ Failed to send invite to {characterName}@{worldId}"); } return num; } } catch (Exception ex) { log.Error("[PartyInvite] Exception: " + ex.Message); log.Error("[PartyInvite] StackTrace: " + ex.StackTrace); return false; } } public unsafe bool InviteToPartyByContentId(ulong contentId, ushort worldId) { try { InfoModule* infoModule = InfoModule.Instance(); if (infoModule == null) { log.Error("[PartyInvite] InfoModule is null!"); return false; } InfoProxyPartyInvite* partyInviteProxy = (InfoProxyPartyInvite*)infoModule->GetInfoProxyById(InfoProxyId.PartyInvite); if (partyInviteProxy == null) { log.Error("[PartyInvite] InfoProxyPartyInvite is null!"); return false; } log.Information($"[PartyInvite] Sending invite to ContentID {contentId}@{worldId}"); bool num = partyInviteProxy->InviteToPartyContentId(contentId, worldId); if (num) { log.Information($"[PartyInvite] Successfully sent invite to ContentID {contentId}@{worldId}"); } else { log.Warning($"[PartyInvite] Failed to send invite to ContentID {contentId}@{worldId}"); } return num; } catch (Exception ex) { log.Error("[PartyInvite] Exception: " + ex.Message); log.Error("[PartyInvite] StackTrace: " + ex.StackTrace); return false; } } public unsafe bool InviteToPartyInInstanceByContentId(ulong contentId) { try { InfoModule* infoModule = InfoModule.Instance(); if (infoModule == null) { log.Error("[PartyInvite] InfoModule is null!"); return false; } InfoProxyPartyInvite* partyInviteProxy = (InfoProxyPartyInvite*)infoModule->GetInfoProxyById(InfoProxyId.PartyInvite); if (partyInviteProxy == null) { log.Error("[PartyInvite] InfoProxyPartyInvite is null!"); return false; } log.Information($"[PartyInvite] Sending instance invite to ContentID {contentId}"); bool num = partyInviteProxy->InviteToPartyInInstanceByContentId(contentId); if (num) { log.Information($"[PartyInvite] Successfully sent instance invite to ContentID {contentId}"); } else { log.Warning($"[PartyInvite] Failed to send instance invite to ContentID {contentId}"); } return num; } catch (Exception ex) { log.Error("[PartyInvite] Exception: " + ex.Message); log.Error("[PartyInvite] StackTrace: " + ex.StackTrace); return false; } } public unsafe bool LeaveParty() { try { GroupManager* groupManager = GroupManager.Instance(); if (groupManager == null) { log.Error("[PartyInvite] GroupManager is null!"); return false; } GroupManager.Group* group = groupManager->GetGroup(); if (group == null || group->MemberCount == 0) { log.Debug("[PartyInvite] Not in a party"); return true; } log.Information($"[PartyInvite] Leaving party (Members: {group->MemberCount})"); RaptureShellModule* shellModule = RaptureShellModule.Instance(); if (shellModule == null) { log.Error("[PartyInvite] RaptureShellModule is null!"); return false; } UIModule* uiModule = UIModule.Instance(); if (uiModule == null) { log.Error("[PartyInvite] UIModule is null!"); return false; } Utf8String* leaveCommand = Utf8String.FromString("/leave"); shellModule->ExecuteCommandInner(leaveCommand, uiModule); leaveCommand->Dtor(); log.Information("[PartyInvite] Leave command executed successfully"); return true; } catch (Exception ex) { log.Error("[PartyInvite] Exception: " + ex.Message); log.Error("[PartyInvite] StackTrace: " + ex.StackTrace); return false; } } }